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 testingwhether a given object is a range, and what kind of range it is:
isInputRange | Tests if something is aninput range, defined to be something from which one can sequentially read data using the primitivesfront,popFront, andempty. |
isOutputRange | Tests if something is anoutput range, defined to be something to which one can sequentially write data using theput primitive. |
isForwardRange | Tests if something is aforward range, defined to be an input range with the additional capability that one can save one's current position with thesave primitive, thus allowing one to iterate over the same range multiple times. |
isBidirectionalRange | Tests if something is abidirectional range, that is, a forward range that allows reverse traversal using the primitives back andpopBack. |
isRandomAccessRange | Tests if something is arandom access range, which is a bidirectional range that also supports the array subscripting operation via the primitiveopIndex. |
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 primitivesmoveFront,moveBack, ormoveAt. |
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 thelength attribute. |
isInfinite | Tests if a given range is aninfinite 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 ton elements. |
popBackN | Advances a given bidirectional range from the right by up ton elements. |
popFrontExactly | Advances a given range by up exactlyn elements. |
popBackExactly | Advances a given bidirectional range from the right by exactlyn elements. |
moveFront | Removes the front element of a range. |
moveBack | Removes the back element of a bidirectional range. |
moveAt | Removes thei'th element of a random-access range. |
walkLength | Computes the length of any range in O(n) time. |
put | Outputs elemente to a range. |
enum bool
isInputRange
(R);
enum bool
isInputRange
(R, E);
Returnstrue ifR is an input range. An input range mustdefine the primitivesempty,popFront, andfront. Thefollowing code should compile for any input range.
R r;// can define a range objectif (r.empty) {}// can test for emptyr.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 allPhobos code. These rules are not checkable at compile-time, so not conformingto these rules when writing ranges or range based code will result inundefined 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 primitives
r.front and
r.empty are
Ο(1) time complexity wise or "cheap" in terms ofrunning time.
Ο() statements in the documentation of range functionsare made with this assumption.
See Also:The header of
std.range for tutorials on ranges.
Returns:true if R is an input range (possibly with element typeE),false if not
Examples:struct A {}struct B{void popFront(); @propertybool empty(); @propertyint front();}staticassert(!isInputRange!A);staticassert(isInputRange!B);staticassert(isInputRange!(int[]));staticassert(isInputRange!(char[]));staticassert(!isInputRange!(char[4]));staticassert(isInputRange!(inout(int)[]));staticassert(!isInputRange!(int[], string));staticassert(isInputRange!(int[],int));staticassert(isInputRange!(int[],constint));staticassert(!isInputRange!(int[],immutableint));staticassert(!isInputRange!(const(int)[],int));staticassert(isInputRange!(const(int)[],constint));staticassert(!isInputRange!(const(int)[],immutableint));staticassert(!isInputRange!(immutable(int)[],int));staticassert(isInputRange!(immutable(int)[],constint));staticassert(isInputRange!(immutable(int)[],immutableint));staticstruct NotDefaultConstructible{ @disablethis();void popFront(); @propertybool empty(); @propertyint front();}staticassert(isInputRange!NotDefaultConstructible);staticstruct NotDefaultConstructibleOrCopyable{ @disablethis(); @disablethis(this);void popFront(); @propertybool empty(); @propertyint front();}staticassert(isInputRange!NotDefaultConstructibleOrCopyable);staticstruct Frontless{void popFront(); @propertybool empty();}staticassert(!isInputRange!Frontless);staticstruct VoidFront{void popFront(); @propertybool empty();void front();}staticassert(!isInputRange!VoidFront);
void
put
(R, E)(ref R
r
, E
e
);
Outputse
tor
. The exact effect is dependent upon the twotypes. Several cases are accepted, as described below. The code snippetsare attempted in order, and the first to compile "wins" and getsevaluated.
In this table "doPut" is a method that places
e
into
r
, using thecorrect primitive:
r
.put
(e
) if
R defines
put
,
r.front = eif
r
is an input range (followed by
r
.popFront()), or
r
(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 rangeE intoR. |
Tipput
shouldnot be used "UFCS-style", e.g.r
.put
(e
).Doing this may callR.put
directly, by-passing any transformationfeature provided byRange.put
.put(r, e) is prefered.
Examples:When an output range's
put
method only accepts elements of type
T, use the global
put
to handle outputting a
T[] to the range or vice-versa.
import std.traits : isSomeChar;staticstruct A{ string data;voidput(C)(C c)if (isSomeChar!C) { data ~= c; }}staticassert(isOutputRange!(A,char));auto a = A();put(a,"Hello");writeln(a.data);// "Hello"
Examples:put
treats dynamic arrays as array slices, and will call
popFront on the slice after an element has been copied.
Be sure to save the position of the array before calling
put
.
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 arraywriteln(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 is
nothrow, but transcoding can throw a
std.utf.UTFException.
// the elements must be mutable, so using string or const(char)[]// won't compilechar[] s1 =newchar[13];auto r1 = s1;put(r1,"Hello, World!"w);writeln(s1);// "Hello, World!"
enum bool
isOutputRange
(R, E);
Returnstrue ifR is an output range for elements of typeE. An output range is defined functionally as a range thatsupports the operationput(r, e) as defined above.
See Also:The header of
std.range for tutorials on ranges.
Examples:void myprint(scopeconst(char)[] s) { }staticassert(isOutputRange!(typeof(&myprint),char));staticassert(isOutputRange!(char[],char));staticassert(isOutputRange!(dchar[],wchar));staticassert(isOutputRange!(dchar[],dchar));
enum bool
isForwardRange
(R);
enum bool
isForwardRange
(R, E);
Returnstrue ifR is a forward range. A forward range is aninput ranger that can save "checkpoints" by savingr.saveto another value of typeR. Notable examples of input ranges thatarenot forward ranges are file/socket ranges; copying such arange will not save the position in the stream, and they most likelyreuse an internal buffer as the entire stream does not sit inmemory. Subsequently, advancing either the original or the copy willadvance the stream, so the copies are not independent.
The following code should compile for any forward range.
staticassert(isInputRange!R);R r1;auto s1 = r1.save;staticassert(is(typeof(s1) == R));
Saving a range is not duplicating it; in the example above,
r1and
r2 still refer to the same underlying data. They justnavigate that data independently.
The semantics of a forward range (not checkable during compilation)are the same as for an input range, with the additional requirementthat backtracking must be possible by saving a copy of the rangeobject with
save and using it later.
save behaves in many ways like a copy constructor, and itsimplementation typically is done using copy construction.
The existence of a copy constructor, however, does not implythe range is a forward range. For example, a range that readsfrom a TTY consumes its input and cannot save its place andread it again, and so cannot be a forward range and cannothave a
save function.
See Also:The header of
std.range for tutorials on ranges.
Returns:true if R is a forward range (possibly with element typeE),false if not
Examples:staticassert(!isForwardRange!(int));staticassert(isForwardRange!(int[]));staticassert(isForwardRange!(inout(int)[]));staticassert(isForwardRange!(int[],constint));staticassert(!isForwardRange!(int[],immutableint));staticassert(!isForwardRange!(const(int)[],int));staticassert(isForwardRange!(const(int)[],constint));staticassert(!isForwardRange!(const(int)[],immutableint));staticassert(!isForwardRange!(immutable(int)[],int));staticassert(isForwardRange!(immutable(int)[],constint));staticassert(isForwardRange!(immutable(int)[],immutableint));
enum bool
isBidirectionalRange
(R);
enum bool
isBidirectionalRange
(R, E);
Returnstrue ifR is a bidirectional range. A bidirectionalrange is a forward range that also offers the primitivesback andpopBack. The following code should compile for any bidirectionalrange.
The semantics of a bidirectional range (not checkable duringcompilation) are assumed to be the following (
r is an object oftype
R):
- r.back returns (possibly a reference to) the lastelement 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.
Returns:true if R is a bidirectional range (possibly with element typeE),false if not
Examples:alias R =int[];R r = [0,1];staticassert(isForwardRange!R);// is forward ranger.popBack();// can invoke popBackauto t = r.back;// can get the back of the rangeauto w = r.front;staticassert(is(typeof(t) ==typeof(w)));// same type for front and back// Checking the element typestaticassert(isBidirectionalRange!(int[],constint));staticassert(!isBidirectionalRange!(int[],immutableint));staticassert(!isBidirectionalRange!(const(int)[],int));staticassert(isBidirectionalRange!(const(int)[],constint));staticassert(!isBidirectionalRange!(const(int)[],immutableint));staticassert(!isBidirectionalRange!(immutable(int)[],int));staticassert(isBidirectionalRange!(immutable(int)[],constint));staticassert(isBidirectionalRange!(immutable(int)[],immutableint));
enum bool
isRandomAccessRange
(R);
enum bool
isRandomAccessRange
(R, E);
Returnstrue ifR is a random-access range. A random-accessrange is a bidirectional range that also offers the primitiveopIndex, OR an infinite forward range that offersopIndex. Ineither case, the range must either offerlength or beinfinite. The following code should compile for any random-accessrange.
The semantics of a random-access range (not checkable duringcompilation) are assumed to be the following (
r is an object oftype
R):
- r.opIndex(n) returns a reference to thenth element in the range.
Although
char[] and
wchar[] (as well as their qualifiedversions including
string and
wstring) are arrays,
isRandomAccessRange yields
false for them because they usevariable-length encodings (UTF-8 and UTF-16 respectively). These typesare bidirectional ranges only.
See Also:The header of
std.range for tutorials on ranges.
Returns:true if R is a random-access range (possibly with element typeE),false if not
Examples:import std.traits : isAggregateType, isAutodecodableString;alias R =int[];// range is finite and bidirectional or infinite and forward.staticassert(isBidirectionalRange!R || isForwardRange!R && isInfinite!R);R r = [0,1];auto e = r[1];// can indexauto f = r.front;staticassert(is(typeof(e) ==typeof(f)));// same type for indexed and frontstaticassert(!(isAutodecodableString!R && !isAggregateType!R));// narrow strings cannot be indexed as rangesstaticassert(hasLength!R || isInfinite!R);// must have length or be infinite// $ must work as it does with arrays if opIndex works with $staticif (is(typeof(r[$]))){staticassert(is(typeof(f) ==typeof(r[$])));// $ - 1 doesn't make sense with infinite ranges but needs to work// with finite ones.staticif (!isInfinite!R)staticassert(is(typeof(f) ==typeof(r[$ - 1])));}// Checking the element typestaticassert(isRandomAccessRange!(int[],constint));staticassert(!isRandomAccessRange!(int[],immutableint));staticassert(!isRandomAccessRange!(const(int)[],int));staticassert(isRandomAccessRange!(const(int)[],constint));staticassert(!isRandomAccessRange!(const(int)[],immutableint));staticassert(!isRandomAccessRange!(immutable(int)[],int));staticassert(isRandomAccessRange!(immutable(int)[],constint));staticassert(isRandomAccessRange!(immutable(int)[],immutableint));
enum bool
hasMobileElements
(R);
Returnstrue iffR is an input range that supports themoveFront primitive, as well asmoveBack andmoveAt if it's abidirectional or random access range. These may be explicitly implemented, ormay work via the default behavior of the module level functionsmoveFrontand friends. The following code should compile for any rangewith mobile elements.
alias E = ElementType!R;R r;staticassert(isInputRange!R);staticassert(is(typeof(moveFront(r)) == E));staticif (isBidirectionalRange!R)staticassert(is(typeof(moveBack(r)) == E));staticif (isRandomAccessRange!R)staticassert(is(typeof(moveAt(r, 0)) == E));
Examples:import std.algorithm.iteration : map;import std.range : iota, repeat;staticstruct HasPostblit{this(this) {}}auto nonMobile = map!"a"(repeat(HasPostblit.init));staticassert(!hasMobileElements!(typeof(nonMobile)));staticassert(hasMobileElements!(int[]));staticassert(hasMobileElements!(inout(int)[]));staticassert(hasMobileElements!(typeof(iota(1000))));staticassert(hasMobileElements!( string));staticassert(hasMobileElements!(dstring));staticassert(hasMobileElements!(char[]));staticassert(hasMobileElements!(dchar[]));
The element type ofR.R does not have to be a range. Theelement type is determined as the type yielded byr.front for anobjectr 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 arraystaticassert(is(ElementType!(int[]) ==int));// Accessing .front retrieves the decoded dcharstaticassert(is(ElementType!(char[]) ==dchar));// rvaluestaticassert(is(ElementType!(dchar[]) ==dchar));// lvalue// Dittostaticassert(is(ElementType!(string) ==dchar));staticassert(is(ElementType!(dstring) ==immutable(dchar)));// For ranges it gets the type of .front.auto range = iota(0, 10);staticassert(is(ElementType!(typeof(range)) ==int));
template
ElementEncodingType
(R)
The encoding element type ofR. For narrow strings (char[],wchar[] and their qualified variants includingstring andwstring),ElementEncodingType
is the character type of thestring. For all other types,ElementEncodingType
is the same asElementType.
Examples:import std.range : iota;// internally the range stores the encoded typestaticassert(is(ElementEncodingType!(char[]) ==char));staticassert(is(ElementEncodingType!(wstring) ==immutable(wchar)));staticassert(is(ElementEncodingType!(byte[]) ==byte));auto range = iota(0, 10);staticassert(is(ElementEncodingType!(typeof(range)) ==int));
enum bool
hasSwappableElements
(R);
Returnstrue ifR is an input range and has swappableelements. The following code should compile for any rangewith swappable elements.
R r;staticassert(isInputRange!R);swap(r.front, r.front);staticif (isBidirectionalRange!R) swap(r.back, r.front);staticif (isRandomAccessRange!R) swap(r[0], r.front);
Examples:staticassert(!hasSwappableElements!(constint[]));staticassert(!hasSwappableElements!(const(int)[]));staticassert(!hasSwappableElements!(inout(int)[]));staticassert(hasSwappableElements!(int[]));staticassert(!hasSwappableElements!( string));staticassert(!hasSwappableElements!(dstring));staticassert(!hasSwappableElements!(char[]));staticassert(hasSwappableElements!(dchar[]));
enum bool
hasAssignableElements
(R);
Returnstrue ifR is an input range and has mutableelements. The following code should compile for any rangewith assignable elements.
R r;staticassert(isInputRange!R);r.front = r.front;staticif (isBidirectionalRange!R) r.back = r.front;staticif (isRandomAccessRange!R) r[0] = r.front;
Examples:staticassert(!hasAssignableElements!(constint[]));staticassert(!hasAssignableElements!(const(int)[]));staticassert(hasAssignableElements!(int[]));staticassert(!hasAssignableElements!(inout(int)[]));staticassert(!hasAssignableElements!( string));staticassert(!hasAssignableElements!(dstring));staticassert(!hasAssignableElements!(char[]));staticassert(hasAssignableElements!(dchar[]));
enum bool
hasLvalueElements
(R);
Tests whether the range
R has lvalue elements. These are defined aselements 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);...staticassert(isInputRange!R);passByRef(r.front);staticif (isBidirectionalRange!R) passByRef(r.back);staticif (isRandomAccessRange!R) passByRef(r[0]);
Yieldstrue ifR has alength member that returns a value ofsize_ttype.R does not have to be a range. IfR is a range, algorithms in thestandard library are only guaranteed to supportlength with typesize_t.
Note that
length is an optional primitive as no range must implement it. Someranges do not store their length explicitly, some cannot compute it withoutactually exhausting the range (e.g. socket streams), and some other ranges maybe infinite.
Although narrow string types (
char[],
wchar[], and their qualifiedderivatives) do define a
length property,
hasLength
yields
false for them.This is because a narrow string's length does not reflect the number ofcharacters, but instead the number of encoding units, and as such is not usefulwith range-oriented algorithms. To use strings as random-access ranges withlength, use
std.string.representation or
std.utf.byCodeUnit.
Examples:staticassert(!hasLength!(char[]));staticassert(hasLength!(int[]));staticassert(hasLength!(inout(int)[]));struct A { size_t length() {return 0; } }struct B { @property size_t length() {return 0; } }staticassert(hasLength!(A));staticassert(hasLength!(B));
Returnstrue ifR is an infinite input range. Aninfinite input range is an input range that has a statically-definedenumerated member calledempty that is alwaysfalse,for example:
struct MyInfiniteRange{enumbool empty =false; ...}
Examples:import std.range : Repeat;staticassert(!isInfinite!(int[]));staticassert(isInfinite!(Repeat!(int)));
Returnstrue ifR offers a slicing operator with integral boundariesthat returns a forward range type.
For finite ranges, the result of
opSlice must be of the same type as theoriginal range type. If the range defines
opDollar, then it must supportsubtraction.
For infinite ranges, when
not using
opDollar, the result of
opSlicemay be a forward range of any type. However, when using
opDollar, the resultof
opSlice must be of the same type as the original range type.
The following expression must be true for
hasSlicing
to be
true:
isForwardRange!R && !(isAutodecodableString!R && !isAggregateType!R) &&is(typeof((R r) {return r[1 .. 1].length; } (R.init)) == 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) {staticassert(isForwardRange!(typeof(r[1 .. 2]))); }));
Examples:import std.range : takeExactly;staticassert(hasSlicing!(int[]));staticassert(hasSlicing!(const(int)[]));staticassert(!hasSlicing!(constint[]));staticassert(hasSlicing!(inout(int)[]));staticassert(!hasSlicing!(inoutint []));staticassert(hasSlicing!(immutable(int)[]));staticassert(!hasSlicing!(immutableint[]));staticassert(!hasSlicing!string);staticassert(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); @disablethis(); C opSlice(size_t, size_t); }struct D {mixin(rangeFuncs);int[] opSlice(size_t, size_t); }staticassert(!hasSlicing!(A));staticassert(hasSlicing!(B));staticassert(hasSlicing!(C));staticassert(!hasSlicing!(D));struct InfOnes{enum empty =false;void popFront() {} @propertyint front() {return 1; } @property InfOnes save() {returnthis; }auto opSlice(size_t i, size_t j) {return takeExactly(this, j - i); }auto opSlice(size_t i, Dollar d) {returnthis; }struct Dollar {} Dollar opDollar()const {return Dollar.init; }}staticassert(hasSlicing!InfOnes);
auto
walkLength
(Range)(Range
range
)
if (isInputRange!Range && !isInfinite!Range);
auto
walkLength
(Range)(Range
range
, const size_t
upTo
)
if (isInputRange!Range);
This is a best-effort implementation oflength for any kind ofrange.
If
hasLength!Range, simply returns
range
.length withoutchecking
upTo
(when specified).
Otherwise, walks the range through its length and returns the numberof elements seen. Performes
Ο(n) evaluations of
range
.emptyand
range
.popFront(), where
n is the effective length of
range.
The
upTo
parameter is useful to "cut the losses" in casethe interest is in seeing whether the range has at least some numberof elements. If the parameter
upTo
is specified, stops if
upTo steps have been taken and returns
upTo
.
Infinite ranges are compatible, provided the parameter
upTo
isspecified, 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 ignoredwriteln(10.iota.walkLength(5));// 10
size_t
popFrontN
(Range)(ref Range
r
, size_t
n
)
if (isInputRange!Range);
size_t
popBackN
(Range)(ref Range
r
, size_t
n
)
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 muchr
was actually advanced, which may be less thann
ifr
did not have at leastn
elements.
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);autor =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);autor =popBackN(LL, 2);assert(equal(LL, [1L, 2L, 3L, 4L]));writeln(r);// 2
void
popFrontExactly
(Range)(ref Range
r
, size_t
n
)
if (isInputRange!Range);
void
popBackExactly
(Range)(ref Range
r
, size_t
n
)
if (isBidirectionalRange!Range);
Eagerly advancesr
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.
NoteUnlikepopFrontN,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.
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 ofr
out and returns it.
If
r
.front is a struct with a destructor or copy constructor defined, it is reset to its
.init value after its value is moved. Otherwise, it is left unchanged.
In either case,
r
.front is left in a destroyable state that does not allocate any resources.
Examples:auto a = [ 1, 2, 3 ];writeln(moveFront(a));// 1writeln(a.length);// 3// define a perfunctory input rangestruct InputRange{enumbool empty =false;enumint front = 7;void popFront() {}intmoveFront() {return 43; }}InputRanger;// calls r.moveFrontwriteln(moveFront(r));// 43
ElementType!R
moveBack
(R)(R
r
);
Moves the back ofr
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; @propertybool empty() {returnfalse; } @property TestRange save() {returnthis; } @propertyrefint front()return {return payload; } @propertyrefint back()return {return payload; }void popFront() { }void popBack() { }}staticassert(isBidirectionalRange!TestRange);TestRanger;auto x =moveBack(r);writeln(x);// 5
ElementType!R
moveAt
(R)(R
r
, size_t
i
);
Moves element at indexi
ofr
out and returns it. Leaves r[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
)
if (is(typeof(a
.length) : size_t));
Implements the range interface primitive
empty
for types thatobey
hasLength property and for narrow strings. Due to thefact that nonmember functions can be called with the first argumentusing the dot notation,
a
.empty
is equivalent to
empty
(a
).
Examples:autoa = [ 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 primitivesave
for built-inarrays. Due to the fact that nonmember functions can be called withthe first argument using the dot notation,array.save
isequivalent tosave
(array). The function does not duplicate thecontent of the array, it simply returns its argument.
Examples:autoa = [ 1, 2, 3 ];auto b =a.save;assert(bisa);
pure nothrow @nogc @safe void
popFront
(T)(ref scope inout(T)[]
a
)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure nothrow @trusted void
popFront
(C)(ref scope inout(C)[]
str
)
if (isAutodecodableString!(C[]));
Implements the range interface primitive
popFront
for built-inarrays. Due to the fact that nonmember functions can be called withthe first argument using the dot notation,
array.popFront
isequivalent to
popFront
(array). For
narrow strings,
popFront
automatically advances to the next
codepoint.
Examples:autoa = [ 1, 2, 3 ];a.popFront();writeln(a);// [2, 3]
pure nothrow @nogc @safe void
popBack
(T)(ref scope inout(T)[]
a
)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure @safe void
popBack
(T)(ref scope inout(T)[]
a
)
if (isAutodecodableString!(T[]));
Implements the range interface primitive
popBack
for built-inarrays. Due to the fact that nonmember functions can be called withthe first argument using the dot notation,
array.popBack
isequivalent to
popBack
(array). For
narrow strings,
popFront automatically eliminates the last
code point.
Examples:autoa = [ 1, 2, 3 ];a.popBack();writeln(a);// [1, 2]
enum bool
autodecodeStrings
;
EXPERIMENTALto try out removing autodecoding, set the versionNoAutodecodeStrings. Most things are expected to fail with this versioncurrently.
pure nothrow @nogc @property ref @safe inout
(T)front
(T)(return scope inout(T)[]
a
)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure @property @safe dchar
front
(T)(scope const(T)[]
a
)
if (isAutodecodableString!(T[]));
Implements the range interface primitive
front
for built-inarrays. Due to the fact that nonmember functions can be called withthe first argument using the dot notation,
array.front
isequivalent to
front
(array). For
narrow strings,
front automatically returns the first
code point as a
dchar.
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
)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));
pure @property @safe dchar
back
(T)(scope const(T)[]
a
)
if (isAutodecodableString!(T[]));
Implements the range interface primitive
back
for built-inarrays. Due to the fact that nonmember functions can be called withthe first argument using the dot notation,
array.back
isequivalent to
back
(array). For
narrow strings,
back automatically returns the last
code point as a
dchar.
Examples:int[]a = [ 1, 2, 3 ];writeln(a.back);// 3a.back += 4;writeln(a.back);// 7