xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/src/std/range/primitives.d (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /**
2 This module is a submodule of $(MREF std, range).
3 
4 It provides basic range functionality by defining several templates for testing
5 whether 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 
37 It 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 
72 Finally, 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 
106 Source: $(PHOBOSSRC std/range/_primitives.d)
107 
108 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
109 
110 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha,
111 and Jonathan M Davis. Credit for some of the ideas in building this module goes
112 to $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
113 */
114 module std.range.primitives;
115 
116 import std.traits;
117 
118 /**
119 Returns $(D true) if $(D R) is an input range. An input range must
120 define the primitives $(D empty), $(D popFront), and $(D front). The
121 following code should compile for any input range.
122 
123 ----
124 R r;              // can define a range object
125 if (r.empty) {}   // can test for empty
126 r.popFront();     // can invoke popFront()
127 auto h = r.front; // can get the front of the range of non-void type
128 ----
129 
130 The following are rules of input ranges are assumed to hold true in all
131 Phobos code. These rules are not checkable at compile-time, so not conforming
132 to these rules when writing ranges or range based code will result in
133 undefined 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 
153 Also, 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
155 running time. $(BIGOH) statements in the documentation of range functions
156 are made with this assumption.
157 
158 Params:
159     R = type to be tested
160 
161 Returns:
162     true if R is an InputRange, false if not
163  */
164 enum 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;
valueR::Front232             @property int value() { return impl._front; }
233             alias value this;
234         }
235 
236         int _front;
237 
emptyR238         @property bool empty() { return _front >= 3; }
frontR239         @property auto front() { return Front(&this); }
popFrontR240         void popFront() { _front++; }
241     }
242     R r;
243 
244     static assert(isInputRange!R);
245     assert(r.equal([ 0, 1, 2 ]));
246 }
247 
248 /+
249 puts the whole raw element $(D e) into $(D r). doPut will not attempt to
250 iterate, slice or transcode $(D e) in any way shape or form. It will $(B only)
251 call the correct primitive ($(D r.put(e)),  $(D r.front = e) or
252 $(D r(0)) once.
253 
254 This can be important when $(D e) needs to be placed in $(D r) unchanged.
255 Furthermore, it can be useful when working with $(D InputRange)s, as doPut
256 guarantees that no more than a single element will be placed.
257 +/
doPut(R,E)258 private 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 /++
315 Outputs $(D e) to $(D r). The exact effect is dependent upon the two
316 types. Several cases are accepted, as described below. The code snippets
317 are attempted in order, and the first to compile "wins" and gets
318 evaluated.
319 
320 In this table "doPut" is a method that places $(D e) into $(D r), using the
321 correct primitive: $(D r.put(e)) if $(D R) defines $(D put), $(D r.front = e)
322 if $(D r) is an input range (followed by $(D r.popFront())), or $(D r(e))
323 otherwise.
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 
349 Tip: $(D put) should $(I not) be used "UFCS-style", e.g. $(D r.put(e)).
350 Doing this may call $(D R.put) directly, by-passing any transformation
351 feature provided by $(D Range.put). $(D put(r, e)) is prefered.
352  +/
put(R,E)353 void 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 {
R()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
418 private void putChar(R, E)(ref R r, E e)
419 if (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 
463 pure @safe unittest
464 {
delegate(const (char)[])465     auto f = delegate (const(char)[]) {};
466     putChar(f, cast(dchar)'a');
467 }
468 
469 
470 @safe pure unittest
471 {
R()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     {
putB483         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 {
myprint(in char[]s)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     {
putLockingTextWriter571         void put(dchar c){}
572     }
573     struct RetroResult
574     {
575         bool end = false;
empty()576         @property bool empty() const { return end; }
front()577         @property dchar front(){ return 'a'; }
popFront()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 
PutC(C)591     static struct PutC(C)
592     {
593         string result;
594         void put(const(C) c) { result ~= to!string((&c)[0 .. 1]); }
595     }
PutS(C)596     static struct PutS(C)
597     {
598         string result;
599         void put(const(C)[] s) { result ~= to!string(s); }
600     }
PutSS(C)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
foreach(value;tuple (type,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;
popFrontCharRange654         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 /+
737 Returns $(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
739 supports the operation $(D doPut(r, e)) as defined above. if $(D doPut(r, e))
740 is valid, then $(D put(r,e)) will have the same behavior.
741 
742 The two guarantees isNativeOutputRange gives over the larger $(D isOutputRange)
743 are:
744 1: $(D e) is $(B exactly) what will be placed (not $(D [e]), for example).
745 2: if $(D E) is a non $(empty) $(D InputRange), then placing $(D e) is
746 guaranteed to not overflow the range.
747  +/
748 package(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 /++
766 Returns $(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
768 supports the operation $(D put(r, e)) as defined above.
769  +/
770 enum 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 /**
806 Returns $(D true) if $(D R) is a forward range. A forward range is an
807 input range $(D r) that can save "checkpoints" by saving $(D r.save)
808 to another value of type $(D R). Notable examples of input ranges that
809 are $(I not) forward ranges are file/socket ranges; copying such a
810 range will not save the position in the stream, and they most likely
811 reuse an internal buffer as the entire stream does not sit in
812 memory. Subsequently, advancing either the original or the copy will
813 advance the stream, so the copies are not independent.
814 
815 The following code should compile for any forward range.
816 
817 ----
818 static assert(isInputRange!R);
819 R r1;
820 auto s1 = r1.save;
821 static assert(is(typeof(s1) == R));
822 ----
823 
824 Saving a range is not duplicating it; in the example above, $(D r1)
825 and $(D r2) still refer to the same underlying data. They just
826 navigate that data independently.
827 
828 The semantics of a forward range (not checkable during compilation)
829 are the same as for an input range, with the additional requirement
830 that backtracking must be possible by saving a copy of the range
831 object with $(D save) and using it later.
832  */
833 enum 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 /**
859 Returns $(D true) if $(D R) is a bidirectional range. A bidirectional
860 range is a forward range that also offers the primitives $(D back) and
861 $(D popBack). The following code should compile for any bidirectional
862 range.
863 
864 The semantics of a bidirectional range (not checkable during
865 compilation) are assumed to be the following ($(D r) is an object of
866 type $(D R)):
867 
868 $(UL $(LI $(D r.back) returns (possibly a reference to) the last
869 element in the range. Calling $(D r.back) is allowed only if calling
870 $(D r.empty) has, or would have, returned $(D false).))
871  */
872 enum 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 /**
915 Returns $(D true) if $(D R) is a random-access range. A random-access
916 range is a bidirectional range that also offers the primitive $(D
917 opIndex), OR an infinite forward range that offers $(D opIndex). In
918 either case, the range must either offer $(D length) or be
919 infinite. The following code should compile for any random-access
920 range.
921 
922 The semantics of a random-access range (not checkable during
923 compilation) are assumed to be the following ($(D r) is an object of
924 type $(D R)): $(UL $(LI $(D r.opIndex(n)) returns a reference to the
925 $(D n)th element in the range.))
926 
927 Although $(D char[]) and $(D wchar[]) (as well as their qualified
928 versions including $(D string) and $(D wstring)) are arrays, $(D
929 isRandomAccessRange) yields $(D false) for them because they use
930 variable-length encodings (UTF-8 and UTF-16 respectively). These types
931 are bidirectional ranges only.
932  */
933 enum 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 /**
1054 Returns $(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
1056 bidirectional or random access range. These may be explicitly implemented, or
1057 may work via the default behavior of the module level functions $(D moveFront)
1058 and friends. The following code should compile for any range
1059 with mobile elements.
1060 
1061 ----
1062 alias E = ElementType!R;
1063 R r;
1064 static assert(isInputRange!R);
1065 static assert(is(typeof(moveFront(r)) == E));
1066 static if (isBidirectionalRange!R)
1067     static assert(is(typeof(moveBack(r)) == E));
1068 static if (isRandomAccessRange!R)
1069     static assert(is(typeof(moveAt(r, 0)) == E));
1070 ----
1071  */
1072 enum 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 /**
1104 The element type of $(D R). $(D R) does not have to be a range. The
1105 element type is determined as the type yielded by $(D r.front) for an
1106 object $(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  */
1111 template 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 /**
1191 The 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
1194 string. For all other types, $(D ElementEncodingType) is the same as
1195 $(D ElementType).
1196  */
1197 template 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 /**
1256 Returns $(D true) if $(D R) is an input range and has swappable
1257 elements. The following code should compile for any range
1258 with swappable elements.
1259 
1260 ----
1261 R r;
1262 static assert(isInputRange!R);
1263 swap(r.front, r.front);
1264 static if (isBidirectionalRange!R) swap(r.back, r.front);
1265 static if (isRandomAccessRange!R) swap(r[0], r.front);
1266 ----
1267  */
1268 template 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 /**
1294 Returns $(D true) if $(D R) is an input range and has mutable
1295 elements. The following code should compile for any range
1296 with assignable elements.
1297 
1298 ----
1299 R r;
1300 static assert(isInputRange!R);
1301 r.front = r.front;
1302 static if (isBidirectionalRange!R) r.back = r.front;
1303 static if (isRandomAccessRange!R) r[0] = r.front;
1304 ----
1305  */
1306 enum 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 /**
1328 Tests whether the range $(D R) has lvalue elements. These are defined as
1329 elements that can be passed by reference and have their address taken.
1330 The following code should compile for any range with lvalue elements.
1331 ----
1332 void passByRef(ref ElementType!R stuff);
1333 ...
1334 static assert(isInputRange!R);
1335 passByRef(r.front);
1336 static if (isBidirectionalRange!R) passByRef(r.back);
1337 static if (isRandomAccessRange!R) passByRef(r[0]);
1338 ----
1339 */
1340 enum 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 /**
1376 Yields `true` if `R` has a `length` member that returns a value of `size_t`
1377 type. `R` does not have to be a range. If `R` is a range, algorithms in the
1378 standard library are only guaranteed to support `length` with type `size_t`.
1379 
1380 Note that `length` is an optional primitive as no range must implement it. Some
1381 ranges do not store their length explicitly, some cannot compute it without
1382 actually exhausting the range (e.g. socket streams), and some other ranges may
1383 be infinite.
1384 
1385 Although narrow string types (`char[]`, `wchar[]`, and their qualified
1386 derivatives) do define a `length` property, `hasLength` yields `false` for them.
1387 This is because a narrow string's length does not reflect the number of
1388 characters, but instead the number of encoding units, and as such is not useful
1389 with range-oriented algorithms. To use strings as random-access ranges with
1390 length, use $(REF representation, std, string) or $(REF byCodeUnit, std, utf).
1391 */
1392 template 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
1414 unittest
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
1432 unittest
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 /**
1445 Returns $(D true) if $(D R) is an infinite input range. An
1446 infinite input range is an input range that has a statically-defined
1447 enumerated member called $(D empty) that is always $(D false),
1448 for example:
1449 
1450 ----
1451 struct MyInfiniteRange
1452 {
1453     enum bool empty = false;
1454     ...
1455 }
1456 ----
1457  */
1458 
1459 template 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 /**
1476 Returns $(D true) if $(D R) offers a slicing operator with integral boundaries
1477 that returns a forward range type.
1478 
1479 For finite ranges, the result of $(D opSlice) must be of the same type as the
1480 original range type. If the range defines $(D opDollar), then it must support
1481 subtraction.
1482 
1483 For 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
1485 original range (they both return the same type for infinite ranges). However,
1486 when using $(D opDollar), the result of $(D opSlice) must be that of the
1487 original range type.
1488 
1489 The 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  */
1505 enum 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 /**
1563 This is a best-effort implementation of $(D length) for any kind of
1564 range.
1565 
1566 If $(D hasLength!Range), simply returns $(D range.length) without
1567 checking $(D upTo) (when specified).
1568 
1569 Otherwise, walks the range through its length and returns the number
1570 of elements seen. Performes $(BIGOH n) evaluations of $(D range.empty)
1571 and $(D range.popFront()), where $(D n) is the effective length of $(D
1572 range).
1573 
1574 The $(D upTo) parameter is useful to "cut the losses" in case
1575 the interest is in seeing whether the range has at least some number
1576 of elements. If the parameter $(D upTo) is specified, stops if $(D
1577 upTo) steps have been taken and returns $(D upTo).
1578 
1579 Infinite ranges are compatible, provided the parameter $(D upTo) is
1580 specified, in which case the implementation simply returns upTo.
1581  */
1582 auto walkLength(Range)(Range range)
1583 if (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
1596 auto walkLength(Range)(Range range, const size_t upTo)
1597 if (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 */
1655 size_t popFrontN(Range)(ref Range r, size_t n)
1656 if (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
1691 size_t popBackN(Range)(ref Range r, size_t n)
1692 if (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 */
1788 void popFrontExactly(Range)(ref Range r, size_t n)
1789 if (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
1804 void popBackExactly(Range)(ref Range r, size_t n)
1805 if (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 */
1849 ElementType!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 */
1907 ElementType!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 */
1953 ElementType!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 /**
2007 Implements the range interface primitive $(D empty) for built-in
2008 arrays. Due to the fact that nonmember functions can be called with
2009 the first argument using the dot notation, $(D array.empty) is
2010 equivalent 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 /**
2026 Implements the range interface primitive $(D save) for built-in
2027 arrays. Due to the fact that nonmember functions can be called with
2028 the first argument using the dot notation, $(D array.save) is
2029 equivalent to $(D save(array)). The function does not duplicate the
2030 content 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 /**
2046 Implements the range interface primitive $(D popFront) for built-in
2047 arrays. Due to the fact that nonmember functions can be called with
2048 the first argument using the dot notation, $(D array.popFront) is
2049 equivalent to $(D popFront(array)). For $(GLOSSARY narrow strings),
2050 $(D popFront) automatically advances to the next $(GLOSSARY code
2051 point).
2052 */
2053 void popFront(T)(ref T[] a) @safe pure nothrow @nogc
2054 if (!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 
2068 version (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
2076 void popFront(C)(ref C[] str) @trusted pure nothrow
2077 if (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 /**
2168 Implements the range interface primitive $(D popBack) for built-in
2169 arrays. Due to the fact that nonmember functions can be called with
2170 the first argument using the dot notation, $(D array.popBack) is
2171 equivalent to $(D popBack(array)). For $(GLOSSARY narrow strings), $(D
2172 popFront) automatically eliminates the last $(GLOSSARY code point).
2173 */
2174 void popBack(T)(ref T[] a) @safe pure nothrow @nogc
2175 if (!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 
2189 version (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
2197 void popBack(T)(ref T[] a) @safe pure
2198 if (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 /**
2234 Implements the range interface primitive $(D front) for built-in
2235 arrays. Due to the fact that nonmember functions can be called with
2236 the first argument using the dot notation, $(D array.front) is
2237 equivalent to $(D front(array)). For $(GLOSSARY narrow strings), $(D
2238 front) automatically returns the first $(GLOSSARY code point) as _a $(D
2239 dchar).
2240 */
2241 @property ref T front(T)(T[] a) @safe pure nothrow @nogc
2242 if (!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
2271 if (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 /**
2280 Implements the range interface primitive $(D back) for built-in
2281 arrays. Due to the fact that nonmember functions can be called with
2282 the first argument using the dot notation, $(D array.back) is
2283 equivalent to $(D back(array)). For $(GLOSSARY narrow strings), $(D
2284 back) automatically returns the last $(GLOSSARY code point) as _a $(D
2285 dchar).
2286 */
2287 @property ref T back(T)(T[] a) @safe pure nothrow @nogc
2288 if (!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
2315 if (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