|  | /** | 
|  | This module is a submodule of $(MREF std, range). | 
|  |  | 
|  | It defines the bidirectional and forward range primitives for arrays: | 
|  | $(LREF empty), $(LREF front), $(LREF back), $(LREF popFront), $(LREF popBack) and $(LREF 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: | 
|  |  | 
|  | $(SCRIPT inhibitQuickIndex = 1;) | 
|  | $(DIVC quickindex, | 
|  | $(BOOKTABLE , | 
|  | $(TR $(TD $(LREF isInputRange)) | 
|  | $(TD Tests if something is an $(I input range), defined to be | 
|  | something from which one can sequentially read data using the | 
|  | primitives `front`, `popFront`, and `empty`. | 
|  | )) | 
|  | $(TR $(TD $(LREF isOutputRange)) | 
|  | $(TD Tests if something is an $(I output range), defined to be | 
|  | something to which one can sequentially write data using the | 
|  | $(LREF put) primitive. | 
|  | )) | 
|  | $(TR $(TD $(LREF isForwardRange)) | 
|  | $(TD Tests if something is a $(I 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. | 
|  | )) | 
|  | $(TR $(TD $(LREF isBidirectionalRange)) | 
|  | $(TD Tests if something is a $(I bidirectional range), that is, a | 
|  | forward range that allows reverse traversal using the primitives $(D | 
|  | back) and `popBack`. | 
|  | )) | 
|  | $(TR $(TD $(LREF isRandomAccessRange)) | 
|  | $(TD Tests if something is a $(I 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: | 
|  |  | 
|  | $(BOOKTABLE , | 
|  | $(TR $(TD $(LREF hasMobileElements)) | 
|  | $(TD Tests if a given range's elements can be moved around using the | 
|  | primitives `moveFront`, `moveBack`, or `moveAt`. | 
|  | )) | 
|  | $(TR $(TD $(LREF ElementType)) | 
|  | $(TD Returns the element type of a given range. | 
|  | )) | 
|  | $(TR $(TD $(LREF ElementEncodingType)) | 
|  | $(TD Returns the encoding element type of a given range. | 
|  | )) | 
|  | $(TR $(TD $(LREF hasSwappableElements)) | 
|  | $(TD Tests if a range is a forward range with swappable elements. | 
|  | )) | 
|  | $(TR $(TD $(LREF hasAssignableElements)) | 
|  | $(TD Tests if a range is a forward range with mutable elements. | 
|  | )) | 
|  | $(TR $(TD $(LREF hasLvalueElements)) | 
|  | $(TD Tests if a range is a forward range with elements that can be | 
|  | passed by reference and have their address taken. | 
|  | )) | 
|  | $(TR $(TD $(LREF hasLength)) | 
|  | $(TD Tests if a given range has the `length` attribute. | 
|  | )) | 
|  | $(TR $(TD $(LREF isInfinite)) | 
|  | $(TD Tests if a given range is an $(I infinite range). | 
|  | )) | 
|  | $(TR $(TD $(LREF hasSlicing)) | 
|  | $(TD Tests if a given range supports the array slicing operation $(D | 
|  | R[x .. y]). | 
|  | )) | 
|  | ) | 
|  |  | 
|  | Finally, it includes some convenience functions for manipulating ranges: | 
|  |  | 
|  | $(BOOKTABLE , | 
|  | $(TR $(TD $(LREF popFrontN)) | 
|  | $(TD Advances a given range by up to $(I n) elements. | 
|  | )) | 
|  | $(TR $(TD $(LREF popBackN)) | 
|  | $(TD Advances a given bidirectional range from the right by up to | 
|  | $(I n) elements. | 
|  | )) | 
|  | $(TR $(TD $(LREF popFrontExactly)) | 
|  | $(TD Advances a given range by up exactly $(I n) elements. | 
|  | )) | 
|  | $(TR $(TD $(LREF popBackExactly)) | 
|  | $(TD Advances a given bidirectional range from the right by exactly | 
|  | $(I n) elements. | 
|  | )) | 
|  | $(TR $(TD $(LREF moveFront)) | 
|  | $(TD Removes the front element of a range. | 
|  | )) | 
|  | $(TR $(TD $(LREF moveBack)) | 
|  | $(TD Removes the back element of a bidirectional range. | 
|  | )) | 
|  | $(TR $(TD $(LREF moveAt)) | 
|  | $(TD Removes the $(I i)'th element of a random-access range. | 
|  | )) | 
|  | $(TR $(TD $(LREF walkLength)) | 
|  | $(TD Computes the length of any range in O(n) time. | 
|  | )) | 
|  | $(TR $(TD $(LREF put)) | 
|  | $(TD Outputs element `e` to a range. | 
|  | )) | 
|  | ) | 
|  |  | 
|  | Source: $(PHOBOSSRC std/range/primitives.d) | 
|  |  | 
|  | License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). | 
|  |  | 
|  | Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, and | 
|  | $(HTTP jmdavisprog.com, Jonathan M Davis). Credit for some of the ideas | 
|  | in building this module goes to | 
|  | $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi). | 
|  | */ | 
|  | module std.range.primitives; | 
|  |  | 
|  | import std.traits; | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` is an input range. An input range must | 
|  | define the primitives `empty`, `popFront`, and `front`. 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. | 
|  |  | 
|  | $(UL | 
|  | $(LI `r.empty` returns `false` if and only if there is more data | 
|  | available in the range.) | 
|  | $(LI `r.empty` evaluated multiple times, without calling | 
|  | `r.popFront`, or otherwise mutating the range object or the | 
|  | underlying data, yields the same result for every evaluation.) | 
|  | $(LI `r.front` returns the current element in the range. | 
|  | It may return by value or by reference.) | 
|  | $(LI `r.front` can be legally evaluated if and only if evaluating | 
|  | `r.empty` has, or would have, equaled `false`.) | 
|  | $(LI `r.front` evaluated multiple times, without calling | 
|  | `r.popFront`, or otherwise mutating the range object or the | 
|  | underlying data, yields the same result for every evaluation.) | 
|  | $(LI `r.popFront` advances to the next element in the range.) | 
|  | $(LI `r.popFront` can be called if and only if evaluating `r.empty` | 
|  | has, or would have, equaled `false`.) | 
|  | ) | 
|  |  | 
|  | Also, note that Phobos code assumes that the primitives `r.front` and | 
|  | `r.empty` are $(BIGOH 1) time complexity wise or "cheap" in terms of | 
|  | running time. $(BIGOH) statements in the documentation of range functions | 
|  | are made with this assumption. | 
|  |  | 
|  | See_Also: | 
|  | The header of $(MREF std,range) for tutorials on ranges. | 
|  |  | 
|  | Params: | 
|  | R = type to be tested | 
|  | E = if present, the elements of the range must be | 
|  | $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) | 
|  | to this type | 
|  |  | 
|  | Returns: | 
|  | `true` if R is an input range (possibly with element type `E`), `false` if not | 
|  | */ | 
|  | enum bool isInputRange(R) = | 
|  | is(typeof(R.init) == R) | 
|  | && is(typeof((R r) { return r.empty; } (R.init)) == bool) | 
|  | && (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front))) | 
|  | && !is(typeof((R r) { return r.front; } (R.init)) == void) | 
|  | && is(typeof((R r) => r.popFront)); | 
|  |  | 
|  | /// ditto | 
|  | enum bool isInputRange(R, E) = | 
|  | .isInputRange!R && isQualifierConvertible!(ElementType!R, E); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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 assert(!isInputRange!(int[], string)); | 
|  | static assert( isInputRange!(int[], int)); | 
|  | static assert( isInputRange!(int[], const int)); | 
|  | static assert(!isInputRange!(int[], immutable int)); | 
|  |  | 
|  | static assert(!isInputRange!(const(int)[], int)); | 
|  | static assert( isInputRange!(const(int)[], const int)); | 
|  | static assert(!isInputRange!(const(int)[], immutable int)); | 
|  |  | 
|  | static assert(!isInputRange!(immutable(int)[], int)); | 
|  | static assert( isInputRange!(immutable(int)[], const int)); | 
|  | static assert( isInputRange!(immutable(int)[], immutable 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); | 
|  | } | 
|  | // https://issues.dlang.org/show_bug.cgi?id=16034 | 
|  | @safe unittest | 
|  | { | 
|  | struct One | 
|  | { | 
|  | int entry = 1; | 
|  | @disable this(this); | 
|  | } | 
|  |  | 
|  | assert(isInputRange!(One[])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | static struct R | 
|  | { | 
|  | static struct Front | 
|  | { | 
|  | R* impl; | 
|  | @property int value() { return impl._front; } | 
|  | alias value this; | 
|  | } | 
|  |  | 
|  | int _front; | 
|  |  | 
|  | @property bool empty() { return _front >= 3; } | 
|  | @property auto front() { return Front(&this); } | 
|  | void popFront() { _front++; } | 
|  | } | 
|  | R r; | 
|  |  | 
|  | static assert(isInputRange!R); | 
|  | assert(r.equal([ 0, 1, 2 ])); | 
|  | } | 
|  |  | 
|  | /+ | 
|  | puts the whole raw element `e` into `r`. doPut will not attempt to | 
|  | iterate, slice or transcode `e` in any way shape or form. It will $(B only) | 
|  | call the correct primitive (`r.put(e)`,  $(D r.front = e) or | 
|  | `r(e)` once. | 
|  |  | 
|  | This can be important when `e` needs to be placed in `r` unchanged. | 
|  | Furthermore, it can be useful when working with `InputRange`s, as doPut | 
|  | guarantees that no more than a single element will be placed. | 
|  | +/ | 
|  | private void doPut(R, E)(ref R r, auto ref E e) | 
|  | { | 
|  | static if (is(PointerTarget!R == struct)) | 
|  | enum usingPut = hasMember!(PointerTarget!R, "put"); | 
|  | else | 
|  | enum usingPut = hasMember!(R, "put"); | 
|  |  | 
|  | static if (usingPut) | 
|  | { | 
|  | static assert(is(typeof(r.put(e))), | 
|  | "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); | 
|  | r.put(e); | 
|  | } | 
|  | else static if (isNarrowString!R && is(const(E) == const(typeof(r[0])))) | 
|  | { | 
|  | // one character, we can put it | 
|  | r[0] = e; | 
|  | r = r[1 .. $]; | 
|  | } | 
|  | else static if (isNarrowString!R && isNarrowString!E && is(typeof(r[] = e))) | 
|  | { | 
|  | // slice assign. Note that this is a duplicate from put, but because | 
|  | // putChar uses doPut exclusively, we have to copy it here. | 
|  | immutable len = e.length; | 
|  | r[0 .. len] = e; | 
|  | r = r[len .. $]; | 
|  | } | 
|  | else static if (isInputRange!R) | 
|  | { | 
|  | static assert(is(typeof(r.front = e)), | 
|  | "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); | 
|  | r.front = e; | 
|  | r.popFront(); | 
|  | } | 
|  | else static if (is(typeof(r(e)))) | 
|  | { | 
|  | r(e); | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(false, | 
|  | "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); | 
|  | } | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(!isNativeOutputRange!(int,     int)); | 
|  | static assert( isNativeOutputRange!(int[],   int)); | 
|  | static assert(!isNativeOutputRange!(int[][], int)); | 
|  |  | 
|  | static assert(!isNativeOutputRange!(int,     int[])); | 
|  | static assert(!isNativeOutputRange!(int[],   int[])); | 
|  | static assert( isNativeOutputRange!(int[][], int[])); | 
|  |  | 
|  | static assert(!isNativeOutputRange!(int,     int[][])); | 
|  | static assert(!isNativeOutputRange!(int[],   int[][])); | 
|  | static assert(!isNativeOutputRange!(int[][], int[][])); | 
|  |  | 
|  | static assert(!isNativeOutputRange!(int[4],   int)); | 
|  | static assert( isNativeOutputRange!(int[4][], int)); //Scary! | 
|  | static assert( isNativeOutputRange!(int[4][], int[4])); | 
|  |  | 
|  | static assert( isNativeOutputRange!( char[],   char)); | 
|  | static assert(!isNativeOutputRange!( char[],  dchar)); | 
|  | static assert( isNativeOutputRange!(dchar[],   char)); | 
|  | static assert( isNativeOutputRange!(dchar[],  dchar)); | 
|  |  | 
|  | } | 
|  |  | 
|  | /++ | 
|  | Outputs `e` to `r`. 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` into `r`, using the | 
|  | correct primitive: `r.put(e)` if `R` defines `put`, $(D r.front = e) | 
|  | if `r` is an input range (followed by `r.popFront()`), or `r(e)` | 
|  | otherwise. | 
|  |  | 
|  | $(BOOKTABLE , | 
|  | $(TR | 
|  | $(TH Code Snippet) | 
|  | $(TH Scenario) | 
|  | ) | 
|  | $(TR | 
|  | $(TD `r.doPut(e);`) | 
|  | $(TD `R` specifically accepts an `E`.) | 
|  | ) | 
|  | $(TR | 
|  | $(TD $(D r.doPut([ e ]);)) | 
|  | $(TD `R` specifically accepts an `E[]`.) | 
|  | ) | 
|  | $(TR | 
|  | $(TD `r.putChar(e);`) | 
|  | $(TD `R` accepts some form of string or character. put will | 
|  | transcode the character `e` accordingly.) | 
|  | ) | 
|  | $(TR | 
|  | $(TD $(D for (; !e.empty; e.popFront()) put(r, e.front);)) | 
|  | $(TD Copying range `E` into `R`.) | 
|  | ) | 
|  | ) | 
|  |  | 
|  | Tip: `put` should $(I not) be used "UFCS-style", e.g. `r.put(e)`. | 
|  | Doing this may call `R.put` directly, by-passing any transformation | 
|  | feature provided by `Range.put`. $(D put(r, e)) is prefered. | 
|  | +/ | 
|  | void put(R, E)(ref R r, E e) | 
|  | { | 
|  | //First level: simply straight up put. | 
|  | static if (is(typeof(doPut(r, e)))) | 
|  | { | 
|  | doPut(r, e); | 
|  | } | 
|  | //Optional optimization block for straight up array to array copy. | 
|  | else static if (isDynamicArray!R && | 
|  | !isAutodecodableString!R && | 
|  | isDynamicArray!E && | 
|  | is(typeof(r[] = e[]))) | 
|  | { | 
|  | immutable len = e.length; | 
|  | r[0 .. len] = e[]; | 
|  | r = r[len .. $]; | 
|  | } | 
|  | //Accepts E[] ? | 
|  | else static if (is(typeof(doPut(r, [e]))) && !isDynamicArray!R) | 
|  | { | 
|  | if (__ctfe) | 
|  | { | 
|  | E[1] arr = [e]; | 
|  | doPut(r, arr[]); | 
|  | } | 
|  | else | 
|  | doPut(r, (ref e) @trusted { return (&e)[0 .. 1]; }(e)); | 
|  | } | 
|  | //special case for char to string. | 
|  | else static if (isSomeChar!E && is(typeof(putChar(r, e)))) | 
|  | { | 
|  | putChar(r, e); | 
|  | } | 
|  | //Extract each element from the range | 
|  | //We can use "put" here, so we can recursively test a RoR of E. | 
|  | else static if (isInputRange!E && is(typeof(put(r, e.front)))) | 
|  | { | 
|  | //Special optimization: If E is a narrow string, and r accepts characters no-wider than the string's | 
|  | //Then simply feed the characters 1 by 1. | 
|  | static if (isAutodecodableString!E && !isAggregateType!E && ( | 
|  | (is(E : const  char[]) && is(typeof(doPut(r,  char.max))) && !is(typeof(doPut(r, dchar.max))) && | 
|  | !is(typeof(doPut(r, wchar.max)))) || | 
|  | (is(E : const wchar[]) && is(typeof(doPut(r, wchar.max))) && !is(typeof(doPut(r, dchar.max)))) ) ) | 
|  | { | 
|  | foreach (c; e) | 
|  | doPut(r, c); | 
|  | } | 
|  | else | 
|  | { | 
|  | for (; !e.empty; e.popFront()) | 
|  | put(r, e.front); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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. | 
|  | */ | 
|  | @safe pure unittest | 
|  | { | 
|  | 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"); | 
|  | assert(a.data == "Hello"); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * `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`. | 
|  | */ | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | int[] a = [1, 2, 3], b = [10, 20]; | 
|  | auto c = a; | 
|  | put(a, b); | 
|  | assert(c == [10, 20, 3]); | 
|  | // at this point, a was advanced twice, so it only contains | 
|  | // its last element while c represents the whole array | 
|  | assert(a == [3]); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 $(REF UTFException, std, utf). | 
|  | */ | 
|  | @safe pure unittest | 
|  | { | 
|  | // 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); | 
|  | assert(s1 == "Hello, World!"); | 
|  | } | 
|  |  | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | // same thing, just using same character width. | 
|  | char[] s1 = new char[13]; | 
|  | auto r1 = s1; | 
|  | put(r1, "Hello, World!"); | 
|  | assert(s1 == "Hello, World!"); | 
|  | } | 
|  |  | 
|  |  | 
|  | @safe pure nothrow @nogc unittest | 
|  | { | 
|  | static struct R() { void put(scope const(char)[]) {} } | 
|  | R!() r; | 
|  | put(r, 'a'); | 
|  | } | 
|  |  | 
|  | //Helper function to handle chars as quickly and as elegantly as possible | 
|  | //Assumes r.put(e)/r(e) has already been tested | 
|  | private void putChar(R, E)(ref R r, E e) | 
|  | if (isSomeChar!E) | 
|  | { | 
|  | // https://issues.dlang.org/show_bug.cgi?id=9186: Can't use (E[]).init | 
|  | enum csCond = is(typeof(doPut(r, (){ ref const( char)[] cstringInit(); return cstringInit(); }()))); | 
|  | enum wsCond = is(typeof(doPut(r, (){ ref const(wchar)[] wstringInit(); return wstringInit(); }()))); | 
|  | enum dsCond = is(typeof(doPut(r, (){ ref const(dchar)[] dstringInit(); return dstringInit(); }()))); | 
|  |  | 
|  | //Use "max" to avoid static type demotion | 
|  | enum ccCond = is(typeof(doPut(r,  char.max))); | 
|  | enum wcCond = is(typeof(doPut(r, wchar.max))); | 
|  | //enum dcCond = is(typeof(doPut(r, dchar.max))); | 
|  |  | 
|  | //Fast transform a narrow char into a wider string | 
|  | static if ((wsCond && E.sizeof < wchar.sizeof) || (dsCond && E.sizeof < dchar.sizeof)) | 
|  | { | 
|  | enum w = wsCond && E.sizeof < wchar.sizeof; | 
|  | Select!(w, wchar, dchar) c = e; | 
|  | typeof(c)[1] arr = [c]; | 
|  | doPut(r, arr[]); | 
|  | } | 
|  | //Encode a wide char into a narrower string | 
|  | else static if (wsCond || csCond) | 
|  | { | 
|  | import std.utf : encode; | 
|  | /+static+/ Select!(wsCond, wchar[2], char[4]) buf; //static prevents purity. | 
|  | doPut(r, buf[0 .. encode(buf, e)]); | 
|  | } | 
|  | //Slowly encode a wide char into a series of narrower chars | 
|  | else static if (wcCond || ccCond) | 
|  | { | 
|  | import std.encoding : encode; | 
|  | alias C = Select!(wcCond, wchar, char); | 
|  | encode!(C, R)(e, r); | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); | 
|  | } | 
|  | } | 
|  |  | 
|  | pure @safe unittest | 
|  | { | 
|  | auto f = delegate (const(char)[]) {}; | 
|  | putChar(f, cast(dchar)'a'); | 
|  | } | 
|  |  | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | static struct R() { void put(scope const(char)[]) {} } | 
|  | R!() r; | 
|  | putChar(r, 'a'); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | struct A {} | 
|  | static assert(!isInputRange!(A)); | 
|  | struct B | 
|  | { | 
|  | void put(int) {} | 
|  | } | 
|  | B b; | 
|  | put(b, 5); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | int[] a = new int[10]; | 
|  | int b; | 
|  | static assert(isInputRange!(typeof(a))); | 
|  | put(a, b); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | void myprint(scope const(char)[] s) { } | 
|  | auto r = &myprint; | 
|  | put(r, 'a'); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | int[] a = new int[10]; | 
|  | static assert(!__traits(compiles, put(a, 1.0L))); | 
|  | put(a, 1); | 
|  | assert(a.length == 9); | 
|  | /* | 
|  | * a[0] = 65;       // OK | 
|  | * a[0] = 'A';      // OK | 
|  | * a[0] = "ABC"[0]; // OK | 
|  | * put(a, "ABC");   // OK | 
|  | */ | 
|  | put(a, "ABC"); | 
|  | assert(a.length == 6); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | char[] a = new char[10]; | 
|  | static assert(!__traits(compiles, put(a, 1.0L))); | 
|  | static assert(!__traits(compiles, put(a, 1))); | 
|  | //char[] is now an output range for char, wchar, dchar, and ranges of such. | 
|  | static assert(__traits(compiles, putChar(a, 'a'))); | 
|  | static assert(__traits(compiles, put(a, wchar('a')))); | 
|  | static assert(__traits(compiles, put(a, dchar('a')))); | 
|  | static assert(__traits(compiles, put(a, "ABC"))); | 
|  | static assert(__traits(compiles, put(a, "ABC"w))); | 
|  | static assert(__traits(compiles, put(a, "ABC"d))); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | // attempt putting into narrow strings by transcoding | 
|  | char[] a = new char[10]; | 
|  | auto b = a; | 
|  | put(a, "ABC"w); | 
|  | assert(b[0 .. 3] == "ABC"); | 
|  | assert(a.length == 7); | 
|  |  | 
|  | a = b; // reset | 
|  | put(a, 'λ'); | 
|  | assert(b[0 .. 2] == "λ"); | 
|  | assert(a.length == 8); | 
|  |  | 
|  | a = b; // reset | 
|  | put(a, "ABC"d); | 
|  | assert(b[0 .. 3] == "ABC"); | 
|  | assert(a.length == 7); | 
|  |  | 
|  | a = b; // reset | 
|  | put(a, '𐐷'); | 
|  | assert(b[0 .. 4] == "𐐷"); | 
|  | assert(a.length == 6); | 
|  |  | 
|  | wchar[] aw = new wchar[10]; | 
|  | auto bw = aw; | 
|  | put(aw, "ABC"); | 
|  | assert(bw[0 .. 3] == "ABC"w); | 
|  | assert(aw.length == 7); | 
|  |  | 
|  | aw = bw; // reset | 
|  | put(aw, 'λ'); | 
|  | assert(bw[0 .. 1] == "λ"w); | 
|  | assert(aw.length == 9); | 
|  |  | 
|  | aw = bw; // reset | 
|  | put(aw, "ABC"d); | 
|  | assert(bw[0 .. 3] == "ABC"w); | 
|  | assert(aw.length == 7); | 
|  |  | 
|  | aw = bw; // reset | 
|  | put(aw, '𐐷'); | 
|  | assert(bw[0 .. 2] == "𐐷"w); | 
|  | assert(aw.length == 8); | 
|  |  | 
|  | aw = bw; // reset | 
|  | put(aw, "𐐷"); // try transcoding from char[] | 
|  | assert(bw[0 .. 2] == "𐐷"w); | 
|  | assert(aw.length == 8); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | int[][] a = new int[][10]; | 
|  | int[]   b = new int[10]; | 
|  | int     c; | 
|  | put(b, c); | 
|  | assert(b.length == 9); | 
|  | put(a, b); | 
|  | assert(a.length == 9); | 
|  | static assert(!__traits(compiles, put(a, c))); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | int[][] a = new int[][](3); | 
|  | int[]   b = [1]; | 
|  | auto aa = a; | 
|  | put(aa, b); | 
|  | assert(aa == [[], []]); | 
|  | assert(a  == [[1], [], []]); | 
|  | int[][3] c = [2]; | 
|  | aa = a; | 
|  | put(aa, c[]); | 
|  | assert(aa.empty); | 
|  | assert(a == [[2], [2], [2]]); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | // Test fix for bug 7476. | 
|  | struct LockingTextWriter | 
|  | { | 
|  | void put(dchar c){} | 
|  | } | 
|  | struct RetroResult | 
|  | { | 
|  | bool end = false; | 
|  | @property bool empty() const { return end; } | 
|  | @property dchar front(){ return 'a'; } | 
|  | void popFront(){ end = true; } | 
|  | } | 
|  | LockingTextWriter w; | 
|  | RetroResult re; | 
|  | put(w, re); | 
|  | } | 
|  |  | 
|  | @system unittest | 
|  | { | 
|  | import std.conv : to; | 
|  | import std.meta : AliasSeq; | 
|  | import std.typecons : tuple; | 
|  |  | 
|  | static struct PutC(C) | 
|  | { | 
|  | string result; | 
|  | void put(const(C) c) { result ~= to!string((&c)[0 .. 1]); } | 
|  | } | 
|  | static struct PutS(C) | 
|  | { | 
|  | string result; | 
|  | void put(const(C)[] s) { result ~= to!string(s); } | 
|  | } | 
|  | static struct PutSS(C) | 
|  | { | 
|  | string result; | 
|  | void put(const(C)[][] ss) | 
|  | { | 
|  | foreach (s; ss) | 
|  | result ~= to!string(s); | 
|  | } | 
|  | } | 
|  |  | 
|  | PutS!char p; | 
|  | putChar(p, cast(dchar)'a'); | 
|  |  | 
|  | //Source Char | 
|  | static foreach (SC; AliasSeq!(char, wchar, dchar)) | 
|  | {{ | 
|  | SC ch = 'I'; | 
|  | dchar dh = '♥'; | 
|  | immutable(SC)[] s = "日本語!"; | 
|  | immutable(SC)[][] ss = ["日本語", "が", "好き", "ですか", "?"]; | 
|  |  | 
|  | //Target Char | 
|  | static foreach (TC; AliasSeq!(char, wchar, dchar)) | 
|  | { | 
|  | //Testing PutC and PutS | 
|  | static foreach (Type; AliasSeq!(PutC!TC, PutS!TC)) | 
|  | {{ | 
|  | Type type; | 
|  | auto sink = new Type(); | 
|  |  | 
|  | //Testing put and sink | 
|  | foreach (value ; tuple(type, sink)) | 
|  | { | 
|  | put(value, ch); | 
|  | assert(value.result == "I"); | 
|  | put(value, dh); | 
|  | assert(value.result == "I♥"); | 
|  | put(value, s); | 
|  | assert(value.result == "I♥日本語!"); | 
|  | put(value, ss); | 
|  | assert(value.result == "I♥日本語!日本語が好きですか?"); | 
|  | } | 
|  | }} | 
|  | } | 
|  | }} | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static struct CharRange | 
|  | { | 
|  | char c; | 
|  | enum empty = false; | 
|  | void popFront(){} | 
|  | ref char front() return @property | 
|  | { | 
|  | return c; | 
|  | } | 
|  | } | 
|  | CharRange c; | 
|  | put(c, cast(dchar)'H'); | 
|  | put(c, "hello"d); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=9823 | 
|  | @system unittest | 
|  | { | 
|  | const(char)[] r; | 
|  | void delegate(const(char)[]) dg = (s) { r = s; }; | 
|  | put(dg, ["ABC"]); | 
|  | assert(r == "ABC"); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=10571 | 
|  | @safe unittest | 
|  | { | 
|  | import std.format.write : formattedWrite; | 
|  | string buf; | 
|  | formattedWrite((scope const(char)[] s) { buf ~= s; }, "%s", "hello"); | 
|  | assert(buf == "hello"); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.format.write : formattedWrite; | 
|  | import std.meta : AliasSeq; | 
|  | struct PutC(C) | 
|  | { | 
|  | void put(C){} | 
|  | } | 
|  | struct PutS(C) | 
|  | { | 
|  | void put(const(C)[]){} | 
|  | } | 
|  | struct CallC(C) | 
|  | { | 
|  | void opCall(C){} | 
|  | } | 
|  | struct CallS(C) | 
|  | { | 
|  | void opCall(const(C)[]){} | 
|  | } | 
|  | struct FrontC(C) | 
|  | { | 
|  | enum empty = false; | 
|  | auto front()@property{return C.init;} | 
|  | void front(C)@property{} | 
|  | void popFront(){} | 
|  | } | 
|  | struct FrontS(C) | 
|  | { | 
|  | enum empty = false; | 
|  | auto front()@property{return C[].init;} | 
|  | void front(const(C)[])@property{} | 
|  | void popFront(){} | 
|  | } | 
|  | void foo() | 
|  | { | 
|  | static foreach (C; AliasSeq!(char, wchar, dchar)) | 
|  | {{ | 
|  | formattedWrite((C c){},        "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | formattedWrite((const(C)[]){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | formattedWrite(PutC!C(),       "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | formattedWrite(PutS!C(),       "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | CallC!C callC; | 
|  | CallS!C callS; | 
|  | formattedWrite(callC,          "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | formattedWrite(callS,          "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | formattedWrite(FrontC!C(),     "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | formattedWrite(FrontS!C(),     "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | }} | 
|  | formattedWrite((dchar[]).init,     "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); | 
|  | } | 
|  | } | 
|  |  | 
|  | /+ | 
|  | Returns `true` if `R` is a native output range for elements of type | 
|  | `E`. An output range is defined functionally as a range that | 
|  | supports the operation $(D doPut(r, e)) as defined above. if $(D doPut(r, e)) | 
|  | is valid, then `put(r,e)` will have the same behavior. | 
|  |  | 
|  | The two guarantees isNativeOutputRange gives over the larger `isOutputRange` | 
|  | are: | 
|  | 1: `e` is $(B exactly) what will be placed (not `[e]`, for example). | 
|  | 2: if `E` is a non $(empty) `InputRange`, then placing `e` is | 
|  | guaranteed to not overflow the range. | 
|  | +/ | 
|  | package(std) enum bool isNativeOutputRange(R, E) = | 
|  | is(typeof(doPut(lvalueOf!R, lvalueOf!E))); | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | int[] r = new int[](4); | 
|  | static assert(isInputRange!(int[])); | 
|  | static assert( isNativeOutputRange!(int[], int)); | 
|  | static assert(!isNativeOutputRange!(int[], int[])); | 
|  | static assert( isOutputRange!(int[], int[])); | 
|  |  | 
|  | if (!r.empty) | 
|  | put(r, 1); //guaranteed to succeed | 
|  | if (!r.empty) | 
|  | put(r, [1, 2]); //May actually error out. | 
|  | } | 
|  |  | 
|  | /++ | 
|  | Returns `true` if `R` is an output range for elements of type | 
|  | `E`. An output range is defined functionally as a range that | 
|  | supports the operation $(D put(r, e)) as defined above. | 
|  |  | 
|  | See_Also: | 
|  | The header of $(MREF std,range) for tutorials on ranges. | 
|  | +/ | 
|  | enum bool isOutputRange(R, E) = | 
|  | is(typeof(put(lvalueOf!R, lvalueOf!E))); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.array; | 
|  | import std.stdio : writeln; | 
|  |  | 
|  | auto app = appender!string(); | 
|  | string s; | 
|  | static assert( isOutputRange!(Appender!string, string)); | 
|  | static assert( isOutputRange!(Appender!string*, string)); | 
|  | static assert(!isOutputRange!(Appender!string, int)); | 
|  | static assert( isOutputRange!(wchar[], wchar)); | 
|  | static assert( isOutputRange!(dchar[], char)); | 
|  | static assert( isOutputRange!(dchar[], string)); | 
|  | static assert( isOutputRange!(dchar[], wstring)); | 
|  | static assert( isOutputRange!(dchar[], dstring)); | 
|  |  | 
|  | static assert(!isOutputRange!(const(int)[], int)); | 
|  | static assert(!isOutputRange!(inout(int)[], int)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` is a forward range. A forward range is an | 
|  | input range `r` that can save "checkpoints" by saving `r.save` | 
|  | to another value of type `R`. Notable examples of input ranges that | 
|  | are $(I 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` | 
|  | and `r2` 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 with `save` and using it later. | 
|  |  | 
|  | `save` behaves in many ways like a copy constructor, and its | 
|  | implementation typically is done using copy construction. | 
|  |  | 
|  | The existence of a copy constructor, however, does not imply | 
|  | the range is a forward range. For example, a range that reads | 
|  | from a TTY consumes its input and cannot save its place and | 
|  | read it again, and so cannot be a forward range and cannot | 
|  | have a `save` function. | 
|  |  | 
|  |  | 
|  | See_Also: | 
|  | The header of $(MREF std,range) for tutorials on ranges. | 
|  |  | 
|  | Params: | 
|  | R = type to be tested | 
|  | E = if present, the elements of the range must be | 
|  | $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) | 
|  | to this type | 
|  |  | 
|  | Returns: | 
|  | `true` if R is a forward range (possibly with element type `E`), `false` if not | 
|  | */ | 
|  | enum bool isForwardRange(R) = isInputRange!R | 
|  | && is(typeof((R r) { return r.save; } (R.init)) == R); | 
|  |  | 
|  | /// ditto | 
|  | enum bool isForwardRange(R, E) = | 
|  | .isForwardRange!R && isQualifierConvertible!(ElementType!R, E); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | static assert(!isForwardRange!(int)); | 
|  | static assert( isForwardRange!(int[])); | 
|  | static assert( isForwardRange!(inout(int)[])); | 
|  |  | 
|  | static assert( isForwardRange!(int[], const int)); | 
|  | static assert(!isForwardRange!(int[], immutable int)); | 
|  |  | 
|  | static assert(!isForwardRange!(const(int)[], int)); | 
|  | static assert( isForwardRange!(const(int)[], const int)); | 
|  | static assert(!isForwardRange!(const(int)[], immutable int)); | 
|  |  | 
|  | static assert(!isForwardRange!(immutable(int)[], int)); | 
|  | static assert( isForwardRange!(immutable(int)[], const int)); | 
|  | static assert( isForwardRange!(immutable(int)[], immutable int)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | // BUG 14544 | 
|  | struct R14544 | 
|  | { | 
|  | int front() { return 0;} | 
|  | void popFront() {} | 
|  | bool empty() { return false; } | 
|  | R14544 save() {return this;} | 
|  | } | 
|  |  | 
|  | static assert( isForwardRange!R14544 ); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` is a bidirectional range. A bidirectional | 
|  | range is a forward range that also offers the primitives `back` and | 
|  | `popBack`. 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 | 
|  | type `R`): | 
|  |  | 
|  | $(UL $(LI `r.back` returns (possibly a reference to) the last | 
|  | element in the range. Calling `r.back` is allowed only if calling | 
|  | `r.empty` has, or would have, returned `false`.)) | 
|  |  | 
|  | See_Also: | 
|  | The header of $(MREF std,range) for tutorials on ranges. | 
|  |  | 
|  | Params: | 
|  | R = type to be tested | 
|  | E = if present, the elements of the range must be | 
|  | $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) | 
|  | to this type | 
|  |  | 
|  | Returns: | 
|  | `true` if R is a bidirectional range (possibly with element type `E`), `false` if not | 
|  | */ | 
|  | enum bool isBidirectionalRange(R) = isForwardRange!R | 
|  | && is(typeof((R r) => r.popBack)) | 
|  | && (is(typeof((return ref R r) => r.back)) || is(typeof(ref (return ref R r) => r.back))) | 
|  | && is(typeof(R.init.back.init) == ElementType!R); | 
|  |  | 
|  | /// ditto | 
|  | enum bool isBidirectionalRange(R, E) = | 
|  | .isBidirectionalRange!R && isQualifierConvertible!(ElementType!R, E); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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 | 
|  |  | 
|  | // Checking the element type | 
|  | static assert( isBidirectionalRange!(int[], const int)); | 
|  | static assert(!isBidirectionalRange!(int[], immutable int)); | 
|  |  | 
|  | static assert(!isBidirectionalRange!(const(int)[], int)); | 
|  | static assert( isBidirectionalRange!(const(int)[], const int)); | 
|  | static assert(!isBidirectionalRange!(const(int)[], immutable int)); | 
|  |  | 
|  | static assert(!isBidirectionalRange!(immutable(int)[], int)); | 
|  | static assert( isBidirectionalRange!(immutable(int)[], const int)); | 
|  | static assert( isBidirectionalRange!(immutable(int)[], immutable int)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | struct A {} | 
|  | struct B | 
|  | { | 
|  | void popFront(); | 
|  | @property bool empty(); | 
|  | @property int front(); | 
|  | } | 
|  | struct C | 
|  | { | 
|  | @property bool empty(); | 
|  | @property C save(); | 
|  | void popFront(); | 
|  | @property int front(); | 
|  | void popBack(); | 
|  | @property int back(); | 
|  | } | 
|  | static assert(!isBidirectionalRange!(A)); | 
|  | static assert(!isBidirectionalRange!(B)); | 
|  | static assert( isBidirectionalRange!(C)); | 
|  | static assert( isBidirectionalRange!(int[])); | 
|  | static assert( isBidirectionalRange!(char[])); | 
|  | static assert( isBidirectionalRange!(inout(int)[])); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` is a random-access range. A random-access | 
|  | range is a bidirectional range that also offers the primitive $(D | 
|  | opIndex), OR an infinite forward range that offers `opIndex`. In | 
|  | either case, the range must either offer `length` 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 | 
|  | type `R`): $(UL $(LI `r.opIndex(n)` returns a reference to the | 
|  | `n`th element in the range.)) | 
|  |  | 
|  | Although `char[]` and `wchar[]` (as well as their qualified | 
|  | versions including `string` and `wstring`) are arrays, $(D | 
|  | isRandomAccessRange) yields `false` 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 $(MREF std,range) for tutorials on ranges. | 
|  |  | 
|  | Params: | 
|  | R = type to be tested | 
|  | E = if present, the elements of the range must be | 
|  | $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) | 
|  | to this type | 
|  |  | 
|  | Returns: | 
|  | `true` if R is a random-access range (possibly with element type `E`), `false` if not | 
|  | */ | 
|  | enum bool isRandomAccessRange(R) = | 
|  | is(typeof(lvalueOf!R[1]) == ElementType!R) | 
|  | && !(isAutodecodableString!R && !isAggregateType!R) | 
|  | && isForwardRange!R | 
|  | && (isBidirectionalRange!R || isInfinite!R) | 
|  | && (hasLength!R || isInfinite!R) | 
|  | && (isInfinite!R || !is(typeof(lvalueOf!R[$ - 1])) | 
|  | || is(typeof(lvalueOf!R[$ - 1]) == ElementType!R)); | 
|  |  | 
|  | /// ditto | 
|  | enum bool isRandomAccessRange(R, E) = | 
|  | .isRandomAccessRange!R && isQualifierConvertible!(ElementType!R, E); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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]))); | 
|  | } | 
|  |  | 
|  | // Checking the element type | 
|  | static assert( isRandomAccessRange!(int[], const int)); | 
|  | static assert(!isRandomAccessRange!(int[], immutable int)); | 
|  |  | 
|  | static assert(!isRandomAccessRange!(const(int)[], int)); | 
|  | static assert( isRandomAccessRange!(const(int)[], const int)); | 
|  | static assert(!isRandomAccessRange!(const(int)[], immutable int)); | 
|  |  | 
|  | static assert(!isRandomAccessRange!(immutable(int)[], int)); | 
|  | static assert( isRandomAccessRange!(immutable(int)[], const int)); | 
|  | static assert( isRandomAccessRange!(immutable(int)[], immutable int)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | struct A {} | 
|  | struct B | 
|  | { | 
|  | void popFront(); | 
|  | @property bool empty(); | 
|  | @property int front(); | 
|  | } | 
|  | struct C | 
|  | { | 
|  | void popFront(); | 
|  | @property bool empty(); | 
|  | @property int front(); | 
|  | void popBack(); | 
|  | @property int back(); | 
|  | } | 
|  | struct D | 
|  | { | 
|  | @property bool empty(); | 
|  | @property D save(); | 
|  | @property int front(); | 
|  | void popFront(); | 
|  | @property int back(); | 
|  | void popBack(); | 
|  | ref int opIndex(uint); | 
|  | @property size_t length(); | 
|  | alias opDollar = length; | 
|  | //int opSlice(uint, uint); | 
|  | } | 
|  | struct E | 
|  | { | 
|  | bool empty(); | 
|  | E save(); | 
|  | int front(); | 
|  | void popFront(); | 
|  | int back(); | 
|  | void popBack(); | 
|  | ref int opIndex(uint); | 
|  | size_t length(); | 
|  | alias opDollar = length; | 
|  | //int opSlice(uint, uint); | 
|  | } | 
|  | static assert(!isRandomAccessRange!(A)); | 
|  | static assert(!isRandomAccessRange!(B)); | 
|  | static assert(!isRandomAccessRange!(C)); | 
|  | static assert( isRandomAccessRange!(D)); | 
|  | static assert( isRandomAccessRange!(E)); | 
|  | static assert( isRandomAccessRange!(int[])); | 
|  | static assert( isRandomAccessRange!(inout(int)[])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | // Test fix for bug 6935. | 
|  | struct R | 
|  | { | 
|  | @disable this(); | 
|  |  | 
|  | @property bool empty() const { return false; } | 
|  | @property int front() const { return 0; } | 
|  | void popFront() {} | 
|  |  | 
|  | @property R save() { return this; } | 
|  |  | 
|  | @property int back() const { return 0; } | 
|  | void popBack(){} | 
|  |  | 
|  | int opIndex(size_t n) const { return 0; } | 
|  | @property size_t length() const { return 0; } | 
|  | alias opDollar = length; | 
|  |  | 
|  | void put(int e){  } | 
|  | } | 
|  | static assert(isInputRange!R); | 
|  | static assert(isForwardRange!R); | 
|  | static assert(isBidirectionalRange!R); | 
|  | static assert(isRandomAccessRange!R); | 
|  | static assert(isOutputRange!(R, int)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` iff `R` is an input range that supports the | 
|  | `moveFront` primitive, as well as `moveBack` and `moveAt` 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 functions `moveFront` | 
|  | 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)); | 
|  | ---- | 
|  | */ | 
|  | enum bool hasMobileElements(R) = | 
|  | isInputRange!R | 
|  | && is(typeof(moveFront(lvalueOf!R)) == ElementType!R) | 
|  | && (!isBidirectionalRange!R | 
|  | || is(typeof(moveBack(lvalueOf!R)) == ElementType!R)) | 
|  | && (!isRandomAccessRange!R | 
|  | || is(typeof(moveAt(lvalueOf!R, 0)) == ElementType!R)); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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[])); | 
|  | } | 
|  |  | 
|  | /** | 
|  | The element type of `R`. `R` does not have to be a range. The | 
|  | element type is determined as the type yielded by `r.front` for an | 
|  | object `r` of type `R`. For example, `ElementType!(T[])` is | 
|  | `T` if `T[]` isn't a narrow string; if it is, the element type is | 
|  | `dchar`. If `R` doesn't have `front`, `ElementType!R` is | 
|  | `void`. | 
|  | */ | 
|  | template ElementType(R) | 
|  | { | 
|  | static if (is(typeof(R.init.front.init) T)) | 
|  | alias ElementType = T; | 
|  | else | 
|  | alias ElementType = void; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(is(ElementType!(byte[]) == byte)); | 
|  | static assert(is(ElementType!(wchar[]) == dchar)); // rvalue | 
|  | static assert(is(ElementType!(wstring) == dchar)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | enum XYZ : string { a = "foo" } | 
|  | auto x = XYZ.a.front; | 
|  | immutable char[3] a = "abc"; | 
|  | int[] i; | 
|  | void[] buf; | 
|  | static assert(is(ElementType!(XYZ) == dchar)); | 
|  | static assert(is(ElementType!(typeof(a)) == dchar)); | 
|  | static assert(is(ElementType!(typeof(i)) == int)); | 
|  | static assert(is(ElementType!(typeof(buf)) == void)); | 
|  | static assert(is(ElementType!(inout(int)[]) == inout(int))); | 
|  | static assert(is(ElementType!(inout(int[])) == inout(int))); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(is(ElementType!(int[5]) == int)); | 
|  | static assert(is(ElementType!(int[0]) == int)); | 
|  | static assert(is(ElementType!(char[5]) == dchar)); | 
|  | static assert(is(ElementType!(char[0]) == dchar)); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=11336 | 
|  | @safe unittest | 
|  | { | 
|  | static struct S | 
|  | { | 
|  | this(this) @disable; | 
|  | } | 
|  | static assert(is(ElementType!(S[]) == S)); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=11401 | 
|  | @safe unittest | 
|  | { | 
|  | // ElementType should also work for non-@propety 'front' | 
|  | struct E { ushort id; } | 
|  | struct R | 
|  | { | 
|  | E front() { return E.init; } | 
|  | } | 
|  | static assert(is(ElementType!R == E)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | The encoding element type of `R`. For narrow strings (`char[]`, | 
|  | `wchar[]` and their qualified variants including `string` and | 
|  | `wstring`), `ElementEncodingType` is the character type of the | 
|  | string. For all other types, `ElementEncodingType` is the same as | 
|  | `ElementType`. | 
|  | */ | 
|  | template ElementEncodingType(R) | 
|  | { | 
|  | static if (is(StringTypeOf!R) && is(R : E[], E)) | 
|  | alias ElementEncodingType = E; | 
|  | else | 
|  | alias ElementEncodingType = ElementType!R; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(is(ElementEncodingType!(wchar[]) == wchar)); | 
|  | static assert(is(ElementEncodingType!(dchar[]) == dchar)); | 
|  | static assert(is(ElementEncodingType!(string)  == immutable(char))); | 
|  | static assert(is(ElementEncodingType!(dstring) == immutable(dchar))); | 
|  | static assert(is(ElementEncodingType!(int[])  == int)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | enum XYZ : string { a = "foo" } | 
|  | auto x = XYZ.a.front; | 
|  | immutable char[3] a = "abc"; | 
|  | int[] i; | 
|  | void[] buf; | 
|  | static assert(is(ElementType!(XYZ) : dchar)); | 
|  | static assert(is(ElementEncodingType!(char[]) == char)); | 
|  | static assert(is(ElementEncodingType!(string) == immutable char)); | 
|  | static assert(is(ElementType!(typeof(a)) : dchar)); | 
|  | static assert(is(ElementType!(typeof(i)) == int)); | 
|  | static assert(is(ElementEncodingType!(typeof(i)) == int)); | 
|  | static assert(is(ElementType!(typeof(buf)) : void)); | 
|  |  | 
|  | static assert(is(ElementEncodingType!(inout char[]) : inout(char))); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(is(ElementEncodingType!(int[5]) == int)); | 
|  | static assert(is(ElementEncodingType!(int[0]) == int)); | 
|  | static assert(is(ElementEncodingType!(char[5]) == char)); | 
|  | static assert(is(ElementEncodingType!(char[0]) == char)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` 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); | 
|  | ---- | 
|  | */ | 
|  | template hasSwappableElements(R) | 
|  | { | 
|  | import std.algorithm.mutation : swap; | 
|  | enum bool hasSwappableElements = isInputRange!R | 
|  | && is(typeof((ref R r) => swap(r.front, r.front))) | 
|  | && (!isBidirectionalRange!R | 
|  | || is(typeof((ref R r) => swap(r.back, r.front)))) | 
|  | && (!isRandomAccessRange!R | 
|  | || is(typeof((ref R r) => swap(r[0], r.front)))); | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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[])); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` 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; | 
|  | ---- | 
|  | */ | 
|  | enum bool hasAssignableElements(R) = isInputRange!R | 
|  | && is(typeof(lvalueOf!R.front = lvalueOf!R.front)) | 
|  | && (!isBidirectionalRange!R | 
|  | || is(typeof(lvalueOf!R.back = lvalueOf!R.back))) | 
|  | && (!isRandomAccessRange!R | 
|  | || is(typeof(lvalueOf!R[0] = lvalueOf!R.front))); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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[])); | 
|  | } | 
|  |  | 
|  | /** | 
|  | 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]); | 
|  | ---- | 
|  | */ | 
|  | enum bool hasLvalueElements(R) = isInputRange!R | 
|  | && is(typeof(isLvalue(lvalueOf!R.front))) | 
|  | && (!isBidirectionalRange!R | 
|  | || is(typeof(isLvalue(lvalueOf!R.back)))) | 
|  | && (!isRandomAccessRange!R | 
|  | || is(typeof(isLvalue(lvalueOf!R[0])))); | 
|  |  | 
|  | /* Compile successfully if argument of type T is an lvalue | 
|  | */ | 
|  | private void isLvalue(T)(T) | 
|  | if (0); | 
|  |  | 
|  | private void isLvalue(T)(ref T) | 
|  | if (1); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | import std.range : iota, chain; | 
|  |  | 
|  | static assert( hasLvalueElements!(int[])); | 
|  | static assert( hasLvalueElements!(const(int)[])); | 
|  | static assert( hasLvalueElements!(inout(int)[])); | 
|  | static assert( hasLvalueElements!(immutable(int)[])); | 
|  | static assert(!hasLvalueElements!(typeof(iota(3)))); | 
|  |  | 
|  | static assert(!hasLvalueElements!( string)); | 
|  | static assert( hasLvalueElements!(dstring)); | 
|  | static assert(!hasLvalueElements!( char[])); | 
|  | static assert( hasLvalueElements!(dchar[])); | 
|  |  | 
|  | auto c = chain([1, 2, 3], [4, 5, 6]); | 
|  | static assert( hasLvalueElements!(typeof(c))); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | // bugfix 6336 | 
|  | struct S { immutable int value; } | 
|  | static assert( isInputRange!(S[])); | 
|  | static assert( hasLvalueElements!(S[])); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Yields `true` if `R` has a `length` member that returns a value of `size_t` | 
|  | type. `R` does not have to be a range. If `R` is a range, algorithms in the | 
|  | standard library are only guaranteed to support `length` with type `size_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 a `length` property, `hasLength` yields `false` 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, use $(REF representation, std, string) or $(REF byCodeUnit, std, utf). | 
|  | */ | 
|  | template hasLength(R) | 
|  | { | 
|  | static if (is(typeof(((R* r) => r.length)(null)) Length)) | 
|  | enum bool hasLength = is(Length == size_t) && | 
|  | !(isAutodecodableString!R && !isAggregateType!R); | 
|  | else | 
|  | enum bool hasLength = false; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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)); | 
|  | } | 
|  |  | 
|  | // test combinations which are invalid on some platforms | 
|  | @safe unittest | 
|  | { | 
|  | struct A { ulong length; } | 
|  | struct B { @property uint length() { return 0; } } | 
|  |  | 
|  | static if (is(size_t == uint)) | 
|  | { | 
|  | static assert(!hasLength!(A)); | 
|  | static assert(hasLength!(B)); | 
|  | } | 
|  | else static if (is(size_t == ulong)) | 
|  | { | 
|  | static assert(hasLength!(A)); | 
|  | static assert(!hasLength!(B)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // test combinations which are invalid on all platforms | 
|  | @safe unittest | 
|  | { | 
|  | struct A { long length; } | 
|  | struct B { int length; } | 
|  | struct C { ubyte length; } | 
|  | struct D { char length; } | 
|  | static assert(!hasLength!(A)); | 
|  | static assert(!hasLength!(B)); | 
|  | static assert(!hasLength!(C)); | 
|  | static assert(!hasLength!(D)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` is an infinite input range. An | 
|  | infinite input range is an input range that has a statically-defined | 
|  | enumerated member called `empty` that is always `false`, | 
|  | for example: | 
|  |  | 
|  | ---- | 
|  | struct MyInfiniteRange | 
|  | { | 
|  | enum bool empty = false; | 
|  | ... | 
|  | } | 
|  | ---- | 
|  | */ | 
|  |  | 
|  | template isInfinite(R) | 
|  | { | 
|  | static if (isInputRange!R && __traits(compiles, { enum e = R.empty; })) | 
|  | enum bool isInfinite = !R.empty; | 
|  | else | 
|  | enum bool isInfinite = false; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | import std.range : Repeat; | 
|  | static assert(!isInfinite!(int[])); | 
|  | static assert( isInfinite!(Repeat!(int))); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Returns `true` if `R` 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 defines `opDollar`, then it must support | 
|  | subtraction. | 
|  |  | 
|  | For infinite ranges, when $(I not) using `opDollar`, the result of `opSlice` | 
|  | may be a forward range of any type. However, when using `opDollar`, the result | 
|  | of `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) | 
|  | { | 
|  | static assert(isForwardRange!(typeof(r[1 .. 2]))); | 
|  | })); | 
|  | ---- | 
|  | */ | 
|  | enum bool hasSlicing(R) = 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) | 
|  | { | 
|  | static assert(isForwardRange!(typeof(r[1 .. 2]))); | 
|  | })); | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=24348 | 
|  | @safe unittest | 
|  | { | 
|  | static struct Slice | 
|  | { | 
|  | size_t length; | 
|  | bool empty() => length == 0; | 
|  | int front() => 0; | 
|  | void popFront() { --length; } | 
|  | Slice save() => this; | 
|  | } | 
|  |  | 
|  | static struct InfZeros | 
|  | { | 
|  | enum empty = false; | 
|  | int front() => 0; | 
|  | void popFront() {} | 
|  | InfZeros save() => this; | 
|  |  | 
|  | Slice opIndex(size_t[2] bounds) | 
|  | { | 
|  | size_t i = bounds[0], j = bounds[1]; | 
|  | size_t length = i <= j ? j - i : 0; | 
|  | return Slice(length); | 
|  | } | 
|  |  | 
|  | size_t[2] opSlice(size_t dim : 0)(size_t i, size_t j) => [i, j]; | 
|  | } | 
|  |  | 
|  | static assert(hasSlicing!InfZeros); | 
|  | } | 
|  |  | 
|  | /** | 
|  | This is a best-effort implementation of `length` for any kind of | 
|  | range. | 
|  |  | 
|  | If `hasLength!Range`, simply returns `range.length` without | 
|  | checking `upTo` (when specified). | 
|  |  | 
|  | Otherwise, walks the range through its length and returns the number | 
|  | of elements seen. Performes $(BIGOH n) evaluations of `range.empty` | 
|  | and `range.popFront()`, where `n` is the effective length of $(D | 
|  | range). | 
|  |  | 
|  | The `upTo` 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 parameter `upTo` is specified, stops if $(D | 
|  | upTo) steps have been taken and returns `upTo`. | 
|  |  | 
|  | Infinite ranges are compatible, provided the parameter `upTo` is | 
|  | specified, in which case the implementation simply returns upTo. | 
|  | */ | 
|  | auto walkLength(Range)(Range range) | 
|  | if (isInputRange!Range && !isInfinite!Range) | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | return range.length; | 
|  | else | 
|  | { | 
|  | size_t result; | 
|  | static if (autodecodeStrings && isNarrowString!Range) | 
|  | { | 
|  | import std.utf : codeUnitLimit; | 
|  | result = range.length; | 
|  | foreach (const i, const c; range) | 
|  | { | 
|  | if (c >= codeUnitLimit!Range) | 
|  | { | 
|  | result = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | range = range[result .. $]; | 
|  | } | 
|  | for ( ; !range.empty ; range.popFront() ) | 
|  | ++result; | 
|  | return result; | 
|  | } | 
|  | } | 
|  | /// ditto | 
|  | auto walkLength(Range)(Range range, const size_t upTo) | 
|  | if (isInputRange!Range) | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | return range.length; | 
|  | else static if (isInfinite!Range) | 
|  | return upTo; | 
|  | else | 
|  | { | 
|  | size_t result; | 
|  | static if (autodecodeStrings && isNarrowString!Range) | 
|  | { | 
|  | import std.utf : codeUnitLimit; | 
|  | result = upTo > range.length ? range.length : upTo; | 
|  | foreach (const i, const c; range[0 .. result]) | 
|  | { | 
|  | if (c >= codeUnitLimit!Range) | 
|  | { | 
|  | result = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | range = range[result .. $]; | 
|  | } | 
|  | for ( ; result < upTo && !range.empty ; range.popFront() ) | 
|  | ++result; | 
|  | return result; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | import std.range : iota; | 
|  |  | 
|  | assert(10.iota.walkLength == 10); | 
|  | // iota has a length function, and therefore the | 
|  | // doesn't have to be walked, and the upTo | 
|  | // parameter is ignored | 
|  | assert(10.iota.walkLength(5) == 10); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration : filter; | 
|  | import std.range : recurrence, take; | 
|  |  | 
|  | //hasLength Range | 
|  | int[] a = [ 1, 2, 3 ]; | 
|  | assert(walkLength(a) == 3); | 
|  | assert(walkLength(a, 0) == 3); | 
|  | assert(walkLength(a, 2) == 3); | 
|  | assert(walkLength(a, 4) == 3); | 
|  |  | 
|  | //Forward Range | 
|  | auto b = filter!"true"([1, 2, 3, 4]); | 
|  | assert(b.walkLength() == 4); | 
|  | assert(b.walkLength(0) == 0); | 
|  | assert(b.walkLength(2) == 2); | 
|  | assert(b.walkLength(4) == 4); | 
|  | assert(b.walkLength(6) == 4); | 
|  |  | 
|  | //Infinite Range | 
|  | auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); | 
|  | assert(!__traits(compiles, fibs.walkLength())); | 
|  | assert(fibs.take(10).walkLength() == 10); | 
|  | assert(fibs.walkLength(55) == 55); | 
|  | } | 
|  |  | 
|  | /** | 
|  | `popFrontN` eagerly advances `r` itself (not a copy) up to `n` times | 
|  | (by calling `r.popFront`). `popFrontN` takes `r` by `ref`, | 
|  | so it mutates the original range. Completes in $(BIGOH 1) steps for ranges | 
|  | that support slicing and have length. | 
|  | Completes in $(BIGOH n) time for all other ranges. | 
|  |  | 
|  | `popBackN` behaves the same as `popFrontN` 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 than `n` if | 
|  | `r` did not have at least `n` elements. | 
|  |  | 
|  | See_Also: $(REF drop, std, range), $(REF dropBack, std, range) | 
|  | */ | 
|  | size_t popFrontN(Range)(ref Range r, size_t n) | 
|  | if (isInputRange!Range) | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | { | 
|  | n = cast(size_t) (n < r.length ? n : r.length); | 
|  | } | 
|  |  | 
|  | static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) | 
|  | { | 
|  | r = r[n .. $]; | 
|  | } | 
|  | else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. | 
|  | { | 
|  | r = r[n .. r.length]; | 
|  | } | 
|  | else | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | { | 
|  | foreach (i; 0 .. n) | 
|  | r.popFront(); | 
|  | } | 
|  | else | 
|  | { | 
|  | foreach (i; 0 .. n) | 
|  | { | 
|  | if (r.empty) return i; | 
|  | r.popFront(); | 
|  | } | 
|  | } | 
|  | } | 
|  | return n; | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | size_t popBackN(Range)(ref Range r, size_t n) | 
|  | if (isBidirectionalRange!Range) | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | { | 
|  | n = cast(size_t) (n < r.length ? n : r.length); | 
|  | } | 
|  |  | 
|  | static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) | 
|  | { | 
|  | r = r[0 .. $ - n]; | 
|  | } | 
|  | else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. | 
|  | { | 
|  | r = r[0 .. r.length - n]; | 
|  | } | 
|  | else | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | { | 
|  | foreach (i; 0 .. n) | 
|  | r.popBack(); | 
|  | } | 
|  | else | 
|  | { | 
|  | foreach (i; 0 .. n) | 
|  | { | 
|  | if (r.empty) return i; | 
|  | r.popBack(); | 
|  | } | 
|  | } | 
|  | } | 
|  | return n; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | int[] a = [ 1, 2, 3, 4, 5 ]; | 
|  | a.popFrontN(2); | 
|  | assert(a == [ 3, 4, 5 ]); | 
|  | a.popFrontN(7); | 
|  | assert(a == [ ]); | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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])); | 
|  | assert(r == 2); | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | int[] a = [ 1, 2, 3, 4, 5 ]; | 
|  | a.popBackN(2); | 
|  | assert(a == [ 1, 2, 3 ]); | 
|  | a.popBackN(7); | 
|  | assert(a == [ ]); | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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])); | 
|  | assert(r == 2); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Eagerly advances `r` itself (not a copy) exactly `n` times (by | 
|  | calling `r.popFront`). `popFrontExactly` takes `r` by `ref`, | 
|  | so it mutates the original range. Completes in $(BIGOH 1) steps for ranges | 
|  | that support slicing, and have either length or are infinite. | 
|  | Completes in $(BIGOH n) time for all other ranges. | 
|  |  | 
|  | Note: Unlike $(LREF popFrontN), `popFrontExactly` will assume that the | 
|  | range holds at least `n` elements. This makes `popFrontExactly` | 
|  | faster than `popFrontN`, but it also means that if `range` does | 
|  | not contain at least `n` elements, it will attempt to call `popFront` | 
|  | on an empty range, which is undefined behavior. So, only use | 
|  | `popFrontExactly` when it is guaranteed that `range` holds at least | 
|  | `n` elements. | 
|  |  | 
|  | `popBackExactly` will behave the same but instead removes elements from | 
|  | the back of the (bidirectional) range instead of the front. | 
|  |  | 
|  | See_Also: $(REF dropExactly, std, range), $(REF dropBackExactly, std, range) | 
|  | */ | 
|  | void popFrontExactly(Range)(ref Range r, size_t n) | 
|  | if (isInputRange!Range) | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | assert(n <= r.length, "range is smaller than amount of items to pop"); | 
|  |  | 
|  | static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) | 
|  | r = r[n .. $]; | 
|  | else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. | 
|  | r = r[n .. r.length]; | 
|  | else | 
|  | foreach (i; 0 .. n) | 
|  | r.popFront(); | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | void popBackExactly(Range)(ref Range r, size_t n) | 
|  | if (isBidirectionalRange!Range) | 
|  | { | 
|  | static if (hasLength!Range) | 
|  | assert(n <= r.length, "range is smaller than amount of items to pop"); | 
|  |  | 
|  | static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) | 
|  | r = r[0 .. $ - n]; | 
|  | else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. | 
|  | r = r[0 .. r.length - n]; | 
|  | else | 
|  | foreach (i; 0 .. n) | 
|  | r.popBack(); | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.algorithm.iteration : filterBidirectional; | 
|  |  | 
|  | auto a = [1, 2, 3]; | 
|  | a.popFrontExactly(1); | 
|  | assert(a == [2, 3]); | 
|  | a.popBackExactly(1); | 
|  | assert(a == [2]); | 
|  |  | 
|  | string s = "日本語"; | 
|  | s.popFrontExactly(1); | 
|  | assert(s == "本語"); | 
|  | s.popBackExactly(1); | 
|  | assert(s == "本"); | 
|  |  | 
|  | auto bd = filterBidirectional!"true"([1, 2, 3]); | 
|  | bd.popFrontExactly(1); | 
|  | assert(bd.equal([2, 3])); | 
|  | bd.popBackExactly(1); | 
|  | assert(bd.equal([2])); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Moves the front of `r` 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. | 
|  | */ | 
|  | ElementType!R moveFront(R)(R r) | 
|  | { | 
|  | static if (is(typeof(&r.moveFront))) | 
|  | { | 
|  | return r.moveFront(); | 
|  | } | 
|  | else static if (!hasElaborateCopyConstructor!(ElementType!R)) | 
|  | { | 
|  | return r.front; | 
|  | } | 
|  | else static if (is(typeof(&(r.front())) == ElementType!R*)) | 
|  | { | 
|  | import std.algorithm.mutation : move; | 
|  | return move(r.front); | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(0, | 
|  | "Cannot move front of a range with a postblit and an rvalue front."); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | auto a = [ 1, 2, 3 ]; | 
|  | assert(moveFront(a) == 1); | 
|  | assert(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 | 
|  | assert(moveFront(r) == 43); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | struct R | 
|  | { | 
|  | @property ref int front() { static int x = 42; return x; } | 
|  | this(this){} | 
|  | } | 
|  | R r; | 
|  | assert(moveFront(r) == 42); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Moves the back of `r` out and returns it. Leaves `r.back` in a | 
|  | destroyable state that does not allocate any resources (usually equal | 
|  | to its `.init` value). | 
|  | */ | 
|  | ElementType!R moveBack(R)(R r) | 
|  | { | 
|  | static if (is(typeof(&r.moveBack))) | 
|  | { | 
|  | return r.moveBack(); | 
|  | } | 
|  | else static if (!hasElaborateCopyConstructor!(ElementType!R)) | 
|  | { | 
|  | return r.back; | 
|  | } | 
|  | else static if (is(typeof(&(r.back())) == ElementType!R*)) | 
|  | { | 
|  | import std.algorithm.mutation : move; | 
|  | return move(r.back); | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(0, | 
|  | "Cannot move back of a range with a postblit and an rvalue back."); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | 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); | 
|  | assert(x == 5); | 
|  | } | 
|  |  | 
|  | /** | 
|  | Moves element at index `i` of `r` out and returns it. Leaves $(D | 
|  | r[i]) in a destroyable state that does not allocate any resources | 
|  | (usually equal to its `.init` value). | 
|  | */ | 
|  | ElementType!R moveAt(R)(R r, size_t i) | 
|  | { | 
|  | static if (is(typeof(&r.moveAt))) | 
|  | { | 
|  | return r.moveAt(i); | 
|  | } | 
|  | else static if (!hasElaborateCopyConstructor!(ElementType!(R))) | 
|  | { | 
|  | return r[i]; | 
|  | } | 
|  | else static if (is(typeof(&r[i]) == ElementType!R*)) | 
|  | { | 
|  | import std.algorithm.mutation : move; | 
|  | return move(r[i]); | 
|  | } | 
|  | else | 
|  | { | 
|  | static assert(0, | 
|  | "Cannot move element of a range with a postblit and rvalue elements."); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe unittest | 
|  | { | 
|  | auto a = [1,2,3,4]; | 
|  | foreach (idx, it; a) | 
|  | { | 
|  | assert(it == moveAt(a, idx)); | 
|  | } | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.internal.test.dummyrange; | 
|  |  | 
|  | foreach (DummyType; AllDummyRanges) | 
|  | { | 
|  | auto d = DummyType.init; | 
|  | assert(moveFront(d) == 1); | 
|  |  | 
|  | static if (isBidirectionalRange!DummyType) | 
|  | { | 
|  | assert(moveBack(d) == 10); | 
|  | } | 
|  |  | 
|  | static if (isRandomAccessRange!DummyType) | 
|  | { | 
|  | assert(moveAt(d, 2) == 3); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | Implements the range interface primitive `empty` for types that | 
|  | obey $(LREF hasLength) 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 to `empty(a)`. | 
|  | */ | 
|  | @property bool empty(T)(auto ref scope T a) | 
|  | if (is(typeof(a.length) : size_t)) | 
|  | { | 
|  | return !a.length; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | auto a = [ 1, 2, 3 ]; | 
|  | assert(!a.empty); | 
|  | assert(a[3 .. $].empty); | 
|  |  | 
|  | int[string] b; | 
|  | assert(b.empty); | 
|  | b["zero"] = 0; | 
|  | assert(!b.empty); | 
|  | } | 
|  |  | 
|  | /** | 
|  | 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 to `save(array)`. The function does not duplicate the | 
|  | content of the array, it simply returns its argument. | 
|  | */ | 
|  | @property inout(T)[] save(T)(return scope inout(T)[] a) @safe pure nothrow @nogc | 
|  | { | 
|  | return a; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | auto a = [ 1, 2, 3 ]; | 
|  | auto b = a.save; | 
|  | assert(b is a); | 
|  | } | 
|  |  | 
|  | /** | 
|  | 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 to `popFront(array)`. For $(GLOSSARY narrow strings), | 
|  | `popFront` automatically advances to the next $(GLOSSARY code | 
|  | point). | 
|  | */ | 
|  | void popFront(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc | 
|  | if (!isAutodecodableString!(T[]) && !is(T[] == void[])) | 
|  | { | 
|  | assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof); | 
|  | a = a[1 .. $]; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | auto a = [ 1, 2, 3 ]; | 
|  | a.popFront(); | 
|  | assert(a == [ 2, 3 ]); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(!is(typeof({          int[4] a; popFront(a); }))); | 
|  | static assert(!is(typeof({ immutable int[] a; popFront(a); }))); | 
|  | static assert(!is(typeof({          void[] a; popFront(a); }))); | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | void popFront(C)(scope ref inout(C)[] str) @trusted pure nothrow | 
|  | if (isAutodecodableString!(C[])) | 
|  | { | 
|  | import std.algorithm.comparison : min; | 
|  |  | 
|  | assert(str.length, "Attempting to popFront() past the end of an array of " ~ C.stringof); | 
|  |  | 
|  | static if (is(immutable C == immutable char)) | 
|  | { | 
|  | static immutable ubyte[] charWidthTab = [ | 
|  | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
|  | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
|  | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 
|  | 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 | 
|  | ]; | 
|  |  | 
|  | immutable c = str[0]; | 
|  | immutable charWidth = c < 192 ? 1 : charWidthTab.ptr[c - 192]; | 
|  | str = str.ptr[min(str.length, charWidth) .. str.length]; | 
|  | } | 
|  | else static if (is(immutable C == immutable wchar)) | 
|  | { | 
|  | immutable u = str[0]; | 
|  | immutable seqLen = 1 + (u >= 0xD800 && u <= 0xDBFF); | 
|  | str = str.ptr[min(seqLen, str.length) .. str.length]; | 
|  | } | 
|  | else static assert(0, "Bad template constraint."); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.meta : AliasSeq; | 
|  |  | 
|  | static foreach (S; AliasSeq!(string, wstring, dstring)) | 
|  | {{ | 
|  | S s = "\xC2\xA9hello"; | 
|  | s.popFront(); | 
|  | assert(s == "hello"); | 
|  |  | 
|  | S str = "hello\U00010143\u0100\U00010143"; | 
|  | foreach (dchar c; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143']) | 
|  | { | 
|  | assert(str.front == c); | 
|  | str.popFront(); | 
|  | } | 
|  | assert(str.empty); | 
|  |  | 
|  | static assert(!is(typeof({          immutable S a; popFront(a); }))); | 
|  | static assert(!is(typeof({ typeof(S.init[0])[4] a; popFront(a); }))); | 
|  | }} | 
|  |  | 
|  | C[] _eatString(C)(C[] str) | 
|  | { | 
|  | while (!str.empty) | 
|  | str.popFront(); | 
|  |  | 
|  | return str; | 
|  | } | 
|  | enum checkCTFE = _eatString("ウェブサイト@La_Verité.com"); | 
|  | static assert(checkCTFE.empty); | 
|  | enum checkCTFEW = _eatString("ウェブサイト@La_Verité.com"w); | 
|  | static assert(checkCTFEW.empty); | 
|  | } | 
|  |  | 
|  | // https://issues.dlang.org/show_bug.cgi?id=16090 | 
|  | @safe unittest | 
|  | { | 
|  | string s = "\u00E4"; | 
|  | assert(s.length == 2); | 
|  | s = s[0 .. 1]; | 
|  | assert(s.length == 1); | 
|  | s.popFront; | 
|  | assert(s.empty); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | wstring s = "\U00010000"; | 
|  | assert(s.length == 2); | 
|  | s = s[0 .. 1]; | 
|  | assert(s.length == 1); | 
|  | s.popFront; | 
|  | assert(s.empty); | 
|  | } | 
|  |  | 
|  | /** | 
|  | 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 to `popBack(array)`. For $(GLOSSARY narrow strings), $(D | 
|  | popFront) automatically eliminates the last $(GLOSSARY code point). | 
|  | */ | 
|  | void popBack(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc | 
|  | if (!isAutodecodableString!(T[]) && !is(T[] == void[])) | 
|  | { | 
|  | assert(a.length); | 
|  | a = a[0 .. $ - 1]; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | auto a = [ 1, 2, 3 ]; | 
|  | a.popBack(); | 
|  | assert(a == [ 1, 2 ]); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | static assert(!is(typeof({ immutable int[] a; popBack(a); }))); | 
|  | static assert(!is(typeof({          int[4] a; popBack(a); }))); | 
|  | static assert(!is(typeof({          void[] a; popBack(a); }))); | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | void popBack(T)(scope ref inout(T)[] a) @safe pure | 
|  | if (isAutodecodableString!(T[])) | 
|  | { | 
|  | import std.utf : strideBack; | 
|  | assert(a.length, "Attempting to popBack() past the front of an array of " ~ T.stringof); | 
|  | a = a[0 .. $ - strideBack(a, $)]; | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.meta : AliasSeq; | 
|  |  | 
|  | static foreach (S; AliasSeq!(string, wstring, dstring)) | 
|  | {{ | 
|  | S s = "hello\xE2\x89\xA0"; | 
|  | s.popBack(); | 
|  | assert(s == "hello"); | 
|  | S s3 = "\xE2\x89\xA0"; | 
|  | auto c = s3.back; | 
|  | assert(c == cast(dchar)'\u2260'); | 
|  | s3.popBack(); | 
|  | assert(s3 == ""); | 
|  |  | 
|  | S str = "\U00010143\u0100\U00010143hello"; | 
|  | foreach (dchar ch; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143']) | 
|  | { | 
|  | assert(str.back == ch); | 
|  | str.popBack(); | 
|  | } | 
|  | assert(str.empty); | 
|  |  | 
|  | static assert(!is(typeof({          immutable S a; popBack(a); }))); | 
|  | static assert(!is(typeof({ typeof(S.init[0])[4] a; popBack(a); }))); | 
|  | }} | 
|  | } | 
|  |  | 
|  | /** | 
|  | EXPERIMENTAL: to try out removing autodecoding, set the version | 
|  | `NoAutodecodeStrings`. Most things are expected to fail with this version | 
|  | currently. | 
|  | */ | 
|  | version (NoAutodecodeStrings) | 
|  | { | 
|  | enum autodecodeStrings = false; | 
|  | } | 
|  | else | 
|  | { | 
|  | /// | 
|  | enum autodecodeStrings = true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | 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 to `front(array)`. For $(GLOSSARY narrow strings), $(D | 
|  | front) automatically returns the first $(GLOSSARY code point) as _a $(D | 
|  | dchar). | 
|  | */ | 
|  | @property ref inout(T) front(T)(return scope inout(T)[] a) @safe pure nothrow @nogc | 
|  | if (!isAutodecodableString!(T[]) && !is(T[] == void[])) | 
|  | { | 
|  | assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); | 
|  | return a[0]; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | int[] a = [ 1, 2, 3 ]; | 
|  | assert(a.front == 1); | 
|  | } | 
|  |  | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | auto a = [ 1, 2 ]; | 
|  | a.front = 4; | 
|  | assert(a.front == 4); | 
|  | assert(a == [ 4, 2 ]); | 
|  |  | 
|  | immutable b = [ 1, 2 ]; | 
|  | assert(b.front == 1); | 
|  |  | 
|  | int[2] c = [ 1, 2 ]; | 
|  | assert(c.front == 1); | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | @property dchar front(T)(scope const(T)[] a) @safe pure | 
|  | if (isAutodecodableString!(T[])) | 
|  | { | 
|  | import std.utf : decode; | 
|  | assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); | 
|  | size_t i = 0; | 
|  | return decode(a, i); | 
|  | } | 
|  |  | 
|  | /** | 
|  | 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 to `back(array)`. For $(GLOSSARY narrow strings), $(D | 
|  | back) automatically returns the last $(GLOSSARY code point) as _a $(D | 
|  | dchar). | 
|  | */ | 
|  | @property ref inout(T) back(T)(return scope inout(T)[] a) @safe pure nothrow @nogc | 
|  | if (!isAutodecodableString!(T[]) && !is(T[] == void[])) | 
|  | { | 
|  | assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); | 
|  | return a[$ - 1]; | 
|  | } | 
|  |  | 
|  | /// | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | int[] a = [ 1, 2, 3 ]; | 
|  | assert(a.back == 3); | 
|  | a.back += 4; | 
|  | assert(a.back == 7); | 
|  | } | 
|  |  | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | immutable b = [ 1, 2, 3 ]; | 
|  | assert(b.back == 3); | 
|  |  | 
|  | int[3] c = [ 1, 2, 3 ]; | 
|  | assert(c.back == 3); | 
|  | } | 
|  |  | 
|  | /// ditto | 
|  | // Specialization for strings | 
|  | @property dchar back(T)(scope const(T)[] a) @safe pure | 
|  | if (isAutodecodableString!(T[])) | 
|  | { | 
|  | import std.utf : decode, strideBack; | 
|  | assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); | 
|  | size_t i = a.length - strideBack(a, a.length); | 
|  | return decode(a, i); | 
|  | } | 
|  |  | 
|  | /* | 
|  | Implements `length` for a range by forwarding it to `member`. | 
|  | */ | 
|  | package(std) mixin template ImplementLength(alias member) | 
|  | { | 
|  | static if (hasLength!(typeof(member))) | 
|  | { | 
|  | @property auto length() | 
|  | { | 
|  | return member.length; | 
|  | } | 
|  | alias opDollar = length; | 
|  | } | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.meta : AliasSeq; | 
|  |  | 
|  | foreach (alias E; AliasSeq!(noreturn, const(noreturn), immutable(noreturn) )) | 
|  | { | 
|  | alias R = E[]; | 
|  |  | 
|  | static assert(isInputRange!R); | 
|  | static assert(isForwardRange!R); | 
|  | static assert(isBidirectionalRange!R); | 
|  | static assert(isRandomAccessRange!R); | 
|  | } | 
|  |  | 
|  | static assert(isOutputRange!(noreturn[], noreturn)); | 
|  | } |