1/**
2This module is a submodule of $(MREF std, range).
3
4It provides basic range functionality by defining several templates for testing
5whether a given object is a _range, and what kind of _range it is:
6
7$(SCRIPT inhibitQuickIndex = 1;)
8$(BOOKTABLE ,
9    $(TR $(TD $(LREF isInputRange))
10        $(TD Tests if something is an $(I input _range), defined to be
11        something from which one can sequentially read data using the
12        primitives $(D front), $(D popFront), and $(D empty).
13    ))
14    $(TR $(TD $(LREF isOutputRange))
15        $(TD Tests if something is an $(I output _range), defined to be
16        something to which one can sequentially write data using the
17        $(LREF put) primitive.
18    ))
19    $(TR $(TD $(LREF isForwardRange))
20        $(TD Tests if something is a $(I forward _range), defined to be an
21        input _range with the additional capability that one can save one's
22        current position with the $(D save) primitive, thus allowing one to
23        iterate over the same _range multiple times.
24    ))
25    $(TR $(TD $(LREF isBidirectionalRange))
26        $(TD Tests if something is a $(I bidirectional _range), that is, a
27        forward _range that allows reverse traversal using the primitives $(D
28        back) and $(D popBack).
29    ))
30    $(TR $(TD $(LREF isRandomAccessRange))
31        $(TD Tests if something is a $(I random access _range), which is a
32        bidirectional _range that also supports the array subscripting
33        operation via the primitive $(D opIndex).
34    ))
35)
36
37It also provides number of templates that test for various _range capabilities:
38
39$(BOOKTABLE ,
40    $(TR $(TD $(LREF hasMobileElements))
41        $(TD Tests if a given _range's elements can be moved around using the
42        primitives $(D moveFront), $(D moveBack), or $(D moveAt).
43    ))
44    $(TR $(TD $(LREF ElementType))
45        $(TD Returns the element type of a given _range.
46    ))
47    $(TR $(TD $(LREF ElementEncodingType))
48        $(TD Returns the encoding element type of a given _range.
49    ))
50    $(TR $(TD $(LREF hasSwappableElements))
51        $(TD Tests if a _range is a forward _range with swappable elements.
52    ))
53    $(TR $(TD $(LREF hasAssignableElements))
54        $(TD Tests if a _range is a forward _range with mutable elements.
55    ))
56    $(TR $(TD $(LREF hasLvalueElements))
57        $(TD Tests if a _range is a forward _range with elements that can be
58        passed by reference and have their address taken.
59    ))
60    $(TR $(TD $(LREF hasLength))
61        $(TD Tests if a given _range has the $(D length) attribute.
62    ))
63    $(TR $(TD $(LREF isInfinite))
64        $(TD Tests if a given _range is an $(I infinite _range).
65    ))
66    $(TR $(TD $(LREF hasSlicing))
67        $(TD Tests if a given _range supports the array slicing operation $(D
68        R[x .. y]).
69    ))
70)
71
72Finally, it includes some convenience functions for manipulating ranges:
73
74$(BOOKTABLE ,
75    $(TR $(TD $(LREF popFrontN))
76        $(TD Advances a given _range by up to $(I n) elements.
77    ))
78    $(TR $(TD $(LREF popBackN))
79        $(TD Advances a given bidirectional _range from the right by up to
80        $(I n) elements.
81    ))
82    $(TR $(TD $(LREF popFrontExactly))
83        $(TD Advances a given _range by up exactly $(I n) elements.
84    ))
85    $(TR $(TD $(LREF popBackExactly))
86        $(TD Advances a given bidirectional _range from the right by exactly
87        $(I n) elements.
88    ))
89    $(TR $(TD $(LREF moveFront))
90        $(TD Removes the front element of a _range.
91    ))
92    $(TR $(TD $(LREF moveBack))
93        $(TD Removes the back element of a bidirectional _range.
94    ))
95    $(TR $(TD $(LREF moveAt))
96        $(TD Removes the $(I i)'th element of a random-access _range.
97    ))
98    $(TR $(TD $(LREF walkLength))
99        $(TD Computes the length of any _range in O(n) time.
100    ))
101    $(TR $(TD $(LREF put))
102        $(TD Outputs element $(D e) to a _range.
103    ))
104)
105
106Source: $(PHOBOSSRC std/range/_primitives.d)
107
108License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
109
110Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha,
111and Jonathan M Davis. Credit for some of the ideas in building this module goes
112to $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
113*/
114module std.range.primitives;
115
116import std.traits;
117
118/**
119Returns $(D true) if $(D R) is an input range. An input range must
120define the primitives $(D empty), $(D popFront), and $(D front). The
121following code should compile for any input range.
122
123----
124R r;              // can define a range object
125if (r.empty) {}   // can test for empty
126r.popFront();     // can invoke popFront()
127auto h = r.front; // can get the front of the range of non-void type
128----
129
130The following are rules of input ranges are assumed to hold true in all
131Phobos code. These rules are not checkable at compile-time, so not conforming
132to these rules when writing ranges or range based code will result in
133undefined behavior.
134
135$(UL
136    $(LI `r.empty` returns `false` if and only if there is more data
137    available in the range.)
138    $(LI `r.empty` evaluated multiple times, without calling
139    `r.popFront`, or otherwise mutating the range object or the
140    underlying data, yields the same result for every evaluation.)
141    $(LI `r.front` returns the current element in the range.
142    It may return by value or by reference.)
143    $(LI `r.front` can be legally evaluated if and only if evaluating
144    `r.empty` has, or would have, equaled `false`.)
145    $(LI `r.front` evaluated multiple times, without calling
146    `r.popFront`, or otherwise mutating the range object or the
147    underlying data, yields the same result for every evaluation.)
148    $(LI `r.popFront` advances to the next element in the range.)
149    $(LI `r.popFront` can be called if and only if evaluating `r.empty`
150    has, or would have, equaled `false`.)
151)
152
153Also, note that Phobos code assumes that the primitives `r.front` and
154`r.empty` are $(BIGOH 1) time complexity wise or "cheap" in terms of
155running time. $(BIGOH) statements in the documentation of range functions
156are made with this assumption.
157
158Params:
159    R = type to be tested
160
161Returns:
162    true if R is an InputRange, false if not
163 */
164enum bool isInputRange(R) =
165    is(typeof(R.init) == R)
166    && is(ReturnType!((R r) => r.empty) == bool)
167    && is(typeof((return ref R r) => r.front))
168    && !is(ReturnType!((R r) => r.front) == void)
169    && is(typeof((R r) => r.popFront));
170
171///
172@safe unittest
173{
174    struct A {}
175    struct B
176    {
177        void popFront();
178        @property bool empty();
179        @property int front();
180    }
181    static assert(!isInputRange!A);
182    static assert( isInputRange!B);
183    static assert( isInputRange!(int[]));
184    static assert( isInputRange!(char[]));
185    static assert(!isInputRange!(char[4]));
186    static assert( isInputRange!(inout(int)[]));
187
188    static struct NotDefaultConstructible
189    {
190        @disable this();
191        void popFront();
192        @property bool empty();
193        @property int front();
194    }
195    static assert( isInputRange!NotDefaultConstructible);
196
197    static struct NotDefaultConstructibleOrCopyable
198    {
199        @disable this();
200        @disable this(this);
201        void popFront();
202        @property bool empty();
203        @property int front();
204    }
205    static assert(isInputRange!NotDefaultConstructibleOrCopyable);
206
207    static struct Frontless
208    {
209        void popFront();
210        @property bool empty();
211    }
212    static assert(!isInputRange!Frontless);
213
214    static struct VoidFront
215    {
216        void popFront();
217        @property bool empty();
218        void front();
219    }
220    static assert(!isInputRange!VoidFront);
221}
222
223@safe unittest
224{
225    import std.algorithm.comparison : equal;
226
227    static struct R
228    {
229        static struct Front
230        {
231            R* impl;
232            @property int value() { return impl._front; }
233            alias value this;
234        }
235
236        int _front;
237
238        @property bool empty() { return _front >= 3; }
239        @property auto front() { return Front(&this); }
240        void popFront() { _front++; }
241    }
242    R r;
243
244    static assert(isInputRange!R);
245    assert(r.equal([ 0, 1, 2 ]));
246}
247
248/+
249puts the whole raw element $(D e) into $(D r). doPut will not attempt to
250iterate, slice or transcode $(D e) in any way shape or form. It will $(B only)
251call the correct primitive ($(D r.put(e)),  $(D r.front = e) or
252$(D r(0)) once.
253
254This can be important when $(D e) needs to be placed in $(D r) unchanged.
255Furthermore, it can be useful when working with $(D InputRange)s, as doPut
256guarantees that no more than a single element will be placed.
257+/
258private void doPut(R, E)(ref R r, auto ref E e)
259{
260    static if (is(PointerTarget!R == struct))
261        enum usingPut = hasMember!(PointerTarget!R, "put");
262    else
263        enum usingPut = hasMember!(R, "put");
264
265    static if (usingPut)
266    {
267        static assert(is(typeof(r.put(e))),
268            "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ ".");
269        r.put(e);
270    }
271    else static if (isInputRange!R)
272    {
273        static assert(is(typeof(r.front = e)),
274            "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ ".");
275        r.front = e;
276        r.popFront();
277    }
278    else static if (is(typeof(r(e))))
279    {
280        r(e);
281    }
282    else
283    {
284        static assert(false,
285            "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ ".");
286    }
287}
288
289@safe unittest
290{
291    static assert(!isNativeOutputRange!(int,     int));
292    static assert( isNativeOutputRange!(int[],   int));
293    static assert(!isNativeOutputRange!(int[][], int));
294
295    static assert(!isNativeOutputRange!(int,     int[]));
296    static assert(!isNativeOutputRange!(int[],   int[]));
297    static assert( isNativeOutputRange!(int[][], int[]));
298
299    static assert(!isNativeOutputRange!(int,     int[][]));
300    static assert(!isNativeOutputRange!(int[],   int[][]));
301    static assert(!isNativeOutputRange!(int[][], int[][]));
302
303    static assert(!isNativeOutputRange!(int[4],   int));
304    static assert( isNativeOutputRange!(int[4][], int)); //Scary!
305    static assert( isNativeOutputRange!(int[4][], int[4]));
306
307    static assert(!isNativeOutputRange!( char[],   char));
308    static assert(!isNativeOutputRange!( char[],  dchar));
309    static assert( isNativeOutputRange!(dchar[],   char));
310    static assert( isNativeOutputRange!(dchar[],  dchar));
311
312}
313
314/++
315Outputs $(D e) to $(D r). The exact effect is dependent upon the two
316types. Several cases are accepted, as described below. The code snippets
317are attempted in order, and the first to compile "wins" and gets
318evaluated.
319
320In this table "doPut" is a method that places $(D e) into $(D r), using the
321correct primitive: $(D r.put(e)) if $(D R) defines $(D put), $(D r.front = e)
322if $(D r) is an input range (followed by $(D r.popFront())), or $(D r(e))
323otherwise.
324
325$(BOOKTABLE ,
326    $(TR
327        $(TH Code Snippet)
328        $(TH Scenario)
329    )
330    $(TR
331        $(TD $(D r.doPut(e);))
332        $(TD $(D R) specifically accepts an $(D E).)
333    )
334    $(TR
335        $(TD $(D r.doPut([ e ]);))
336        $(TD $(D R) specifically accepts an $(D E[]).)
337    )
338    $(TR
339        $(TD $(D r.putChar(e);))
340        $(TD $(D R) accepts some form of string or character. put will
341            transcode the character $(D e) accordingly.)
342    )
343    $(TR
344        $(TD $(D for (; !e.empty; e.popFront()) put(r, e.front);))
345        $(TD Copying range $(D E) into $(D R).)
346    )
347)
348
349Tip: $(D put) should $(I not) be used "UFCS-style", e.g. $(D r.put(e)).
350Doing this may call $(D R.put) directly, by-passing any transformation
351feature provided by $(D Range.put). $(D put(r, e)) is prefered.
352 +/
353void put(R, E)(ref R r, E e)
354{
355    //First level: simply straight up put.
356    static if (is(typeof(doPut(r, e))))
357    {
358        doPut(r, e);
359    }
360    //Optional optimization block for straight up array to array copy.
361    else static if (isDynamicArray!R && !isNarrowString!R && isDynamicArray!E && is(typeof(r[] = e[])))
362    {
363        immutable len = e.length;
364        r[0 .. len] = e[];
365        r = r[len .. $];
366    }
367    //Accepts E[] ?
368    else static if (is(typeof(doPut(r, [e]))) && !isDynamicArray!R)
369    {
370        if (__ctfe)
371        {
372            E[1] arr = [e];
373            doPut(r, arr[]);
374        }
375        else
376            doPut(r, (ref e) @trusted { return (&e)[0 .. 1]; }(e));
377    }
378    //special case for char to string.
379    else static if (isSomeChar!E && is(typeof(putChar(r, e))))
380    {
381        putChar(r, e);
382    }
383    //Extract each element from the range
384    //We can use "put" here, so we can recursively test a RoR of E.
385    else static if (isInputRange!E && is(typeof(put(r, e.front))))
386    {
387        //Special optimization: If E is a narrow string, and r accepts characters no-wider than the string's
388        //Then simply feed the characters 1 by 1.
389        static if (isNarrowString!E && (
390            (is(E : const  char[]) && is(typeof(doPut(r,  char.max))) && !is(typeof(doPut(r, dchar.max))) &&
391                !is(typeof(doPut(r, wchar.max)))) ||
392            (is(E : const wchar[]) && is(typeof(doPut(r, wchar.max))) && !is(typeof(doPut(r, dchar.max)))) ) )
393        {
394            foreach (c; e)
395                doPut(r, c);
396        }
397        else
398        {
399            for (; !e.empty; e.popFront())
400                put(r, e.front);
401        }
402    }
403    else
404    {
405        static assert(false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ ".");
406    }
407}
408
409@safe pure nothrow @nogc unittest
410{
411    static struct R() { void put(in char[]) {} }
412    R!() r;
413    put(r, 'a');
414}
415
416//Helper function to handle chars as quickly and as elegantly as possible
417//Assumes r.put(e)/r(e) has already been tested
418private void putChar(R, E)(ref R r, E e)
419if (isSomeChar!E)
420{
421    ////@@@9186@@@: Can't use (E[]).init
422    ref const( char)[] cstringInit();
423    ref const(wchar)[] wstringInit();
424    ref const(dchar)[] dstringInit();
425
426    enum csCond = !isDynamicArray!R && is(typeof(doPut(r, cstringInit())));
427    enum wsCond = !isDynamicArray!R && is(typeof(doPut(r, wstringInit())));
428    enum dsCond = !isDynamicArray!R && is(typeof(doPut(r, dstringInit())));
429
430    //Use "max" to avoid static type demotion
431    enum ccCond = is(typeof(doPut(r,  char.max)));
432    enum wcCond = is(typeof(doPut(r, wchar.max)));
433    //enum dcCond = is(typeof(doPut(r, dchar.max)));
434
435    //Fast transform a narrow char into a wider string
436    static if ((wsCond && E.sizeof < wchar.sizeof) || (dsCond && E.sizeof < dchar.sizeof))
437    {
438        enum w = wsCond && E.sizeof < wchar.sizeof;
439        Select!(w, wchar, dchar) c = e;
440        typeof(c)[1] arr = [c];
441        doPut(r, arr[]);
442    }
443    //Encode a wide char into a narrower string
444    else static if (wsCond || csCond)
445    {
446        import std.utf : encode;
447        /+static+/ Select!(wsCond, wchar[2], char[4]) buf; //static prevents purity.
448        doPut(r, buf[0 .. encode(buf, e)]);
449    }
450    //Slowly encode a wide char into a series of narrower chars
451    else static if (wcCond || ccCond)
452    {
453        import std.encoding : encode;
454        alias C = Select!(wcCond, wchar, char);
455        encode!(C, R)(e, r);
456    }
457    else
458    {
459        static assert(false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ ".");
460    }
461}
462
463pure @safe unittest
464{
465    auto f = delegate (const(char)[]) {};
466    putChar(f, cast(dchar)'a');
467}
468
469
470@safe pure unittest
471{
472    static struct R() { void put(in char[]) {} }
473    R!() r;
474    putChar(r, 'a');
475}
476
477@safe unittest
478{
479    struct A {}
480    static assert(!isInputRange!(A));
481    struct B
482    {
483        void put(int) {}
484    }
485    B b;
486    put(b, 5);
487}
488
489@safe unittest
490{
491    int[] a = [1, 2, 3], b = [10, 20];
492    auto c = a;
493    put(a, b);
494    assert(c == [10, 20, 3]);
495    assert(a == [3]);
496}
497
498@safe unittest
499{
500    int[] a = new int[10];
501    int b;
502    static assert(isInputRange!(typeof(a)));
503    put(a, b);
504}
505
506@safe unittest
507{
508    void myprint(in char[] s) { }
509    auto r = &myprint;
510    put(r, 'a');
511}
512
513@safe unittest
514{
515    int[] a = new int[10];
516    static assert(!__traits(compiles, put(a, 1.0L)));
517    put(a, 1);
518    assert(a.length == 9);
519    /*
520     * a[0] = 65;       // OK
521     * a[0] = 'A';      // OK
522     * a[0] = "ABC"[0]; // OK
523     * put(a, "ABC");   // OK
524     */
525    put(a, "ABC");
526    assert(a.length == 6);
527}
528
529@safe unittest
530{
531    char[] a = new char[10];
532    static assert(!__traits(compiles, put(a, 1.0L)));
533    static assert(!__traits(compiles, put(a, 1)));
534    // char[] is NOT output range.
535    static assert(!__traits(compiles, put(a, 'a')));
536    static assert(!__traits(compiles, put(a, "ABC")));
537}
538
539@safe unittest
540{
541    int[][] a = new int[][10];
542    int[]   b = new int[10];
543    int     c;
544    put(b, c);
545    assert(b.length == 9);
546    put(a, b);
547    assert(a.length == 9);
548    static assert(!__traits(compiles, put(a, c)));
549}
550
551@safe unittest
552{
553    int[][] a = new int[][](3);
554    int[]   b = [1];
555    auto aa = a;
556    put(aa, b);
557    assert(aa == [[], []]);
558    assert(a  == [[1], [], []]);
559    int[][3] c = [2];
560    aa = a;
561    put(aa, c[]);
562    assert(aa.empty);
563    assert(a == [[2], [2], [2]]);
564}
565
566@safe unittest
567{
568    // Test fix for bug 7476.
569    struct LockingTextWriter
570    {
571        void put(dchar c){}
572    }
573    struct RetroResult
574    {
575        bool end = false;
576        @property bool empty() const { return end; }
577        @property dchar front(){ return 'a'; }
578        void popFront(){ end = true; }
579    }
580    LockingTextWriter w;
581    RetroResult r;
582    put(w, r);
583}
584
585@system unittest
586{
587    import std.conv : to;
588    import std.meta : AliasSeq;
589    import std.typecons : tuple;
590
591    static struct PutC(C)
592    {
593        string result;
594        void put(const(C) c) { result ~= to!string((&c)[0 .. 1]); }
595    }
596    static struct PutS(C)
597    {
598        string result;
599        void put(const(C)[] s) { result ~= to!string(s); }
600    }
601    static struct PutSS(C)
602    {
603        string result;
604        void put(const(C)[][] ss)
605        {
606            foreach (s; ss)
607                result ~= to!string(s);
608        }
609    }
610
611    PutS!char p;
612    putChar(p, cast(dchar)'a');
613
614    //Source Char
615    foreach (SC; AliasSeq!(char, wchar, dchar))
616    {
617        SC ch = 'I';
618        dchar dh = '���';
619        immutable(SC)[] s = "������������";
620        immutable(SC)[][] ss = ["���������", "���", "������", "���������", "���"];
621
622        //Target Char
623        foreach (TC; AliasSeq!(char, wchar, dchar))
624        {
625            //Testing PutC and PutS
626            foreach (Type; AliasSeq!(PutC!TC, PutS!TC))
627            (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
628                Type type;
629                auto sink = new Type();
630
631                //Testing put and sink
632                foreach (value ; tuple(type, sink))
633                {
634                    put(value, ch);
635                    assert(value.result == "I");
636                    put(value, dh);
637                    assert(value.result == "I���");
638                    put(value, s);
639                    assert(value.result == "I���������������");
640                    put(value, ss);
641                    assert(value.result == "I���������������������������������������������");
642                }
643            }();
644        }
645    }
646}
647
648@safe unittest
649{
650    static struct CharRange
651    {
652        char c;
653        enum empty = false;
654        void popFront(){}
655        ref char front() return @property
656        {
657            return c;
658        }
659    }
660    CharRange c;
661    put(c, cast(dchar)'H');
662    put(c, "hello"d);
663}
664
665@system unittest
666{
667    // issue 9823
668    const(char)[] r;
669    void delegate(const(char)[]) dg = (s) { r = s; };
670    put(dg, ["ABC"]);
671    assert(r == "ABC");
672}
673
674@safe unittest
675{
676    // issue 10571
677    import std.format;
678    string buf;
679    formattedWrite((in char[] s) { buf ~= s; }, "%s", "hello");
680    assert(buf == "hello");
681}
682
683@safe unittest
684{
685    import std.format;
686    import std.meta : AliasSeq;
687    struct PutC(C)
688    {
689        void put(C){}
690    }
691    struct PutS(C)
692    {
693        void put(const(C)[]){}
694    }
695    struct CallC(C)
696    {
697        void opCall(C){}
698    }
699    struct CallS(C)
700    {
701        void opCall(const(C)[]){}
702    }
703    struct FrontC(C)
704    {
705        enum empty = false;
706        auto front()@property{return C.init;}
707        void front(C)@property{}
708        void popFront(){}
709    }
710    struct FrontS(C)
711    {
712        enum empty = false;
713        auto front()@property{return C[].init;}
714        void front(const(C)[])@property{}
715        void popFront(){}
716    }
717    void foo()
718    {
719        foreach (C; AliasSeq!(char, wchar, dchar))
720        {
721            formattedWrite((C c){},        "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
722            formattedWrite((const(C)[]){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
723            formattedWrite(PutC!C(),       "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
724            formattedWrite(PutS!C(),       "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
725            CallC!C callC;
726            CallS!C callS;
727            formattedWrite(callC,          "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
728            formattedWrite(callS,          "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
729            formattedWrite(FrontC!C(),     "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
730            formattedWrite(FrontS!C(),     "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
731        }
732        formattedWrite((dchar[]).init,     "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d);
733    }
734}
735
736/+
737Returns $(D true) if $(D R) is a native output range for elements of type
738$(D E). An output range is defined functionally as a range that
739supports the operation $(D doPut(r, e)) as defined above. if $(D doPut(r, e))
740is valid, then $(D put(r,e)) will have the same behavior.
741
742The two guarantees isNativeOutputRange gives over the larger $(D isOutputRange)
743are:
7441: $(D e) is $(B exactly) what will be placed (not $(D [e]), for example).
7452: if $(D E) is a non $(empty) $(D InputRange), then placing $(D e) is
746guaranteed to not overflow the range.
747 +/
748package(std) enum bool isNativeOutputRange(R, E) =
749    is(typeof(doPut(lvalueOf!R, lvalueOf!E)));
750
751@safe unittest
752{
753    int[] r = new int[](4);
754    static assert(isInputRange!(int[]));
755    static assert( isNativeOutputRange!(int[], int));
756    static assert(!isNativeOutputRange!(int[], int[]));
757    static assert( isOutputRange!(int[], int[]));
758
759    if (!r.empty)
760        put(r, 1); //guaranteed to succeed
761    if (!r.empty)
762        put(r, [1, 2]); //May actually error out.
763}
764
765/++
766Returns $(D true) if $(D R) is an output range for elements of type
767$(D E). An output range is defined functionally as a range that
768supports the operation $(D put(r, e)) as defined above.
769 +/
770enum bool isOutputRange(R, E) =
771    is(typeof(put(lvalueOf!R, lvalueOf!E)));
772
773///
774@safe unittest
775{
776    void myprint(in char[] s) { }
777    static assert(isOutputRange!(typeof(&myprint), char));
778
779    static assert(!isOutputRange!(char[], char));
780    static assert( isOutputRange!(dchar[], wchar));
781    static assert( isOutputRange!(dchar[], dchar));
782}
783
784@safe unittest
785{
786    import std.array;
787    import std.stdio : writeln;
788
789    auto app = appender!string();
790    string s;
791    static assert( isOutputRange!(Appender!string, string));
792    static assert( isOutputRange!(Appender!string*, string));
793    static assert(!isOutputRange!(Appender!string, int));
794    static assert(!isOutputRange!(wchar[], wchar));
795    static assert( isOutputRange!(dchar[], char));
796    static assert( isOutputRange!(dchar[], string));
797    static assert( isOutputRange!(dchar[], wstring));
798    static assert( isOutputRange!(dchar[], dstring));
799
800    static assert(!isOutputRange!(const(int)[], int));
801    static assert(!isOutputRange!(inout(int)[], int));
802}
803
804
805/**
806Returns $(D true) if $(D R) is a forward range. A forward range is an
807input range $(D r) that can save "checkpoints" by saving $(D r.save)
808to another value of type $(D R). Notable examples of input ranges that
809are $(I not) forward ranges are file/socket ranges; copying such a
810range will not save the position in the stream, and they most likely
811reuse an internal buffer as the entire stream does not sit in
812memory. Subsequently, advancing either the original or the copy will
813advance the stream, so the copies are not independent.
814
815The following code should compile for any forward range.
816
817----
818static assert(isInputRange!R);
819R r1;
820auto s1 = r1.save;
821static assert(is(typeof(s1) == R));
822----
823
824Saving a range is not duplicating it; in the example above, $(D r1)
825and $(D r2) still refer to the same underlying data. They just
826navigate that data independently.
827
828The semantics of a forward range (not checkable during compilation)
829are the same as for an input range, with the additional requirement
830that backtracking must be possible by saving a copy of the range
831object with $(D save) and using it later.
832 */
833enum bool isForwardRange(R) = isInputRange!R
834    && is(ReturnType!((R r) => r.save) == R);
835
836///
837@safe unittest
838{
839    static assert(!isForwardRange!(int));
840    static assert( isForwardRange!(int[]));
841    static assert( isForwardRange!(inout(int)[]));
842}
843
844@safe unittest
845{
846    // BUG 14544
847    struct R14544
848    {
849        int front() { return 0;}
850        void popFront() {}
851        bool empty() { return false; }
852        R14544 save() {return this;}
853    }
854
855    static assert( isForwardRange!R14544 );
856}
857
858/**
859Returns $(D true) if $(D R) is a bidirectional range. A bidirectional
860range is a forward range that also offers the primitives $(D back) and
861$(D popBack). The following code should compile for any bidirectional
862range.
863
864The semantics of a bidirectional range (not checkable during
865compilation) are assumed to be the following ($(D r) is an object of
866type $(D R)):
867
868$(UL $(LI $(D r.back) returns (possibly a reference to) the last
869element in the range. Calling $(D r.back) is allowed only if calling
870$(D r.empty) has, or would have, returned $(D false).))
871 */
872enum bool isBidirectionalRange(R) = isForwardRange!R
873    && is(typeof((R r) => r.popBack))
874    && is(ReturnType!((R r) => r.back) == ElementType!R);
875
876///
877@safe unittest
878{
879    alias R = int[];
880    R r = [0,1];
881    static assert(isForwardRange!R);           // is forward range
882    r.popBack();                               // can invoke popBack
883    auto t = r.back;                           // can get the back of the range
884    auto w = r.front;
885    static assert(is(typeof(t) == typeof(w))); // same type for front and back
886}
887
888@safe unittest
889{
890    struct A {}
891    struct B
892    {
893        void popFront();
894        @property bool empty();
895        @property int front();
896    }
897    struct C
898    {
899        @property bool empty();
900        @property C save();
901        void popFront();
902        @property int front();
903        void popBack();
904        @property int back();
905    }
906    static assert(!isBidirectionalRange!(A));
907    static assert(!isBidirectionalRange!(B));
908    static assert( isBidirectionalRange!(C));
909    static assert( isBidirectionalRange!(int[]));
910    static assert( isBidirectionalRange!(char[]));
911    static assert( isBidirectionalRange!(inout(int)[]));
912}
913
914/**
915Returns $(D true) if $(D R) is a random-access range. A random-access
916range is a bidirectional range that also offers the primitive $(D
917opIndex), OR an infinite forward range that offers $(D opIndex). In
918either case, the range must either offer $(D length) or be
919infinite. The following code should compile for any random-access
920range.
921
922The semantics of a random-access range (not checkable during
923compilation) are assumed to be the following ($(D r) is an object of
924type $(D R)): $(UL $(LI $(D r.opIndex(n)) returns a reference to the
925$(D n)th element in the range.))
926
927Although $(D char[]) and $(D wchar[]) (as well as their qualified
928versions including $(D string) and $(D wstring)) are arrays, $(D
929isRandomAccessRange) yields $(D false) for them because they use
930variable-length encodings (UTF-8 and UTF-16 respectively). These types
931are bidirectional ranges only.
932 */
933enum bool isRandomAccessRange(R) =
934    is(typeof(lvalueOf!R[1]) == ElementType!R)
935    && !isNarrowString!R
936    && isForwardRange!R
937    && (isBidirectionalRange!R || isInfinite!R)
938    && (hasLength!R || isInfinite!R)
939    && (isInfinite!R || !is(typeof(lvalueOf!R[$ - 1]))
940        || is(typeof(lvalueOf!R[$ - 1]) == ElementType!R));
941
942///
943@safe unittest
944{
945    import std.traits : isNarrowString;
946
947    alias R = int[];
948
949    // range is finite and bidirectional or infinite and forward.
950    static assert(isBidirectionalRange!R ||
951                  isForwardRange!R && isInfinite!R);
952
953    R r = [0,1];
954    auto e = r[1]; // can index
955    auto f = r.front;
956    static assert(is(typeof(e) == typeof(f))); // same type for indexed and front
957    static assert(!isNarrowString!R); // narrow strings cannot be indexed as ranges
958    static assert(hasLength!R || isInfinite!R); // must have length or be infinite
959
960    // $ must work as it does with arrays if opIndex works with $
961    static if (is(typeof(r[$])))
962    {
963        static assert(is(typeof(f) == typeof(r[$])));
964
965        // $ - 1 doesn't make sense with infinite ranges but needs to work
966        // with finite ones.
967        static if (!isInfinite!R)
968            static assert(is(typeof(f) == typeof(r[$ - 1])));
969    }
970}
971
972@safe unittest
973{
974    struct A {}
975    struct B
976    {
977        void popFront();
978        @property bool empty();
979        @property int front();
980    }
981    struct C
982    {
983        void popFront();
984        @property bool empty();
985        @property int front();
986        void popBack();
987        @property int back();
988    }
989    struct D
990    {
991        @property bool empty();
992        @property D save();
993        @property int front();
994        void popFront();
995        @property int back();
996        void popBack();
997        ref int opIndex(uint);
998        @property size_t length();
999        alias opDollar = length;
1000        //int opSlice(uint, uint);
1001    }
1002    struct E
1003    {
1004        bool empty();
1005        E save();
1006        int front();
1007        void popFront();
1008        int back();
1009        void popBack();
1010        ref int opIndex(uint);
1011        size_t length();
1012        alias opDollar = length;
1013        //int opSlice(uint, uint);
1014    }
1015    static assert(!isRandomAccessRange!(A));
1016    static assert(!isRandomAccessRange!(B));
1017    static assert(!isRandomAccessRange!(C));
1018    static assert( isRandomAccessRange!(D));
1019    static assert( isRandomAccessRange!(E));
1020    static assert( isRandomAccessRange!(int[]));
1021    static assert( isRandomAccessRange!(inout(int)[]));
1022}
1023
1024@safe unittest
1025{
1026    // Test fix for bug 6935.
1027    struct R
1028    {
1029        @disable this();
1030
1031        @property bool empty() const { return false; }
1032        @property int front() const { return 0; }
1033        void popFront() {}
1034
1035        @property R save() { return this; }
1036
1037        @property int back() const { return 0; }
1038        void popBack(){}
1039
1040        int opIndex(size_t n) const { return 0; }
1041        @property size_t length() const { return 0; }
1042        alias opDollar = length;
1043
1044        void put(int e){  }
1045    }
1046    static assert(isInputRange!R);
1047    static assert(isForwardRange!R);
1048    static assert(isBidirectionalRange!R);
1049    static assert(isRandomAccessRange!R);
1050    static assert(isOutputRange!(R, int));
1051}
1052
1053/**
1054Returns $(D true) iff $(D R) is an input range that supports the
1055$(D moveFront) primitive, as well as $(D moveBack) and $(D moveAt) if it's a
1056bidirectional or random access range. These may be explicitly implemented, or
1057may work via the default behavior of the module level functions $(D moveFront)
1058and friends. The following code should compile for any range
1059with mobile elements.
1060
1061----
1062alias E = ElementType!R;
1063R r;
1064static assert(isInputRange!R);
1065static assert(is(typeof(moveFront(r)) == E));
1066static if (isBidirectionalRange!R)
1067    static assert(is(typeof(moveBack(r)) == E));
1068static if (isRandomAccessRange!R)
1069    static assert(is(typeof(moveAt(r, 0)) == E));
1070----
1071 */
1072enum bool hasMobileElements(R) =
1073    isInputRange!R
1074    && is(typeof(moveFront(lvalueOf!R)) == ElementType!R)
1075    && (!isBidirectionalRange!R
1076        || is(typeof(moveBack(lvalueOf!R)) == ElementType!R))
1077    && (!isRandomAccessRange!R
1078        || is(typeof(moveAt(lvalueOf!R, 0)) == ElementType!R));
1079
1080///
1081@safe unittest
1082{
1083    import std.algorithm.iteration : map;
1084    import std.range : iota, repeat;
1085
1086    static struct HasPostblit
1087    {
1088        this(this) {}
1089    }
1090
1091    auto nonMobile = map!"a"(repeat(HasPostblit.init));
1092    static assert(!hasMobileElements!(typeof(nonMobile)));
1093    static assert( hasMobileElements!(int[]));
1094    static assert( hasMobileElements!(inout(int)[]));
1095    static assert( hasMobileElements!(typeof(iota(1000))));
1096
1097    static assert( hasMobileElements!( string));
1098    static assert( hasMobileElements!(dstring));
1099    static assert( hasMobileElements!( char[]));
1100    static assert( hasMobileElements!(dchar[]));
1101}
1102
1103/**
1104The element type of $(D R). $(D R) does not have to be a range. The
1105element type is determined as the type yielded by $(D r.front) for an
1106object $(D r) of type $(D R). For example, $(D ElementType!(T[])) is
1107$(D T) if $(D T[]) isn't a narrow string; if it is, the element type is
1108$(D dchar). If $(D R) doesn't have $(D front), $(D ElementType!R) is
1109$(D void).
1110 */
1111template ElementType(R)
1112{
1113    static if (is(typeof(R.init.front.init) T))
1114        alias ElementType = T;
1115    else
1116        alias ElementType = void;
1117}
1118
1119///
1120@safe unittest
1121{
1122    import std.range : iota;
1123
1124    // Standard arrays: returns the type of the elements of the array
1125    static assert(is(ElementType!(int[]) == int));
1126
1127    // Accessing .front retrieves the decoded dchar
1128    static assert(is(ElementType!(char[])  == dchar)); // rvalue
1129    static assert(is(ElementType!(dchar[]) == dchar)); // lvalue
1130
1131    // Ditto
1132    static assert(is(ElementType!(string) == dchar));
1133    static assert(is(ElementType!(dstring) == immutable(dchar)));
1134
1135    // For ranges it gets the type of .front.
1136    auto range = iota(0, 10);
1137    static assert(is(ElementType!(typeof(range)) == int));
1138}
1139
1140@safe unittest
1141{
1142    static assert(is(ElementType!(byte[]) == byte));
1143    static assert(is(ElementType!(wchar[]) == dchar)); // rvalue
1144    static assert(is(ElementType!(wstring) == dchar));
1145}
1146
1147@safe unittest
1148{
1149    enum XYZ : string { a = "foo" }
1150    auto x = XYZ.a.front;
1151    immutable char[3] a = "abc";
1152    int[] i;
1153    void[] buf;
1154    static assert(is(ElementType!(XYZ) == dchar));
1155    static assert(is(ElementType!(typeof(a)) == dchar));
1156    static assert(is(ElementType!(typeof(i)) == int));
1157    static assert(is(ElementType!(typeof(buf)) == void));
1158    static assert(is(ElementType!(inout(int)[]) == inout(int)));
1159    static assert(is(ElementType!(inout(int[])) == inout(int)));
1160}
1161
1162@safe unittest
1163{
1164    static assert(is(ElementType!(int[5]) == int));
1165    static assert(is(ElementType!(int[0]) == int));
1166    static assert(is(ElementType!(char[5]) == dchar));
1167    static assert(is(ElementType!(char[0]) == dchar));
1168}
1169
1170@safe unittest //11336
1171{
1172    static struct S
1173    {
1174        this(this) @disable;
1175    }
1176    static assert(is(ElementType!(S[]) == S));
1177}
1178
1179@safe unittest // 11401
1180{
1181    // ElementType should also work for non-@propety 'front'
1182    struct E { ushort id; }
1183    struct R
1184    {
1185        E front() { return E.init; }
1186    }
1187    static assert(is(ElementType!R == E));
1188}
1189
1190/**
1191The encoding element type of $(D R). For narrow strings ($(D char[]),
1192$(D wchar[]) and their qualified variants including $(D string) and
1193$(D wstring)), $(D ElementEncodingType) is the character type of the
1194string. For all other types, $(D ElementEncodingType) is the same as
1195$(D ElementType).
1196 */
1197template ElementEncodingType(R)
1198{
1199    static if (is(StringTypeOf!R) && is(R : E[], E))
1200        alias ElementEncodingType = E;
1201    else
1202        alias ElementEncodingType = ElementType!R;
1203}
1204
1205///
1206@safe unittest
1207{
1208    import std.range : iota;
1209    // internally the range stores the encoded type
1210    static assert(is(ElementEncodingType!(char[])  == char));
1211
1212    static assert(is(ElementEncodingType!(wstring) == immutable(wchar)));
1213
1214    static assert(is(ElementEncodingType!(byte[]) == byte));
1215
1216    auto range = iota(0, 10);
1217    static assert(is(ElementEncodingType!(typeof(range)) == int));
1218}
1219
1220@safe unittest
1221{
1222    static assert(is(ElementEncodingType!(wchar[]) == wchar));
1223    static assert(is(ElementEncodingType!(dchar[]) == dchar));
1224    static assert(is(ElementEncodingType!(string)  == immutable(char)));
1225    static assert(is(ElementEncodingType!(dstring) == immutable(dchar)));
1226    static assert(is(ElementEncodingType!(int[])  == int));
1227}
1228
1229@safe unittest
1230{
1231    enum XYZ : string { a = "foo" }
1232    auto x = XYZ.a.front;
1233    immutable char[3] a = "abc";
1234    int[] i;
1235    void[] buf;
1236    static assert(is(ElementType!(XYZ) : dchar));
1237    static assert(is(ElementEncodingType!(char[]) == char));
1238    static assert(is(ElementEncodingType!(string) == immutable char));
1239    static assert(is(ElementType!(typeof(a)) : dchar));
1240    static assert(is(ElementType!(typeof(i)) == int));
1241    static assert(is(ElementEncodingType!(typeof(i)) == int));
1242    static assert(is(ElementType!(typeof(buf)) : void));
1243
1244    static assert(is(ElementEncodingType!(inout char[]) : inout(char)));
1245}
1246
1247@safe unittest
1248{
1249    static assert(is(ElementEncodingType!(int[5]) == int));
1250    static assert(is(ElementEncodingType!(int[0]) == int));
1251    static assert(is(ElementEncodingType!(char[5]) == char));
1252    static assert(is(ElementEncodingType!(char[0]) == char));
1253}
1254
1255/**
1256Returns $(D true) if $(D R) is an input range and has swappable
1257elements. The following code should compile for any range
1258with swappable elements.
1259
1260----
1261R r;
1262static assert(isInputRange!R);
1263swap(r.front, r.front);
1264static if (isBidirectionalRange!R) swap(r.back, r.front);
1265static if (isRandomAccessRange!R) swap(r[0], r.front);
1266----
1267 */
1268template hasSwappableElements(R)
1269{
1270    import std.algorithm.mutation : swap;
1271    enum bool hasSwappableElements = isInputRange!R
1272        && is(typeof((ref R r) => swap(r.front, r.front)))
1273        && (!isBidirectionalRange!R
1274            || is(typeof((ref R r) => swap(r.back, r.front))))
1275        && (!isRandomAccessRange!R
1276            || is(typeof((ref R r) => swap(r[0], r.front))));
1277}
1278
1279///
1280@safe unittest
1281{
1282    static assert(!hasSwappableElements!(const int[]));
1283    static assert(!hasSwappableElements!(const(int)[]));
1284    static assert(!hasSwappableElements!(inout(int)[]));
1285    static assert( hasSwappableElements!(int[]));
1286
1287    static assert(!hasSwappableElements!( string));
1288    static assert(!hasSwappableElements!(dstring));
1289    static assert(!hasSwappableElements!( char[]));
1290    static assert( hasSwappableElements!(dchar[]));
1291}
1292
1293/**
1294Returns $(D true) if $(D R) is an input range and has mutable
1295elements. The following code should compile for any range
1296with assignable elements.
1297
1298----
1299R r;
1300static assert(isInputRange!R);
1301r.front = r.front;
1302static if (isBidirectionalRange!R) r.back = r.front;
1303static if (isRandomAccessRange!R) r[0] = r.front;
1304----
1305 */
1306enum bool hasAssignableElements(R) = isInputRange!R
1307    && is(typeof(lvalueOf!R.front = lvalueOf!R.front))
1308    && (!isBidirectionalRange!R
1309        || is(typeof(lvalueOf!R.back = lvalueOf!R.back)))
1310    && (!isRandomAccessRange!R
1311        || is(typeof(lvalueOf!R[0] = lvalueOf!R.front)));
1312
1313///
1314@safe unittest
1315{
1316    static assert(!hasAssignableElements!(const int[]));
1317    static assert(!hasAssignableElements!(const(int)[]));
1318    static assert( hasAssignableElements!(int[]));
1319    static assert(!hasAssignableElements!(inout(int)[]));
1320
1321    static assert(!hasAssignableElements!( string));
1322    static assert(!hasAssignableElements!(dstring));
1323    static assert(!hasAssignableElements!( char[]));
1324    static assert( hasAssignableElements!(dchar[]));
1325}
1326
1327/**
1328Tests whether the range $(D R) has lvalue elements. These are defined as
1329elements that can be passed by reference and have their address taken.
1330The following code should compile for any range with lvalue elements.
1331----
1332void passByRef(ref ElementType!R stuff);
1333...
1334static assert(isInputRange!R);
1335passByRef(r.front);
1336static if (isBidirectionalRange!R) passByRef(r.back);
1337static if (isRandomAccessRange!R) passByRef(r[0]);
1338----
1339*/
1340enum bool hasLvalueElements(R) = isInputRange!R
1341    && is(typeof(((ref x) => x)(lvalueOf!R.front)))
1342    && (!isBidirectionalRange!R
1343        || is(typeof(((ref x) => x)(lvalueOf!R.back))))
1344    && (!isRandomAccessRange!R
1345        || is(typeof(((ref x) => x)(lvalueOf!R[0]))));
1346
1347///
1348@safe unittest
1349{
1350    import std.range : iota, chain;
1351
1352    static assert( hasLvalueElements!(int[]));
1353    static assert( hasLvalueElements!(const(int)[]));
1354    static assert( hasLvalueElements!(inout(int)[]));
1355    static assert( hasLvalueElements!(immutable(int)[]));
1356    static assert(!hasLvalueElements!(typeof(iota(3))));
1357
1358    static assert(!hasLvalueElements!( string));
1359    static assert( hasLvalueElements!(dstring));
1360    static assert(!hasLvalueElements!( char[]));
1361    static assert( hasLvalueElements!(dchar[]));
1362
1363    auto c = chain([1, 2, 3], [4, 5, 6]);
1364    static assert( hasLvalueElements!(typeof(c)));
1365}
1366
1367@safe unittest
1368{
1369    // bugfix 6336
1370    struct S { immutable int value; }
1371    static assert( isInputRange!(S[]));
1372    static assert( hasLvalueElements!(S[]));
1373}
1374
1375/**
1376Yields `true` if `R` has a `length` member that returns a value of `size_t`
1377type. `R` does not have to be a range. If `R` is a range, algorithms in the
1378standard library are only guaranteed to support `length` with type `size_t`.
1379
1380Note that `length` is an optional primitive as no range must implement it. Some
1381ranges do not store their length explicitly, some cannot compute it without
1382actually exhausting the range (e.g. socket streams), and some other ranges may
1383be infinite.
1384
1385Although narrow string types (`char[]`, `wchar[]`, and their qualified
1386derivatives) do define a `length` property, `hasLength` yields `false` for them.
1387This is because a narrow string's length does not reflect the number of
1388characters, but instead the number of encoding units, and as such is not useful
1389with range-oriented algorithms. To use strings as random-access ranges with
1390length, use $(REF representation, std, string) or $(REF byCodeUnit, std, utf).
1391*/
1392template hasLength(R)
1393{
1394    static if (is(typeof(((R* r) => r.length)(null)) Length))
1395        enum bool hasLength = is(Length == size_t) && !isNarrowString!R;
1396    else
1397        enum bool hasLength = false;
1398}
1399
1400///
1401@safe unittest
1402{
1403    static assert(!hasLength!(char[]));
1404    static assert( hasLength!(int[]));
1405    static assert( hasLength!(inout(int)[]));
1406
1407    struct A { size_t length() { return 0; } }
1408    struct B { @property size_t length() { return 0; } }
1409    static assert( hasLength!(A));
1410    static assert( hasLength!(B));
1411}
1412
1413// test combinations which are invalid on some platforms
1414unittest
1415{
1416    struct A { ulong length; }
1417    struct B { @property uint length() { return 0; } }
1418
1419    static if (is(size_t == uint))
1420    {
1421        static assert(!hasLength!(A));
1422        static assert(hasLength!(B));
1423    }
1424    else static if (is(size_t == ulong))
1425    {
1426        static assert(hasLength!(A));
1427        static assert(!hasLength!(B));
1428    }
1429}
1430
1431// test combinations which are invalid on all platforms
1432unittest
1433{
1434    struct A { long length; }
1435    struct B { int length; }
1436    struct C { ubyte length; }
1437    struct D { char length; }
1438    static assert(!hasLength!(A));
1439    static assert(!hasLength!(B));
1440    static assert(!hasLength!(C));
1441    static assert(!hasLength!(D));
1442}
1443
1444/**
1445Returns $(D true) if $(D R) is an infinite input range. An
1446infinite input range is an input range that has a statically-defined
1447enumerated member called $(D empty) that is always $(D false),
1448for example:
1449
1450----
1451struct MyInfiniteRange
1452{
1453    enum bool empty = false;
1454    ...
1455}
1456----
1457 */
1458
1459template isInfinite(R)
1460{
1461    static if (isInputRange!R && __traits(compiles, { enum e = R.empty; }))
1462        enum bool isInfinite = !R.empty;
1463    else
1464        enum bool isInfinite = false;
1465}
1466
1467///
1468@safe unittest
1469{
1470    import std.range : Repeat;
1471    static assert(!isInfinite!(int[]));
1472    static assert( isInfinite!(Repeat!(int)));
1473}
1474
1475/**
1476Returns $(D true) if $(D R) offers a slicing operator with integral boundaries
1477that returns a forward range type.
1478
1479For finite ranges, the result of $(D opSlice) must be of the same type as the
1480original range type. If the range defines $(D opDollar), then it must support
1481subtraction.
1482
1483For infinite ranges, when $(I not) using $(D opDollar), the result of
1484$(D opSlice) must be the result of $(LREF take) or $(LREF takeExactly) on the
1485original range (they both return the same type for infinite ranges). However,
1486when using $(D opDollar), the result of $(D opSlice) must be that of the
1487original range type.
1488
1489The following expression must be true for `hasSlicing` to be `true`:
1490
1491----
1492    isForwardRange!R
1493    && !isNarrowString!R
1494    && is(ReturnType!((R r) => r[1 .. 1].length) == size_t)
1495    && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
1496    && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
1497    && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
1498        || is(typeof(lvalueOf!R[0 .. $ - 1]) == R))
1499    && is(typeof((ref R r)
1500    {
1501        static assert(isForwardRange!(typeof(r[1 .. 2])));
1502    }));
1503----
1504 */
1505enum bool hasSlicing(R) = isForwardRange!R
1506    && !isNarrowString!R
1507    && is(ReturnType!((R r) => r[1 .. 1].length) == size_t)
1508    && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
1509    && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
1510    && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
1511        || is(typeof(lvalueOf!R[0 .. $ - 1]) == R))
1512    && is(typeof((ref R r)
1513    {
1514        static assert(isForwardRange!(typeof(r[1 .. 2])));
1515    }));
1516
1517///
1518@safe unittest
1519{
1520    import std.range : takeExactly;
1521    static assert( hasSlicing!(int[]));
1522    static assert( hasSlicing!(const(int)[]));
1523    static assert(!hasSlicing!(const int[]));
1524    static assert( hasSlicing!(inout(int)[]));
1525    static assert(!hasSlicing!(inout int []));
1526    static assert( hasSlicing!(immutable(int)[]));
1527    static assert(!hasSlicing!(immutable int[]));
1528    static assert(!hasSlicing!string);
1529    static assert( hasSlicing!dstring);
1530
1531    enum rangeFuncs = "@property int front();" ~
1532                      "void popFront();" ~
1533                      "@property bool empty();" ~
1534                      "@property auto save() { return this; }" ~
1535                      "@property size_t length();";
1536
1537    struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); }
1538    struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); }
1539    struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); }
1540    struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); }
1541    static assert(!hasSlicing!(A));
1542    static assert( hasSlicing!(B));
1543    static assert( hasSlicing!(C));
1544    static assert(!hasSlicing!(D));
1545
1546    struct InfOnes
1547    {
1548        enum empty = false;
1549        void popFront() {}
1550        @property int front() { return 1; }
1551        @property InfOnes save() { return this; }
1552        auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); }
1553        auto opSlice(size_t i, Dollar d) { return this; }
1554
1555        struct Dollar {}
1556        Dollar opDollar() const { return Dollar.init; }
1557    }
1558
1559    static assert(hasSlicing!InfOnes);
1560}
1561
1562/**
1563This is a best-effort implementation of $(D length) for any kind of
1564range.
1565
1566If $(D hasLength!Range), simply returns $(D range.length) without
1567checking $(D upTo) (when specified).
1568
1569Otherwise, walks the range through its length and returns the number
1570of elements seen. Performes $(BIGOH n) evaluations of $(D range.empty)
1571and $(D range.popFront()), where $(D n) is the effective length of $(D
1572range).
1573
1574The $(D upTo) parameter is useful to "cut the losses" in case
1575the interest is in seeing whether the range has at least some number
1576of elements. If the parameter $(D upTo) is specified, stops if $(D
1577upTo) steps have been taken and returns $(D upTo).
1578
1579Infinite ranges are compatible, provided the parameter $(D upTo) is
1580specified, in which case the implementation simply returns upTo.
1581 */
1582auto walkLength(Range)(Range range)
1583if (isInputRange!Range && !isInfinite!Range)
1584{
1585    static if (hasLength!Range)
1586        return range.length;
1587    else
1588    {
1589        size_t result;
1590        for ( ; !range.empty ; range.popFront() )
1591            ++result;
1592        return result;
1593    }
1594}
1595/// ditto
1596auto walkLength(Range)(Range range, const size_t upTo)
1597if (isInputRange!Range)
1598{
1599    static if (hasLength!Range)
1600        return range.length;
1601    else static if (isInfinite!Range)
1602        return upTo;
1603    else
1604    {
1605        size_t result;
1606        for ( ; result < upTo && !range.empty ; range.popFront() )
1607            ++result;
1608        return result;
1609    }
1610}
1611
1612@safe unittest
1613{
1614    import std.algorithm.iteration : filter;
1615    import std.range : recurrence, take;
1616
1617    //hasLength Range
1618    int[] a = [ 1, 2, 3 ];
1619    assert(walkLength(a) == 3);
1620    assert(walkLength(a, 0) == 3);
1621    assert(walkLength(a, 2) == 3);
1622    assert(walkLength(a, 4) == 3);
1623
1624    //Forward Range
1625    auto b = filter!"true"([1, 2, 3, 4]);
1626    assert(b.walkLength() == 4);
1627    assert(b.walkLength(0) == 0);
1628    assert(b.walkLength(2) == 2);
1629    assert(b.walkLength(4) == 4);
1630    assert(b.walkLength(6) == 4);
1631
1632    //Infinite Range
1633    auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
1634    assert(!__traits(compiles, fibs.walkLength()));
1635    assert(fibs.take(10).walkLength() == 10);
1636    assert(fibs.walkLength(55) == 55);
1637}
1638
1639/**
1640    Eagerly advances $(D r) itself (not a copy) up to $(D n) times (by
1641    calling $(D r.popFront)). $(D popFrontN) takes $(D r) by $(D ref),
1642    so it mutates the original range. Completes in $(BIGOH 1) steps for ranges
1643    that support slicing and have length.
1644    Completes in $(BIGOH n) time for all other ranges.
1645
1646    Returns:
1647    How much $(D r) was actually advanced, which may be less than $(D n) if
1648    $(D r) did not have at least $(D n) elements.
1649
1650    $(D popBackN) will behave the same but instead removes elements from
1651    the back of the (bidirectional) range instead of the front.
1652
1653    See_Also: $(REF drop, std, range), $(REF dropBack, std, range)
1654*/
1655size_t popFrontN(Range)(ref Range r, size_t n)
1656if (isInputRange!Range)
1657{
1658    static if (hasLength!Range)
1659    {
1660        n = cast(size_t) (n < r.length ? n : r.length);
1661    }
1662
1663    static if (hasSlicing!Range && is(typeof(r = r[n .. $])))
1664    {
1665        r = r[n .. $];
1666    }
1667    else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar.
1668    {
1669        r = r[n .. r.length];
1670    }
1671    else
1672    {
1673        static if (hasLength!Range)
1674        {
1675            foreach (i; 0 .. n)
1676                r.popFront();
1677        }
1678        else
1679        {
1680            foreach (i; 0 .. n)
1681            {
1682                if (r.empty) return i;
1683                r.popFront();
1684            }
1685        }
1686    }
1687    return n;
1688}
1689
1690/// ditto
1691size_t popBackN(Range)(ref Range r, size_t n)
1692if (isBidirectionalRange!Range)
1693{
1694    static if (hasLength!Range)
1695    {
1696        n = cast(size_t) (n < r.length ? n : r.length);
1697    }
1698
1699    static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n])))
1700    {
1701        r = r[0 .. $ - n];
1702    }
1703    else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar.
1704    {
1705        r = r[0 .. r.length - n];
1706    }
1707    else
1708    {
1709        static if (hasLength!Range)
1710        {
1711            foreach (i; 0 .. n)
1712                r.popBack();
1713        }
1714        else
1715        {
1716            foreach (i; 0 .. n)
1717            {
1718                if (r.empty) return i;
1719                r.popBack();
1720            }
1721        }
1722    }
1723    return n;
1724}
1725
1726///
1727@safe unittest
1728{
1729    int[] a = [ 1, 2, 3, 4, 5 ];
1730    a.popFrontN(2);
1731    assert(a == [ 3, 4, 5 ]);
1732    a.popFrontN(7);
1733    assert(a == [ ]);
1734}
1735
1736///
1737@safe unittest
1738{
1739    import std.algorithm.comparison : equal;
1740    import std.range : iota;
1741    auto LL = iota(1L, 7L);
1742    auto r = popFrontN(LL, 2);
1743    assert(equal(LL, [3L, 4L, 5L, 6L]));
1744    assert(r == 2);
1745}
1746
1747///
1748@safe unittest
1749{
1750    int[] a = [ 1, 2, 3, 4, 5 ];
1751    a.popBackN(2);
1752    assert(a == [ 1, 2, 3 ]);
1753    a.popBackN(7);
1754    assert(a == [ ]);
1755}
1756
1757///
1758@safe unittest
1759{
1760    import std.algorithm.comparison : equal;
1761    import std.range : iota;
1762    auto LL = iota(1L, 7L);
1763    auto r = popBackN(LL, 2);
1764    assert(equal(LL, [1L, 2L, 3L, 4L]));
1765    assert(r == 2);
1766}
1767
1768/**
1769    Eagerly advances $(D r) itself (not a copy) exactly $(D n) times (by
1770    calling $(D r.popFront)). $(D popFrontExactly) takes $(D r) by $(D ref),
1771    so it mutates the original range. Completes in $(BIGOH 1) steps for ranges
1772    that support slicing, and have either length or are infinite.
1773    Completes in $(BIGOH n) time for all other ranges.
1774
1775    Note: Unlike $(LREF popFrontN), $(D popFrontExactly) will assume that the
1776    range holds at least $(D n) elements. This makes $(D popFrontExactly)
1777    faster than $(D popFrontN), but it also means that if $(D range) does
1778    not contain at least $(D n) elements, it will attempt to call $(D popFront)
1779    on an empty range, which is undefined behavior. So, only use
1780    $(D popFrontExactly) when it is guaranteed that $(D range) holds at least
1781    $(D n) elements.
1782
1783    $(D popBackExactly) will behave the same but instead removes elements from
1784    the back of the (bidirectional) range instead of the front.
1785
1786    See_Also: $(REF dropExcatly, std, range), $(REF dropBackExactly, std, range)
1787*/
1788void popFrontExactly(Range)(ref Range r, size_t n)
1789if (isInputRange!Range)
1790{
1791    static if (hasLength!Range)
1792        assert(n <= r.length, "range is smaller than amount of items to pop");
1793
1794    static if (hasSlicing!Range && is(typeof(r = r[n .. $])))
1795        r = r[n .. $];
1796    else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar.
1797        r = r[n .. r.length];
1798    else
1799        foreach (i; 0 .. n)
1800            r.popFront();
1801}
1802
1803/// ditto
1804void popBackExactly(Range)(ref Range r, size_t n)
1805if (isBidirectionalRange!Range)
1806{
1807    static if (hasLength!Range)
1808        assert(n <= r.length, "range is smaller than amount of items to pop");
1809
1810    static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n])))
1811        r = r[0 .. $ - n];
1812    else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar.
1813        r = r[0 .. r.length - n];
1814    else
1815        foreach (i; 0 .. n)
1816            r.popBack();
1817}
1818
1819///
1820@safe unittest
1821{
1822    import std.algorithm.comparison : equal;
1823    import std.algorithm.iteration : filterBidirectional;
1824
1825    auto a = [1, 2, 3];
1826    a.popFrontExactly(1);
1827    assert(a == [2, 3]);
1828    a.popBackExactly(1);
1829    assert(a == [2]);
1830
1831    string s = "���������";
1832    s.popFrontExactly(1);
1833    assert(s == "������");
1834    s.popBackExactly(1);
1835    assert(s == "���");
1836
1837    auto bd = filterBidirectional!"true"([1, 2, 3]);
1838    bd.popFrontExactly(1);
1839    assert(bd.equal([2, 3]));
1840    bd.popBackExactly(1);
1841    assert(bd.equal([2]));
1842}
1843
1844/**
1845   Moves the front of $(D r) out and returns it. Leaves $(D r.front) in a
1846   destroyable state that does not allocate any resources (usually equal
1847   to its $(D .init) value).
1848*/
1849ElementType!R moveFront(R)(R r)
1850{
1851    static if (is(typeof(&r.moveFront)))
1852    {
1853        return r.moveFront();
1854    }
1855    else static if (!hasElaborateCopyConstructor!(ElementType!R))
1856    {
1857        return r.front;
1858    }
1859    else static if (is(typeof(&(r.front())) == ElementType!R*))
1860    {
1861        import std.algorithm.mutation : move;
1862        return move(r.front);
1863    }
1864    else
1865    {
1866        static assert(0,
1867                "Cannot move front of a range with a postblit and an rvalue front.");
1868    }
1869}
1870
1871///
1872@safe unittest
1873{
1874    auto a = [ 1, 2, 3 ];
1875    assert(moveFront(a) == 1);
1876    assert(a.length == 3);
1877
1878    // define a perfunctory input range
1879    struct InputRange
1880    {
1881        enum bool empty = false;
1882        enum int front = 7;
1883        void popFront() {}
1884        int moveFront() { return 43; }
1885    }
1886    InputRange r;
1887    // calls r.moveFront
1888    assert(moveFront(r) == 43);
1889}
1890
1891@safe unittest
1892{
1893    struct R
1894    {
1895        @property ref int front() { static int x = 42; return x; }
1896        this(this){}
1897    }
1898    R r;
1899    assert(moveFront(r) == 42);
1900}
1901
1902/**
1903   Moves the back of $(D r) out and returns it. Leaves $(D r.back) in a
1904   destroyable state that does not allocate any resources (usually equal
1905   to its $(D .init) value).
1906*/
1907ElementType!R moveBack(R)(R r)
1908{
1909    static if (is(typeof(&r.moveBack)))
1910    {
1911        return r.moveBack();
1912    }
1913    else static if (!hasElaborateCopyConstructor!(ElementType!R))
1914    {
1915        return r.back;
1916    }
1917    else static if (is(typeof(&(r.back())) == ElementType!R*))
1918    {
1919        import std.algorithm.mutation : move;
1920        return move(r.back);
1921    }
1922    else
1923    {
1924        static assert(0,
1925                "Cannot move back of a range with a postblit and an rvalue back.");
1926    }
1927}
1928
1929///
1930@safe unittest
1931{
1932    struct TestRange
1933    {
1934        int payload = 5;
1935        @property bool empty() { return false; }
1936        @property TestRange save() { return this; }
1937        @property ref int front() return { return payload; }
1938        @property ref int back() return { return payload; }
1939        void popFront() { }
1940        void popBack() { }
1941    }
1942    static assert(isBidirectionalRange!TestRange);
1943    TestRange r;
1944    auto x = moveBack(r);
1945    assert(x == 5);
1946}
1947
1948/**
1949   Moves element at index $(D i) of $(D r) out and returns it. Leaves $(D
1950   r[i]) in a destroyable state that does not allocate any resources
1951   (usually equal to its $(D .init) value).
1952*/
1953ElementType!R moveAt(R)(R r, size_t i)
1954{
1955    static if (is(typeof(&r.moveAt)))
1956    {
1957        return r.moveAt(i);
1958    }
1959    else static if (!hasElaborateCopyConstructor!(ElementType!(R)))
1960    {
1961        return r[i];
1962    }
1963    else static if (is(typeof(&r[i]) == ElementType!R*))
1964    {
1965        import std.algorithm.mutation : move;
1966        return move(r[i]);
1967    }
1968    else
1969    {
1970        static assert(0,
1971                "Cannot move element of a range with a postblit and rvalue elements.");
1972    }
1973}
1974
1975///
1976@safe unittest
1977{
1978    auto a = [1,2,3,4];
1979    foreach (idx, it; a)
1980    {
1981        assert(it == moveAt(a, idx));
1982    }
1983}
1984
1985@safe unittest
1986{
1987    import std.internal.test.dummyrange;
1988
1989    foreach (DummyType; AllDummyRanges)
1990    {
1991        auto d = DummyType.init;
1992        assert(moveFront(d) == 1);
1993
1994        static if (isBidirectionalRange!DummyType)
1995        {
1996            assert(moveBack(d) == 10);
1997        }
1998
1999        static if (isRandomAccessRange!DummyType)
2000        {
2001            assert(moveAt(d, 2) == 3);
2002        }
2003    }
2004}
2005
2006/**
2007Implements the range interface primitive $(D empty) for built-in
2008arrays. Due to the fact that nonmember functions can be called with
2009the first argument using the dot notation, $(D array.empty) is
2010equivalent to $(D empty(array)).
2011 */
2012@property bool empty(T)(in T[] a) @safe pure nothrow @nogc
2013{
2014    return !a.length;
2015}
2016
2017///
2018@safe pure nothrow unittest
2019{
2020    auto a = [ 1, 2, 3 ];
2021    assert(!a.empty);
2022    assert(a[3 .. $].empty);
2023}
2024
2025/**
2026Implements the range interface primitive $(D save) for built-in
2027arrays. Due to the fact that nonmember functions can be called with
2028the first argument using the dot notation, $(D array.save) is
2029equivalent to $(D save(array)). The function does not duplicate the
2030content of the array, it simply returns its argument.
2031 */
2032@property T[] save(T)(T[] a) @safe pure nothrow @nogc
2033{
2034    return a;
2035}
2036
2037///
2038@safe pure nothrow unittest
2039{
2040    auto a = [ 1, 2, 3 ];
2041    auto b = a.save;
2042    assert(b is a);
2043}
2044
2045/**
2046Implements the range interface primitive $(D popFront) for built-in
2047arrays. Due to the fact that nonmember functions can be called with
2048the first argument using the dot notation, $(D array.popFront) is
2049equivalent to $(D popFront(array)). For $(GLOSSARY narrow strings),
2050$(D popFront) automatically advances to the next $(GLOSSARY code
2051point).
2052*/
2053void popFront(T)(ref T[] a) @safe pure nothrow @nogc
2054if (!isNarrowString!(T[]) && !is(T[] == void[]))
2055{
2056    assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof);
2057    a = a[1 .. $];
2058}
2059
2060///
2061@safe pure nothrow unittest
2062{
2063    auto a = [ 1, 2, 3 ];
2064    a.popFront();
2065    assert(a == [ 2, 3 ]);
2066}
2067
2068version (unittest)
2069{
2070    static assert(!is(typeof({          int[4] a; popFront(a); })));
2071    static assert(!is(typeof({ immutable int[] a; popFront(a); })));
2072    static assert(!is(typeof({          void[] a; popFront(a); })));
2073}
2074
2075/// ditto
2076void popFront(C)(ref C[] str) @trusted pure nothrow
2077if (isNarrowString!(C[]))
2078{
2079    import std.algorithm.comparison : min;
2080
2081    assert(str.length, "Attempting to popFront() past the end of an array of " ~ C.stringof);
2082
2083    static if (is(Unqual!C == char))
2084    {
2085        static immutable ubyte[] charWidthTab = [
2086            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2087            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2088            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2089            4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
2090        ];
2091
2092        immutable c = str[0];
2093        if (c < 192)
2094        {
2095            str = str.ptr[1 .. str.length];
2096        }
2097        else
2098        {
2099            str = str.ptr[min(str.length, charWidthTab.ptr[c - 192]) .. str.length];
2100        }
2101
2102    }
2103    else static if (is(Unqual!C == wchar))
2104    {
2105        immutable u = str[0];
2106        immutable seqLen = 1 + (u >= 0xD800 && u <= 0xDBFF);
2107        str = str.ptr[min(seqLen, str.length) .. str.length];
2108    }
2109    else static assert(0, "Bad template constraint.");
2110}
2111
2112@safe pure unittest
2113{
2114    import std.meta : AliasSeq;
2115
2116    foreach (S; AliasSeq!(string, wstring, dstring))
2117    {
2118        S s = "\xC2\xA9hello";
2119        s.popFront();
2120        assert(s == "hello");
2121
2122        S str = "hello\U00010143\u0100\U00010143";
2123        foreach (dchar c; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143'])
2124        {
2125            assert(str.front == c);
2126            str.popFront();
2127        }
2128        assert(str.empty);
2129
2130        static assert(!is(typeof({          immutable S a; popFront(a); })));
2131        static assert(!is(typeof({ typeof(S.init[0])[4] a; popFront(a); })));
2132    }
2133
2134    C[] _eatString(C)(C[] str)
2135    {
2136        while (!str.empty)
2137            str.popFront();
2138
2139        return str;
2140    }
2141    enum checkCTFE = _eatString("������������������@La_Verit��.com");
2142    static assert(checkCTFE.empty);
2143    enum checkCTFEW = _eatString("������������������@La_Verit��.com"w);
2144    static assert(checkCTFEW.empty);
2145}
2146
2147@safe unittest // issue 16090
2148{
2149    string s = "\u00E4";
2150    assert(s.length == 2);
2151    s = s[0 .. 1];
2152    assert(s.length == 1);
2153    s.popFront;
2154    assert(s.empty);
2155}
2156
2157@safe unittest
2158{
2159    wstring s = "\U00010000";
2160    assert(s.length == 2);
2161    s = s[0 .. 1];
2162    assert(s.length == 1);
2163    s.popFront;
2164    assert(s.empty);
2165}
2166
2167/**
2168Implements the range interface primitive $(D popBack) for built-in
2169arrays. Due to the fact that nonmember functions can be called with
2170the first argument using the dot notation, $(D array.popBack) is
2171equivalent to $(D popBack(array)). For $(GLOSSARY narrow strings), $(D
2172popFront) automatically eliminates the last $(GLOSSARY code point).
2173*/
2174void popBack(T)(ref T[] a) @safe pure nothrow @nogc
2175if (!isNarrowString!(T[]) && !is(T[] == void[]))
2176{
2177    assert(a.length);
2178    a = a[0 .. $ - 1];
2179}
2180
2181///
2182@safe pure nothrow unittest
2183{
2184    auto a = [ 1, 2, 3 ];
2185    a.popBack();
2186    assert(a == [ 1, 2 ]);
2187}
2188
2189version (unittest)
2190{
2191    static assert(!is(typeof({ immutable int[] a; popBack(a); })));
2192    static assert(!is(typeof({          int[4] a; popBack(a); })));
2193    static assert(!is(typeof({          void[] a; popBack(a); })));
2194}
2195
2196/// ditto
2197void popBack(T)(ref T[] a) @safe pure
2198if (isNarrowString!(T[]))
2199{
2200    import std.utf : strideBack;
2201    assert(a.length, "Attempting to popBack() past the front of an array of " ~ T.stringof);
2202    a = a[0 .. $ - strideBack(a, $)];
2203}
2204
2205@safe pure unittest
2206{
2207    import std.meta : AliasSeq;
2208
2209    foreach (S; AliasSeq!(string, wstring, dstring))
2210    {
2211        S s = "hello\xE2\x89\xA0";
2212        s.popBack();
2213        assert(s == "hello");
2214        S s3 = "\xE2\x89\xA0";
2215        auto c = s3.back;
2216        assert(c == cast(dchar)'\u2260');
2217        s3.popBack();
2218        assert(s3 == "");
2219
2220        S str = "\U00010143\u0100\U00010143hello";
2221        foreach (dchar ch; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143'])
2222        {
2223            assert(str.back == ch);
2224            str.popBack();
2225        }
2226        assert(str.empty);
2227
2228        static assert(!is(typeof({          immutable S a; popBack(a); })));
2229        static assert(!is(typeof({ typeof(S.init[0])[4] a; popBack(a); })));
2230    }
2231}
2232
2233/**
2234Implements the range interface primitive $(D front) for built-in
2235arrays. Due to the fact that nonmember functions can be called with
2236the first argument using the dot notation, $(D array.front) is
2237equivalent to $(D front(array)). For $(GLOSSARY narrow strings), $(D
2238front) automatically returns the first $(GLOSSARY code point) as _a $(D
2239dchar).
2240*/
2241@property ref T front(T)(T[] a) @safe pure nothrow @nogc
2242if (!isNarrowString!(T[]) && !is(T[] == void[]))
2243{
2244    assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
2245    return a[0];
2246}
2247
2248///
2249@safe pure nothrow unittest
2250{
2251    int[] a = [ 1, 2, 3 ];
2252    assert(a.front == 1);
2253}
2254
2255@safe pure nothrow unittest
2256{
2257    auto a = [ 1, 2 ];
2258    a.front = 4;
2259    assert(a.front == 4);
2260    assert(a == [ 4, 2 ]);
2261
2262    immutable b = [ 1, 2 ];
2263    assert(b.front == 1);
2264
2265    int[2] c = [ 1, 2 ];
2266    assert(c.front == 1);
2267}
2268
2269/// ditto
2270@property dchar front(T)(T[] a) @safe pure
2271if (isNarrowString!(T[]))
2272{
2273    import std.utf : decode;
2274    assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
2275    size_t i = 0;
2276    return decode(a, i);
2277}
2278
2279/**
2280Implements the range interface primitive $(D back) for built-in
2281arrays. Due to the fact that nonmember functions can be called with
2282the first argument using the dot notation, $(D array.back) is
2283equivalent to $(D back(array)). For $(GLOSSARY narrow strings), $(D
2284back) automatically returns the last $(GLOSSARY code point) as _a $(D
2285dchar).
2286*/
2287@property ref T back(T)(T[] a) @safe pure nothrow @nogc
2288if (!isNarrowString!(T[]) && !is(T[] == void[]))
2289{
2290    assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof);
2291    return a[$ - 1];
2292}
2293
2294///
2295@safe pure nothrow unittest
2296{
2297    int[] a = [ 1, 2, 3 ];
2298    assert(a.back == 3);
2299    a.back += 4;
2300    assert(a.back == 7);
2301}
2302
2303@safe pure nothrow unittest
2304{
2305    immutable b = [ 1, 2, 3 ];
2306    assert(b.back == 3);
2307
2308    int[3] c = [ 1, 2, 3 ];
2309    assert(c.back == 3);
2310}
2311
2312/// ditto
2313// Specialization for strings
2314@property dchar back(T)(T[] a) @safe pure
2315if (isNarrowString!(T[]))
2316{
2317    import std.utf : decode, strideBack;
2318    assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof);
2319    size_t i = a.length - strideBack(a, a.length);
2320    return decode(a, i);
2321}
2322