std.range.primitives
This module is a submodule of std.range
.
It defines the bidirectional and forward range primitives for arrays: empty
, front
, back
, popFront
, popBack
and save
.
It provides basic range functionality by defining several templates for testing whether a given object is a range, and what kind of range it is:
isInputRange | Tests if something is an input range, defined to be something from which one can sequentially read data using the primitives front , popFront , and empty . |
isOutputRange | Tests if something is an output range, defined to be something to which one can sequentially write data using the put primitive. |
isForwardRange | Tests if something is a forward range, defined to be an input range with the additional capability that one can save one's current position with the save primitive, thus allowing one to iterate over the same range multiple times. |
isBidirectionalRange | Tests if something is a bidirectional range, that is, a forward range that allows reverse traversal using the primitives back and popBack . |
isRandomAccessRange | Tests if something is a random access range, which is a bidirectional range that also supports the array subscripting operation via the primitive opIndex . |
It also provides number of templates that test for various range capabilities:
hasMobileElements | Tests if a given range's elements can be moved around using the primitives moveFront , moveBack , or moveAt . |
ElementType | Returns the element type of a given range. |
ElementEncodingType | Returns the encoding element type of a given range. |
hasSwappableElements | Tests if a range is a forward range with swappable elements. |
hasAssignableElements | Tests if a range is a forward range with mutable elements. |
hasLvalueElements | Tests if a range is a forward range with elements that can be passed by reference and have their address taken. |
hasLength | Tests if a given range has the length attribute. |
isInfinite | Tests if a given range is an infinite range. |
hasSlicing | Tests if a given range supports the array slicing operation R[x .. y] . |
Finally, it includes some convenience functions for manipulating ranges:
popFrontN | Advances a given range by up to n elements. |
popBackN | Advances a given bidirectional range from the right by up to n elements. |
popFrontExactly | Advances a given range by up exactly n elements. |
popBackExactly | Advances a given bidirectional range from the right by exactly n elements. |
moveFront | Removes the front element of a range. |
moveBack | Removes the back element of a bidirectional range. |
moveAt | Removes the i'th element of a random-access range. |
walkLength | Computes the length of any range in O(n) time. |
put | Outputs element e to a range. |
- Source
- std/range/primitives.d
- License:
- Boost License 1.0.
- Authors:
- Andrei Alexandrescu, David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to Leonardo Maffi.
- enum bool isInputRange(R);
-
Returns
true
ifR
is an input range. An input range must define the primitivesempty
,popFront
, andfront
. The following code should compile for any input range.R r; // can define a range object if (r.empty) {} // can test for empty r.popFront(); // can invoke popFront() auto h = r.front; // can get the front of the range of non-void type
The following are rules of input ranges are assumed to hold true in all Phobos code. These rules are not checkable at compile-time, so not conforming to these rules when writing ranges or range based code will result in undefined behavior.
-
r.empty
returnsfalse
if and only if there is more data available in the range. -
r.empty
evaluated multiple times, without callingr.popFront
, or otherwise mutating the range object or the underlying data, yields the same result for every evaluation. -
r.front
returns the current element in the range. It may return by value or by reference. -
r.front
can be legally evaluated if and only if evaluatingr.empty
has, or would have, equaledfalse
. -
r.front
evaluated multiple times, without callingr.popFront
, or otherwise mutating the range object or the underlying data, yields the same result for every evaluation. -
r.popFront
advances to the next element in the range. -
r.popFront
can be called if and only if evaluatingr.empty
has, or would have, equaledfalse
.
Also, note that Phobos code assumes that the primitivesr.front
andr.empty
are Ο(1
) time complexity wise or "cheap" in terms of running time. Ο() statements in the documentation of range functions are made with this assumption.- See Also:
- The header of
std.range
for tutorials on ranges.
- Parameters:
R type to be tested
- Returns:
-
true
if R is an input range,false
if not
- Examples:
-
struct A {} struct B { void popFront(); @property bool empty(); @property int front(); } static assert(!isInputRange!A); static assert( isInputRange!B); static assert( isInputRange!(int[])); static assert( isInputRange!(char[])); static assert(!isInputRange!(char[4])); static assert( isInputRange!(inout(int)[])); static struct NotDefaultConstructible { @disable this(); void popFront(); @property bool empty(); @property int front(); } static assert( isInputRange!NotDefaultConstructible); static struct NotDefaultConstructibleOrCopyable { @disable this(); @disable this(this); void popFront(); @property bool empty(); @property int front(); } static assert(isInputRange!NotDefaultConstructibleOrCopyable); static struct Frontless { void popFront(); @property bool empty(); } static assert(!isInputRange!Frontless); static struct VoidFront { void popFront(); @property bool empty(); void front(); } static assert(!isInputRange!VoidFront);
-
- void put(R, E)(ref R r, E e);
-
Outputs
e
tor
. The exact effect is dependent upon the two types. Several cases are accepted, as described below. The code snippets are attempted in order, and the first to compile "wins" and gets evaluated.In this table "doPut" is a method that places
e
intor
, using the correct primitive:r.put(e)
ifR
definesput
,r.front = e
ifr
is an input range (followed byr.popFront()
), orr(e)
otherwise.
Code Snippet Scenario r.doPut(e);
R
specifically accepts anE
.r.doPut([ e ]);
R
specifically accepts anE[]
.r.putChar(e);
R
accepts some form of string or character. put will transcode the charactere
accordingly.for (; !e.empty; e.popFront()) put(r, e.front);
Copying range E
intoR
.- Tip
-
put
should not be used "UFCS-style", e.g.r.put(e)
. Doing this may callR.put
directly, by-passing any transformation feature provided byRange.put
.put(r, e)
is prefered.
- Examples:
- When an output range's
put
method only accepts elements of typeT
, use the globalput
to handle outputting aT[]
to the range or vice-versa.import std.traits : isSomeChar; static struct A { string data; void put(C)(C c) if (isSomeChar!C) { data ~= c; } } static assert(isOutputRange!(A, char)); auto a = A(); put(a, "Hello"); writeln(a.data); // "Hello"
- Examples:
-
put
treats dynamic arrays as array slices, and will callpopFront
on the slice after an element has been copied. Be sure to save the position of the array before callingput
.int[] a = [1, 2, 3], b = [10, 20]; auto c = a; put(a, b); writeln(c); // [10, 20, 3] // at this point, a was advanced twice, so it only contains // its last element while c represents the whole array writeln(a); // [3]
- Examples:
- It's also possible to
put
any width strings or characters into narrow strings -- put does the conversion for you. Note that putting the same width character as the target buffer type isnothrow
, but transcoding can throw astd.utf.UTFException
.// the elements must be mutable, so using string or const(char)[] // won't compile char[] s1 = new char[13]; auto r1 = s1; put(r1, "Hello, World!"w); writeln(s1); // "Hello, World!"
- enum bool isOutputRange(R, E);
-
Returns
true
ifR
is an output range for elements of typeE
. An output range is defined functionally as a range that supports the operationput(r, e)
as defined above.- See Also:
- The header of
std.range
for tutorials on ranges.
- Examples:
-
void myprint(scope const(char)[] s) { } static assert(isOutputRange!(typeof(&myprint), char)); static assert( isOutputRange!(char[], char)); static assert( isOutputRange!(dchar[], wchar)); static assert( isOutputRange!(dchar[], dchar));
- enum bool isForwardRange(R);
-
Returns
true
ifR
is a forward range. A forward range is an input ranger
that can save "checkpoints" by savingr.save
to another value of typeR
. Notable examples of input ranges that are not forward ranges are file/socket ranges; copying such a range will not save the position in the stream, and they most likely reuse an internal buffer as the entire stream does not sit in memory. Subsequently, advancing either the original or the copy will advance the stream, so the copies are not independent.The following code should compile for any forward range.
static assert(isInputRange!R); R r1; auto s1 = r1.save; static assert(is(typeof(s1) == R));
Saving a range is not duplicating it; in the example above,r1
andr2
still refer to the same underlying data. They just navigate that data independently.
The semantics of a forward range (not checkable during compilation) are the same as for an input range, with the additional requirement that backtracking must be possible by saving a copy of the range object withsave
and using it later.- See Also:
- The header of
std.range
for tutorials on ranges.
- Examples:
-
static assert(!isForwardRange!(int)); static assert( isForwardRange!(int[])); static assert( isForwardRange!(inout(int)[]));
- enum bool isBidirectionalRange(R);
-
Returns
true
ifR
is a bidirectional range. A bidirectional range is a forward range that also offers the primitivesback
andpopBack
. The following code should compile for any bidirectional range.The semantics of a bidirectional range (not checkable during compilation) are assumed to be the following (
r
is an object of typeR
):
-
r.back
returns (possibly a reference to) the last element in the range. Callingr.back
is allowed only if callingr.empty
has, or would have, returnedfalse
.
- See Also:
- The header of
std.range
for tutorials on ranges.
- Examples:
-
alias R = int[]; R r = [0,1]; static assert(isForwardRange!R); // is forward range r.popBack(); // can invoke popBack auto t = r.back; // can get the back of the range auto w = r.front; static assert(is(typeof(t) == typeof(w))); // same type for front and back
-
- enum bool isRandomAccessRange(R);
-
Returns
true
ifR
is a random-access range. A random-access range is a bidirectional range that also offers the primitiveopIndex
, OR an infinite forward range that offersopIndex
. In either case, the range must either offerlength
or be infinite. The following code should compile for any random-access range.The semantics of a random-access range (not checkable during compilation) are assumed to be the following (
r
is an object of typeR
):-
r.opIndex(n)
returns a reference to then
th element in the range.
Althoughchar[]
andwchar[]
(as well as their qualified versions includingstring
andwstring
) are arrays,isRandomAccessRange
yieldsfalse
for them because they use variable-length encodings (UTF-8 and UTF-16 respectively). These types are bidirectional ranges only.- See Also:
- The header of
std.range
for tutorials on ranges.
- Examples:
-
import std.traits : isAggregateType, isAutodecodableString; alias R = int[]; // range is finite and bidirectional or infinite and forward. static assert(isBidirectionalRange!R || isForwardRange!R && isInfinite!R); R r = [0,1]; auto e = r[1]; // can index auto f = r.front; static assert(is(typeof(e) == typeof(f))); // same type for indexed and front static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges static assert(hasLength!R || isInfinite!R); // must have length or be infinite // $ must work as it does with arrays if opIndex works with $ static if (is(typeof(r[$]))) { static assert(is(typeof(f) == typeof(r[$]))); // $ - 1 doesn't make sense with infinite ranges but needs to work // with finite ones. static if (!isInfinite!R) static assert(is(typeof(f) == typeof(r[$ - 1]))); }
-
- enum bool hasMobileElements(R);
-
Returns
true
iffR
is an input range that supports themoveFront
primitive, as well asmoveBack
andmoveAt
if it's a bidirectional or random access range. These may be explicitly implemented, or may work via the default behavior of the module level functionsmoveFront
and friends. The following code should compile for any range with mobile elements.alias E = ElementType!R; R r; static assert(isInputRange!R); static assert(is(typeof(moveFront(r)) == E)); static if (isBidirectionalRange!R) static assert(is(typeof(moveBack(r)) == E)); static if (isRandomAccessRange!R) static assert(is(typeof(moveAt(r, 0)) == E));
- Examples:
-
import std.algorithm.iteration : map; import std.range : iota, repeat; static struct HasPostblit { this(this) {} } auto nonMobile = map!"a"(repeat(HasPostblit.init)); static assert(!hasMobileElements!(typeof(nonMobile))); static assert( hasMobileElements!(int[])); static assert( hasMobileElements!(inout(int)[])); static assert( hasMobileElements!(typeof(iota(1000)))); static assert( hasMobileElements!( string)); static assert( hasMobileElements!(dstring)); static assert( hasMobileElements!( char[])); static assert( hasMobileElements!(dchar[]));
- template ElementType(R)
-
The element type of
R
.R
does not have to be a range. The element type is determined as the type yielded byr.front
for an objectr
of typeR
. For example,ElementType!(T[])
isT
ifT[]
isn't a narrow string; if it is, the element type isdchar
. IfR
doesn't havefront
,ElementType!R
isvoid
.- Examples:
-
import std.range : iota; // Standard arrays: returns the type of the elements of the array static assert(is(ElementType!(int[]) == int)); // Accessing .front retrieves the decoded dchar static assert(is(ElementType!(char[]) == dchar)); // rvalue static assert(is(ElementType!(dchar[]) == dchar)); // lvalue // Ditto static assert(is(ElementType!(string) == dchar)); static assert(is(ElementType!(dstring) == immutable(dchar))); // For ranges it gets the type of .front. auto range = iota(0, 10); static assert(is(ElementType!(typeof(range)) == int));
- template ElementEncodingType(R)
-
The encoding element type of
R
. For narrow strings (char[]
,wchar[]
and their qualified variants includingstring
andwstring
),ElementEncodingType
is the character type of the string. For all other types,ElementEncodingType
is the same asElementType
.- Examples:
-
import std.range : iota; // internally the range stores the encoded type static assert(is(ElementEncodingType!(char[]) == char)); static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); static assert(is(ElementEncodingType!(byte[]) == byte)); auto range = iota(0, 10); static assert(is(ElementEncodingType!(typeof(range)) == int));
- enum bool hasSwappableElements(R);
-
Returns
true
ifR
is an input range and has swappable elements. The following code should compile for any range with swappable elements.R r; static assert(isInputRange!R); swap(r.front, r.front); static if (isBidirectionalRange!R) swap(r.back, r.front); static if (isRandomAccessRange!R) swap(r[0], r.front);
- Examples:
-
static assert(!hasSwappableElements!(const int[])); static assert(!hasSwappableElements!(const(int)[])); static assert(!hasSwappableElements!(inout(int)[])); static assert( hasSwappableElements!(int[])); static assert(!hasSwappableElements!( string)); static assert(!hasSwappableElements!(dstring)); static assert(!hasSwappableElements!( char[])); static assert( hasSwappableElements!(dchar[]));
- enum bool hasAssignableElements(R);
-
Returns
true
ifR
is an input range and has mutable elements. The following code should compile for any range with assignable elements.R r; static assert(isInputRange!R); r.front = r.front; static if (isBidirectionalRange!R) r.back = r.front; static if (isRandomAccessRange!R) r[0] = r.front;
- Examples:
-
static assert(!hasAssignableElements!(const int[])); static assert(!hasAssignableElements!(const(int)[])); static assert( hasAssignableElements!(int[])); static assert(!hasAssignableElements!(inout(int)[])); static assert(!hasAssignableElements!( string)); static assert(!hasAssignableElements!(dstring)); static assert(!hasAssignableElements!( char[])); static assert( hasAssignableElements!(dchar[]));
- enum bool hasLvalueElements(R);
-
Tests whether the range
R
has lvalue elements. These are defined as elements that can be passed by reference and have their address taken. The following code should compile for any range with lvalue elements.void passByRef(ref ElementType!R stuff); ... static assert(isInputRange!R); passByRef(r.front); static if (isBidirectionalRange!R) passByRef(r.back); static if (isRandomAccessRange!R) passByRef(r[0]);
- template hasLength(R)
-
Yields
true
ifR
has alength
member that returns a value ofsize_t
type.R
does not have to be a range. IfR
is a range, algorithms in the standard library are only guaranteed to supportlength
with typesize_t
.Note that
length
is an optional primitive as no range must implement it. Some ranges do not store their length explicitly, some cannot compute it without actually exhausting the range (e.g. socket streams), and some other ranges may be infinite.
Although narrow string types (char[]
,wchar[]
, and their qualified derivatives) do define alength
property,hasLength
yieldsfalse
for them. This is because a narrow string's length does not reflect the number of characters, but instead the number of encoding units, and as such is not useful with range-oriented algorithms. To use strings as random-access ranges with length, usestd.string.representation
orstd.utf.byCodeUnit
.- Examples:
-
static assert(!hasLength!(char[])); static assert( hasLength!(int[])); static assert( hasLength!(inout(int)[])); struct A { size_t length() { return 0; } } struct B { @property size_t length() { return 0; } } static assert( hasLength!(A)); static assert( hasLength!(B));
- template isInfinite(R)
-
Returns
true
ifR
is an infinite input range. An infinite input range is an input range that has a statically-defined enumerated member calledempty
that is alwaysfalse
, for example:struct MyInfiniteRange { enum bool empty = false; ... }
- Examples:
-
import std.range : Repeat; static assert(!isInfinite!(int[])); static assert( isInfinite!(Repeat!(int)));
- enum bool hasSlicing(R);
-
Returns
true
ifR
offers a slicing operator with integral boundaries that returns a forward range type.For finite ranges, the result of
opSlice
must be of the same type as the original range type. If the range definesopDollar
, then it must support subtraction.
For infinite ranges, when not usingopDollar
, the result ofopSlice
must be the result oftake
ortakeExactly
on the original range (they both return the same type for infinite ranges). However, when usingopDollar
, the result ofopSlice
must be that of the original range type.
The following expression must be true forhasSlicing
to betrue
:
isForwardRange!R && !isNarrowString!R && is(ReturnType!((R r) => r[1 .. 1].length) == size_t) && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R) && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R)) && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R || is(typeof(lvalueOf!R[0 .. $ - 1]) == R)) && is(typeof((ref R r) { static assert(isForwardRange!(typeof(r[1 .. 2]))); }));
- Examples:
-
import std.range : takeExactly; static assert( hasSlicing!(int[])); static assert( hasSlicing!(const(int)[])); static assert(!hasSlicing!(const int[])); static assert( hasSlicing!(inout(int)[])); static assert(!hasSlicing!(inout int [])); static assert( hasSlicing!(immutable(int)[])); static assert(!hasSlicing!(immutable int[])); static assert(!hasSlicing!string); static assert( hasSlicing!dstring); enum rangeFuncs = "@property int front();" ~ "void popFront();" ~ "@property bool empty();" ~ "@property auto save() { return this; }" ~ "@property size_t length();"; struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } static assert(!hasSlicing!(A)); static assert( hasSlicing!(B)); static assert( hasSlicing!(C)); static assert(!hasSlicing!(D)); struct InfOnes { enum empty = false; void popFront() {} @property int front() { return 1; } @property InfOnes save() { return this; } auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } auto opSlice(size_t i, Dollar d) { return this; } struct Dollar {} Dollar opDollar() const { return Dollar.init; } } static assert(hasSlicing!InfOnes);
- auto walkLength(Range)(Range range)
Constraints: if (isInputRange!Range && !isInfinite!Range);
auto walkLength(Range)(Range range, const size_t upTo)
Constraints: if (isInputRange!Range); -
This is a best-effort implementation of
length
for any kind of range.If
hasLength!Range
, simply returnsrange.length
without checkingupTo
(when specified).
Otherwise, walks the range through its length and returns the number of elements seen. Performes Ο(n
) evaluations ofrange.empty
andrange.popFront()
, wheren
is the effective length ofrange
.
TheupTo
parameter is useful to "cut the losses" in case the interest is in seeing whether the range has at least some number of elements. If the parameterupTo
is specified, stops ifupTo
steps have been taken and returnsupTo
.
Infinite ranges are compatible, provided the parameterupTo
is specified, in which case the implementation simply returns upTo.- Examples:
-
import std.range : iota; writeln(10.iota.walkLength); // 10 // iota has a length function, and therefore the // doesn't have to be walked, and the upTo // parameter is ignored writeln(10.iota.walkLength(5)); // 10
- size_t popFrontN(Range)(ref Range r, size_t n)
Constraints: if (isInputRange!Range);
size_t popBackN(Range)(ref Range r, size_t n)
Constraints: if (isBidirectionalRange!Range); -
popFrontN
eagerly advancesr
itself (not a copy) up ton
times (by callingr.popFront
).popFrontN
takesr
byref
, so it mutates the original range. Completes in Ο(1
) steps for ranges that support slicing and have length. Completes in Ο(n
) time for all other ranges.popBackN
behaves the same aspopFrontN
but instead removes elements from the back of the (bidirectional) range instead of the front.- Returns:
- How much
r
was actually advanced, which may be less thann
ifr
did not have at leastn
elements.
- See Also:
-
std.range.drop
,std.range.dropBack
- Examples:
-
int[] a = [ 1, 2, 3, 4, 5 ]; a.popFrontN(2); writeln(a); // [3, 4, 5] a.popFrontN(7); writeln(a); // []
- Examples:
-
import std.algorithm.comparison : equal; import std.range : iota; auto LL = iota(1L, 7L); auto r = popFrontN(LL, 2); assert(equal(LL, [3L, 4L, 5L, 6L])); writeln(r); // 2
- Examples:
-
int[] a = [ 1, 2, 3, 4, 5 ]; a.popBackN(2); writeln(a); // [1, 2, 3] a.popBackN(7); writeln(a); // []
- Examples:
-
import std.algorithm.comparison : equal; import std.range : iota; auto LL = iota(1L, 7L); auto r = popBackN(LL, 2); assert(equal(LL, [1L, 2L, 3L, 4L])); writeln(r); // 2
- void popFrontExactly(Range)(ref Range r, size_t n)
Constraints: if (isInputRange!Range);
void popBackExactly(Range)(ref Range r, size_t n)
Constraints: if (isBidirectionalRange!Range); -
Eagerly advances
r
itself (not a copy) exactlyn
times (by callingr.popFront
).popFrontExactly
takesr
byref
, so it mutates the original range. Completes in Ο(1
) steps for ranges that support slicing, and have either length or are infinite. Completes in Ο(n
) time for all other ranges.- Note
- Unlike
popFrontN
,popFrontExactly
will assume that the range holds at leastn
elements. This makespopFrontExactly
faster thanpopFrontN
, but it also means that ifrange
does not contain at leastn
elements, it will attempt to callpopFront
on an empty range, which is undefined behavior. So, only usepopFrontExactly
when it is guaranteed thatrange
holds at leastn
elements.
popBackExactly
will behave the same but instead removes elements from the back of the (bidirectional) range instead of the front.- See Also:
-
std.range.dropExactly
,std.range.dropBackExactly
- Examples:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : filterBidirectional; auto a = [1, 2, 3]; a.popFrontExactly(1); writeln(a); // [2, 3] a.popBackExactly(1); writeln(a); // [2] string s = "日本語"; s.popFrontExactly(1); writeln(s); // "本語" s.popBackExactly(1); writeln(s); // "本" auto bd = filterBidirectional!"true"([1, 2, 3]); bd.popFrontExactly(1); assert(bd.equal([2, 3])); bd.popBackExactly(1); assert(bd.equal([2]));
- ElementType!R moveFront(R)(R r);
-
Moves the front of
r
out and returns it. Leavesr.front
in a destroyable state that does not allocate any resources (usually equal to its.init
value).- Examples:
-
auto a = [ 1, 2, 3 ]; writeln(moveFront(a)); // 1 writeln(a.length); // 3 // define a perfunctory input range struct InputRange { enum bool empty = false; enum int front = 7; void popFront() {} int moveFront() { return 43; } } InputRange r; // calls r.moveFront writeln(moveFront(r)); // 43
- ElementType!R moveBack(R)(R r);
-
Moves the back of
r
out and returns it. Leavesr.back
in a destroyable state that does not allocate any resources (usually equal to its.init
value).- Examples:
-
struct TestRange { int payload = 5; @property bool empty() { return false; } @property TestRange save() { return this; } @property ref int front() return { return payload; } @property ref int back() return { return payload; } void popFront() { } void popBack() { } } static assert(isBidirectionalRange!TestRange); TestRange r; auto x = moveBack(r); writeln(x); // 5
- ElementType!R moveAt(R)(R r, size_t i);
-
Moves element at index
i
ofr
out and returns it. Leavesr[i]
in a destroyable state that does not allocate any resources (usually equal to its.init
value).- Examples:
-
auto a = [1,2,3,4]; foreach (idx, it; a) { writeln(it); // moveAt(a, idx) }
- @property bool empty(T)(auto ref scope T a)
Constraints: if (is(typeof(a.length) : size_t)); -
Implements the range interface primitive
empty
for types that obeyhasLength
property and for narrow strings. Due to the fact that nonmember functions can be called with the first argument using the dot notation,a.empty
is equivalent toempty(a)
.- Examples:
-
auto a = [ 1, 2, 3 ]; assert(!a.empty); assert(a[3 .. $].empty); int[string] b; assert(b.empty); b["zero"] = 0; assert(!b.empty);
- pure nothrow @nogc @property @safe inout(T)[] save(T)(return scope inout(T)[] a);
-
Implements the range interface primitive
save
for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation,array.save
is equivalent tosave(array)
. The function does not duplicate the content of the array, it simply returns its argument.- Examples:
-
auto a = [ 1, 2, 3 ]; auto b = a.save; assert(b is a);
- pure nothrow @nogc @safe void popFront(T)(ref scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure nothrow @trusted void popFront(C)(ref scope inout(C)[] str)
Constraints: if (isAutodecodableString!(C[])); -
Implements the range interface primitive
popFront
for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation,array.popFront
is equivalent topopFront(array)
. For narrow strings,popFront
automatically advances to the next code point.- Examples:
-
auto a = [ 1, 2, 3 ]; a.popFront(); writeln(a); // [2, 3]
- pure nothrow @nogc @safe void popBack(T)(ref scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure @safe void popBack(T)(ref scope inout(T)[] a)
Constraints: if (isAutodecodableString!(T[])); -
Implements the range interface primitive
popBack
for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation,array.popBack
is equivalent topopBack(array)
. For narrow strings,popFront
automatically eliminates the last code point.- Examples:
-
auto a = [ 1, 2, 3 ]; a.popBack(); writeln(a); // [1, 2]
- enum bool autodecodeStrings;
-
- EXPERIMENTAL
- to try out removing autodecoding, set the version
NoAutodecodeStrings
. Most things are expected to fail with this version currently.
- pure nothrow @nogc @property ref @safe inout(T) front(T)(return scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure @property @safe dchar front(T)(scope const(T)[] a)
Constraints: if (isAutodecodableString!(T[])); -
Implements the range interface primitive
front
for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation,array.front
is equivalent tofront(array)
. For narrow strings,front
automatically returns the first code point as adchar
.- Examples:
-
int[] a = [ 1, 2, 3 ]; writeln(a.front); // 1
- pure nothrow @nogc @property ref @safe inout(T) back(T)(return scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure @property @safe dchar back(T)(scope const(T)[] a)
Constraints: if (isAutodecodableString!(T[])); -
Implements the range interface primitive
back
for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation,array.back
is equivalent toback(array)
. For narrow strings,back
automatically returns the last code point as adchar
.- Examples:
-
int[] a = [ 1, 2, 3 ]; writeln(a.back); // 3 a.back += 4; writeln(a.back); // 7
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_range_primitives.html