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