2 This module is a submodule of $(MREF std, range).
4 It defines the bidirectional and forward range primitives for arrays:
5 $(LREF empty), $(LREF front), $(LREF back), $(LREF popFront), $(LREF popBack) and $(LREF save).
7 It provides basic range functionality by defining several templates for testing
8 whether a given object is a range, and what kind of range it is:
10 $(SCRIPT inhibitQuickIndex = 1;)
13 $(TR $(TD $(LREF isInputRange))
14 $(TD Tests if something is an $(I input range), defined to be
15 something from which one can sequentially read data using the
16 primitives `front`, `popFront`, and `empty`.
18 $(TR $(TD $(LREF isOutputRange))
19 $(TD Tests if something is an $(I output range), defined to be
20 something to which one can sequentially write data using the
21 $(LREF put) primitive.
23 $(TR $(TD $(LREF isForwardRange))
24 $(TD Tests if something is a $(I forward range), defined to be an
25 input range with the additional capability that one can save one's
26 current position with the `save` primitive, thus allowing one to
27 iterate over the same range multiple times.
29 $(TR $(TD $(LREF isBidirectionalRange))
30 $(TD Tests if something is a $(I bidirectional range), that is, a
31 forward range that allows reverse traversal using the primitives $(D
34 $(TR $(TD $(LREF isRandomAccessRange))
35 $(TD Tests if something is a $(I random access range), which is a
36 bidirectional range that also supports the array subscripting
37 operation via the primitive `opIndex`.
41 It also provides number of templates that test for various range capabilities:
44 $(TR $(TD $(LREF hasMobileElements))
45 $(TD Tests if a given range's elements can be moved around using the
46 primitives `moveFront`, `moveBack`, or `moveAt`.
48 $(TR $(TD $(LREF ElementType))
49 $(TD Returns the element type of a given range.
51 $(TR $(TD $(LREF ElementEncodingType))
52 $(TD Returns the encoding element type of a given range.
54 $(TR $(TD $(LREF hasSwappableElements))
55 $(TD Tests if a range is a forward range with swappable elements.
57 $(TR $(TD $(LREF hasAssignableElements))
58 $(TD Tests if a range is a forward range with mutable elements.
60 $(TR $(TD $(LREF hasLvalueElements))
61 $(TD Tests if a range is a forward range with elements that can be
62 passed by reference and have their address taken.
64 $(TR $(TD $(LREF hasLength))
65 $(TD Tests if a given range has the `length` attribute.
67 $(TR $(TD $(LREF isInfinite))
68 $(TD Tests if a given range is an $(I infinite range).
70 $(TR $(TD $(LREF hasSlicing))
71 $(TD Tests if a given range supports the array slicing operation $(D
76 Finally, it includes some convenience functions for manipulating ranges:
79 $(TR $(TD $(LREF popFrontN))
80 $(TD Advances a given range by up to $(I n) elements.
82 $(TR $(TD $(LREF popBackN))
83 $(TD Advances a given bidirectional range from the right by up to
86 $(TR $(TD $(LREF popFrontExactly))
87 $(TD Advances a given range by up exactly $(I n) elements.
89 $(TR $(TD $(LREF popBackExactly))
90 $(TD Advances a given bidirectional range from the right by exactly
93 $(TR $(TD $(LREF moveFront))
94 $(TD Removes the front element of a range.
96 $(TR $(TD $(LREF moveBack))
97 $(TD Removes the back element of a bidirectional range.
99 $(TR $(TD $(LREF moveAt))
100 $(TD Removes the $(I i)'th element of a random-access range.
102 $(TR $(TD $(LREF walkLength))
103 $(TD Computes the length of any range in O(n) time.
105 $(TR $(TD $(LREF put))
106 $(TD Outputs element `e` to a range.
110 Source: $(PHOBOSSRC std/range/primitives.d)
112 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
114 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, and
115 $(HTTP jmdavisprog.com, Jonathan M Davis). Credit for some of the ideas
116 in building this module goes to
117 $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
119 module std
.range
.primitives
;
124 Returns `true` if `R` is an input range. An input range must
125 define the primitives `empty`, `popFront`, and `front`. The
126 following code should compile for any input range.
129 R r; // can define a range object
130 if (r.empty) {} // can test for empty
131 r.popFront(); // can invoke popFront()
132 auto h = r.front; // can get the front of the range of non-void type
135 The following are rules of input ranges are assumed to hold true in all
136 Phobos code. These rules are not checkable at compile-time, so not conforming
137 to these rules when writing ranges or range based code will result in
141 $(LI `r.empty` returns `false` if and only if there is more data
142 available in the range.)
143 $(LI `r.empty` evaluated multiple times, without calling
144 `r.popFront`, or otherwise mutating the range object or the
145 underlying data, yields the same result for every evaluation.)
146 $(LI `r.front` returns the current element in the range.
147 It may return by value or by reference.)
148 $(LI `r.front` can be legally evaluated if and only if evaluating
149 `r.empty` has, or would have, equaled `false`.)
150 $(LI `r.front` evaluated multiple times, without calling
151 `r.popFront`, or otherwise mutating the range object or the
152 underlying data, yields the same result for every evaluation.)
153 $(LI `r.popFront` advances to the next element in the range.)
154 $(LI `r.popFront` can be called if and only if evaluating `r.empty`
155 has, or would have, equaled `false`.)
158 Also, note that Phobos code assumes that the primitives `r.front` and
159 `r.empty` are $(BIGOH 1) time complexity wise or "cheap" in terms of
160 running time. $(BIGOH) statements in the documentation of range functions
161 are made with this assumption.
164 The header of $(MREF std,range) for tutorials on ranges.
167 R = type to be tested
168 E = if present, the elements of the range must be
169 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
173 `true` if R is an input range (possibly with element type `E`), `false` if not
175 enum bool isInputRange(R
) =
176 is(typeof(R
.init
) == R
)
177 && is(typeof((R r
) { return r
.empty
; } (R
.init
)) == bool)
178 && (is(typeof((return ref R r
) => r
.front
)) ||
is(typeof(ref (return ref R r
) => r
.front
)))
179 && !is(typeof((R r
) { return r
.front
; } (R
.init
)) == void)
180 && is(typeof((R r
) => r
.popFront
));
183 enum bool isInputRange(R
, E
) =
184 .isInputRange
!R
&& isQualifierConvertible
!(ElementType
!R
, E
);
193 @property bool empty();
194 @property int front();
196 static assert(!isInputRange
!A
);
197 static assert( isInputRange
!B
);
198 static assert( isInputRange
!(int[]));
199 static assert( isInputRange
!(char[]));
200 static assert(!isInputRange
!(char[4]));
201 static assert( isInputRange
!(inout(int)[]));
202 static assert(!isInputRange
!(int[], string
));
203 static assert( isInputRange
!(int[], int));
204 static assert( isInputRange
!(int[], const int));
205 static assert(!isInputRange
!(int[], immutable int));
207 static assert(!isInputRange
!(const(int)[], int));
208 static assert( isInputRange
!(const(int)[], const int));
209 static assert(!isInputRange
!(const(int)[], immutable int));
211 static assert(!isInputRange
!(immutable(int)[], int));
212 static assert( isInputRange
!(immutable(int)[], const int));
213 static assert( isInputRange
!(immutable(int)[], immutable int));
215 static struct NotDefaultConstructible
219 @property bool empty();
220 @property int front();
222 static assert( isInputRange
!NotDefaultConstructible
);
224 static struct NotDefaultConstructibleOrCopyable
229 @property bool empty();
230 @property int front();
232 static assert(isInputRange
!NotDefaultConstructibleOrCopyable
);
234 static struct Frontless
237 @property bool empty();
239 static assert(!isInputRange
!Frontless
);
241 static struct VoidFront
244 @property bool empty();
247 static assert(!isInputRange
!VoidFront
);
249 // https://issues.dlang.org/show_bug.cgi?id=16034
258 assert(isInputRange
!(One
[]));
263 import std
.algorithm
.comparison
: equal
;
270 @property int value() { return impl
._front
; }
276 @property bool empty() { return _front
>= 3; }
277 @property auto front() { return Front(&this); }
278 void popFront() { _front
++; }
282 static assert(isInputRange
!R
);
283 assert(r
.equal([ 0, 1, 2 ]));
287 puts the whole raw element `e` into `r`. doPut will not attempt to
288 iterate, slice or transcode `e` in any way shape or form. It will $(B only)
289 call the correct primitive (`r.put(e)`, $(D r.front = e) or
292 This can be important when `e` needs to be placed in `r` unchanged.
293 Furthermore, it can be useful when working with `InputRange`s, as doPut
294 guarantees that no more than a single element will be placed.
296 private void doPut(R
, E
)(ref R r
, auto ref E e
)
298 static if (is(PointerTarget
!R
== struct))
299 enum usingPut
= hasMember
!(PointerTarget
!R
, "put");
301 enum usingPut
= hasMember
!(R
, "put");
305 static assert(is(typeof(r
.put(e
))),
306 "Cannot put a " ~ E
.stringof
~ " into a " ~ R
.stringof
~ ".");
309 else static if (isNarrowString
!R
&& is(const(E
) == const(typeof(r
[0]))))
311 // one character, we can put it
315 else static if (isNarrowString
!R
&& isNarrowString
!E
&& is(typeof(r
[] = e
)))
317 // slice assign. Note that this is a duplicate from put, but because
318 // putChar uses doPut exclusively, we have to copy it here.
319 immutable len
= e
.length
;
323 else static if (isInputRange
!R
)
325 static assert(is(typeof(r
.front
= e
)),
326 "Cannot put a " ~ E
.stringof
~ " into a " ~ R
.stringof
~ ".");
330 else static if (is(typeof(r(e
))))
337 "Cannot put a " ~ E
.stringof
~ " into a " ~ R
.stringof
~ ".");
343 static assert(!isNativeOutputRange
!(int, int));
344 static assert( isNativeOutputRange
!(int[], int));
345 static assert(!isNativeOutputRange
!(int[][], int));
347 static assert(!isNativeOutputRange
!(int, int[]));
348 static assert(!isNativeOutputRange
!(int[], int[]));
349 static assert( isNativeOutputRange
!(int[][], int[]));
351 static assert(!isNativeOutputRange
!(int, int[][]));
352 static assert(!isNativeOutputRange
!(int[], int[][]));
353 static assert(!isNativeOutputRange
!(int[][], int[][]));
355 static assert(!isNativeOutputRange
!(int[4], int));
356 static assert( isNativeOutputRange
!(int[4][], int)); //Scary!
357 static assert( isNativeOutputRange
!(int[4][], int[4]));
359 static assert( isNativeOutputRange
!( char[], char));
360 static assert(!isNativeOutputRange
!( char[], dchar));
361 static assert( isNativeOutputRange
!(dchar[], char));
362 static assert( isNativeOutputRange
!(dchar[], dchar));
367 Outputs `e` to `r`. The exact effect is dependent upon the two
368 types. Several cases are accepted, as described below. The code snippets
369 are attempted in order, and the first to compile "wins" and gets
372 In this table "doPut" is a method that places `e` into `r`, using the
373 correct primitive: `r.put(e)` if `R` defines `put`, $(D r.front = e)
374 if `r` is an input range (followed by `r.popFront()`), or `r(e)`
384 $(TD `R` specifically accepts an `E`.)
387 $(TD $(D r.doPut([ e ]);))
388 $(TD `R` specifically accepts an `E[]`.)
391 $(TD `r.putChar(e);`)
392 $(TD `R` accepts some form of string or character. put will
393 transcode the character `e` accordingly.)
396 $(TD $(D for (; !e.empty; e.popFront()) put(r, e.front);))
397 $(TD Copying range `E` into `R`.)
401 Tip: `put` should $(I not) be used "UFCS-style", e.g. `r.put(e)`.
402 Doing this may call `R.put` directly, by-passing any transformation
403 feature provided by `Range.put`. $(D put(r, e)) is prefered.
405 void put(R
, E
)(ref R r
, E e
)
407 //First level: simply straight up put.
408 static if (is(typeof(doPut(r
, e
))))
412 //Optional optimization block for straight up array to array copy.
413 else static if (isDynamicArray
!R
&&
414 !isAutodecodableString
!R
&&
416 is(typeof(r
[] = e
[])))
418 immutable len
= e
.length
;
423 else static if (is(typeof(doPut(r
, [e
]))) && !isDynamicArray
!R
)
431 doPut(r
, (ref e
) @trusted { return (&e
)[0 .. 1]; }(e
));
433 //special case for char to string.
434 else static if (isSomeChar
!E
&& is(typeof(putChar(r
, e
))))
438 //Extract each element from the range
439 //We can use "put" here, so we can recursively test a RoR of E.
440 else static if (isInputRange
!E
&& is(typeof(put(r
, e
.front
))))
442 //Special optimization: If E is a narrow string, and r accepts characters no-wider than the string's
443 //Then simply feed the characters 1 by 1.
444 static if (isAutodecodableString
!E
&& !isAggregateType
!E
&& (
445 (is(E
: const char[]) && is(typeof(doPut(r
, char.max
))) && !is(typeof(doPut(r
, dchar.max
))) &&
446 !is(typeof(doPut(r
, wchar.max
)))) ||
447 (is(E
: const wchar[]) && is(typeof(doPut(r
, wchar.max
))) && !is(typeof(doPut(r
, dchar.max
)))) ) )
454 for (; !e
.empty
; e
.popFront())
460 static assert(false, "Cannot put a " ~ E
.stringof
~ " into a " ~ R
.stringof
~ ".");
465 * When an output range's `put` method only accepts elements of type
466 * `T`, use the global `put` to handle outputting a `T[]` to the range
471 import std
.traits
: isSomeChar
;
477 void put(C
)(C c
) if (isSomeChar
!C
)
482 static assert(isOutputRange
!(A
, char));
486 assert(a
.data
== "Hello");
490 * `put` treats dynamic arrays as array slices, and will call `popFront`
491 * on the slice after an element has been copied.
493 * Be sure to save the position of the array before calling `put`.
495 @safe pure nothrow unittest
497 int[] a
= [1, 2, 3], b
= [10, 20];
500 assert(c
== [10, 20, 3]);
501 // at this point, a was advanced twice, so it only contains
502 // its last element while c represents the whole array
507 * It's also possible to `put` any width strings or characters into narrow
508 * strings -- put does the conversion for you.
510 * Note that putting the same width character as the target buffer type is
511 * `nothrow`, but transcoding can throw a $(REF UTFException, std, utf).
515 // the elements must be mutable, so using string or const(char)[]
517 char[] s1
= new char[13];
519 put(r1
, "Hello, World!"w
);
520 assert(s1
== "Hello, World!");
523 @safe pure nothrow unittest
525 // same thing, just using same character width.
526 char[] s1
= new char[13];
528 put(r1
, "Hello, World!");
529 assert(s1
== "Hello, World!");
533 @safe pure nothrow @nogc unittest
535 static struct R() { void put(scope const(char)[]) {} }
540 //Helper function to handle chars as quickly and as elegantly as possible
541 //Assumes r.put(e)/r(e) has already been tested
542 private void putChar(R
, E
)(ref R r
, E e
)
545 // https://issues.dlang.org/show_bug.cgi?id=9186: Can't use (E[]).init
546 enum csCond
= is(typeof(doPut(r
, (){ ref const( char)[] cstringInit(); return cstringInit(); }())));
547 enum wsCond
= is(typeof(doPut(r
, (){ ref const(wchar)[] wstringInit(); return wstringInit(); }())));
548 enum dsCond
= is(typeof(doPut(r
, (){ ref const(dchar)[] dstringInit(); return dstringInit(); }())));
550 //Use "max" to avoid static type demotion
551 enum ccCond
= is(typeof(doPut(r
, char.max
)));
552 enum wcCond
= is(typeof(doPut(r
, wchar.max
)));
553 //enum dcCond = is(typeof(doPut(r, dchar.max)));
555 //Fast transform a narrow char into a wider string
556 static if ((wsCond
&& E
.sizeof
< wchar.sizeof
) ||
(dsCond
&& E
.sizeof
< dchar.sizeof
))
558 enum w
= wsCond
&& E
.sizeof
< wchar.sizeof
;
559 Select
!(w
, wchar, dchar) c
= e
;
560 typeof(c
)[1] arr
= [c
];
563 //Encode a wide char into a narrower string
564 else static if (wsCond || csCond
)
566 import std
.utf
: encode
;
567 /+static+/ Select
!(wsCond
, wchar[2], char[4]) buf
; //static prevents purity.
568 doPut(r
, buf
[0 .. encode(buf
, e
)]);
570 //Slowly encode a wide char into a series of narrower chars
571 else static if (wcCond || ccCond
)
573 import std
.encoding
: encode
;
574 alias C
= Select
!(wcCond
, wchar, char);
579 static assert(false, "Cannot put a " ~ E
.stringof
~ " into a " ~ R
.stringof
~ ".");
585 auto f
= delegate (const(char)[]) {};
586 putChar(f
, cast(dchar)'a');
592 static struct R() { void put(scope const(char)[]) {} }
600 static assert(!isInputRange
!(A
));
611 int[] a
= new int[10];
613 static assert(isInputRange
!(typeof(a
)));
619 void myprint(scope const(char)[] s
) { }
626 int[] a
= new int[10];
627 static assert(!__traits(compiles
, put(a
, 1.0L)));
629 assert(a
.length
== 9);
633 * a[0] = "ABC"[0]; // OK
634 * put(a, "ABC"); // OK
637 assert(a
.length
== 6);
642 char[] a
= new char[10];
643 static assert(!__traits(compiles
, put(a
, 1.0L)));
644 static assert(!__traits(compiles
, put(a
, 1)));
645 //char[] is now an output range for char, wchar, dchar, and ranges of such.
646 static assert(__traits(compiles
, putChar(a
, 'a')));
647 static assert(__traits(compiles
, put(a
, wchar('a'))));
648 static assert(__traits(compiles
, put(a
, dchar('a'))));
649 static assert(__traits(compiles
, put(a
, "ABC")));
650 static assert(__traits(compiles
, put(a
, "ABC"w
)));
651 static assert(__traits(compiles
, put(a
, "ABC"d
)));
656 // attempt putting into narrow strings by transcoding
657 char[] a
= new char[10];
660 assert(b
[0 .. 3] == "ABC");
661 assert(a
.length
== 7);
665 assert(b
[0 .. 2] == "λ");
666 assert(a
.length
== 8);
670 assert(b
[0 .. 3] == "ABC");
671 assert(a
.length
== 7);
675 assert(b
[0 .. 4] == "𐐷");
676 assert(a
.length
== 6);
678 wchar[] aw
= new wchar[10];
681 assert(bw
[0 .. 3] == "ABC"w
);
682 assert(aw
.length
== 7);
686 assert(bw
[0 .. 1] == "λ"w
);
687 assert(aw
.length
== 9);
691 assert(bw
[0 .. 3] == "ABC"w
);
692 assert(aw
.length
== 7);
696 assert(bw
[0 .. 2] == "𐐷"w
);
697 assert(aw
.length
== 8);
700 put(aw
, "𐐷"); // try transcoding from char[]
701 assert(bw
[0 .. 2] == "𐐷"w
);
702 assert(aw
.length
== 8);
707 int[][] a
= new int[][10];
708 int[] b
= new int[10];
711 assert(b
.length
== 9);
713 assert(a
.length
== 9);
714 static assert(!__traits(compiles
, put(a
, c
)));
719 int[][] a
= new int[][](3);
723 assert(aa
== [[], []]);
724 assert(a
== [[1], [], []]);
729 assert(a
== [[2], [2], [2]]);
734 // Test fix for bug 7476.
735 struct LockingTextWriter
742 @property bool empty() const { return end
; }
743 @property dchar front(){ return 'a'; }
744 void popFront(){ end
= true; }
753 import std
.conv
: to
;
754 import std
.meta
: AliasSeq
;
755 import std
.typecons
: tuple
;
757 static struct PutC(C
)
760 void put(const(C
) c
) { result
~= to
!string((&c
)[0 .. 1]); }
762 static struct PutS(C
)
765 void put(const(C
)[] s
) { result
~= to
!string(s
); }
767 static struct PutSS(C
)
770 void put(const(C
)[][] ss
)
773 result
~= to
!string(s
);
778 putChar(p
, cast(dchar)'a');
781 static foreach (SC
; AliasSeq
!(char, wchar, dchar))
785 immutable(SC
)[] s
= "日本語!";
786 immutable(SC
)[][] ss
= ["日本語", "が", "好き", "ですか", "?"];
789 static foreach (TC
; AliasSeq
!(char, wchar, dchar))
791 //Testing PutC and PutS
792 static foreach (Type
; AliasSeq
!(PutC
!TC
, PutS
!TC
))
795 auto sink
= new Type();
797 //Testing put and sink
798 foreach (value
; tuple(type
, sink
))
801 assert(value
.result
== "I");
803 assert(value
.result
== "I♥");
805 assert(value
.result
== "I♥日本語!");
807 assert(value
.result
== "I♥日本語!日本語が好きですか?");
816 static struct CharRange
821 ref char front() return @property
827 put(c
, cast(dchar)'H');
831 // https://issues.dlang.org/show_bug.cgi?id=9823
835 void delegate(const(char)[]) dg
= (s
) { r
= s
; };
840 // https://issues.dlang.org/show_bug.cgi?id=10571
843 import std
.format
.write
: formattedWrite
;
845 formattedWrite((scope const(char)[] s
) { buf
~= s
; }, "%s", "hello");
846 assert(buf
== "hello");
851 import std
.format
.write
: formattedWrite
;
852 import std
.meta
: AliasSeq
;
859 void put(const(C
)[]){}
867 void opCall(const(C
)[]){}
872 auto front()@property{return C
.init
;}
873 void front(C
)@property{}
879 auto front()@property{return C
[].init
;}
880 void front(const(C
)[])@property{}
885 static foreach (C
; AliasSeq
!(char, wchar, dchar))
887 formattedWrite((C c
){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
888 formattedWrite((const(C
)[]){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
889 formattedWrite(PutC
!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
890 formattedWrite(PutS
!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
893 formattedWrite(callC
, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
894 formattedWrite(callS
, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
895 formattedWrite(FrontC
!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
896 formattedWrite(FrontS
!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
898 formattedWrite((dchar[]).init
, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c
, "a"w
, "a"d
);
903 Returns `true` if `R` is a native output range for elements of type
904 `E`. An output range is defined functionally as a range that
905 supports the operation $(D doPut(r, e)) as defined above. if $(D doPut(r, e))
906 is valid, then `put(r,e)` will have the same behavior.
908 The two guarantees isNativeOutputRange gives over the larger `isOutputRange`
910 1: `e` is $(B exactly) what will be placed (not `[e]`, for example).
911 2: if `E` is a non $(empty) `InputRange`, then placing `e` is
912 guaranteed to not overflow the range.
914 package(std
) enum bool isNativeOutputRange(R
, E
) =
915 is(typeof(doPut(lvalueOf
!R
, lvalueOf
!E
)));
919 int[] r
= new int[](4);
920 static assert(isInputRange
!(int[]));
921 static assert( isNativeOutputRange
!(int[], int));
922 static assert(!isNativeOutputRange
!(int[], int[]));
923 static assert( isOutputRange
!(int[], int[]));
926 put(r
, 1); //guaranteed to succeed
928 put(r
, [1, 2]); //May actually error out.
932 Returns `true` if `R` is an output range for elements of type
933 `E`. An output range is defined functionally as a range that
934 supports the operation $(D put(r, e)) as defined above.
937 The header of $(MREF std,range) for tutorials on ranges.
939 enum bool isOutputRange(R
, E
) =
940 is(typeof(put(lvalueOf
!R
, lvalueOf
!E
)));
945 void myprint(scope const(char)[] s
) { }
946 static assert(isOutputRange
!(typeof(&myprint
), char));
948 static assert( isOutputRange
!(char[], char));
949 static assert( isOutputRange
!(dchar[], wchar));
950 static assert( isOutputRange
!(dchar[], dchar));
956 import std
.stdio
: writeln
;
958 auto app
= appender
!string();
960 static assert( isOutputRange
!(Appender
!string
, string
));
961 static assert( isOutputRange
!(Appender
!string
*, string
));
962 static assert(!isOutputRange
!(Appender
!string
, int));
963 static assert( isOutputRange
!(wchar[], wchar));
964 static assert( isOutputRange
!(dchar[], char));
965 static assert( isOutputRange
!(dchar[], string
));
966 static assert( isOutputRange
!(dchar[], wstring
));
967 static assert( isOutputRange
!(dchar[], dstring
));
969 static assert(!isOutputRange
!(const(int)[], int));
970 static assert(!isOutputRange
!(inout(int)[], int));
975 Returns `true` if `R` is a forward range. A forward range is an
976 input range `r` that can save "checkpoints" by saving `r.save`
977 to another value of type `R`. Notable examples of input ranges that
978 are $(I not) forward ranges are file/socket ranges; copying such a
979 range will not save the position in the stream, and they most likely
980 reuse an internal buffer as the entire stream does not sit in
981 memory. Subsequently, advancing either the original or the copy will
982 advance the stream, so the copies are not independent.
984 The following code should compile for any forward range.
987 static assert(isInputRange!R);
990 static assert(is(typeof(s1) == R));
993 Saving a range is not duplicating it; in the example above, `r1`
994 and `r2` still refer to the same underlying data. They just
995 navigate that data independently.
997 The semantics of a forward range (not checkable during compilation)
998 are the same as for an input range, with the additional requirement
999 that backtracking must be possible by saving a copy of the range
1000 object with `save` and using it later.
1002 `save` behaves in many ways like a copy constructor, and its
1003 implementation typically is done using copy construction.
1005 The existence of a copy constructor, however, does not imply
1006 the range is a forward range. For example, a range that reads
1007 from a TTY consumes its input and cannot save its place and
1008 read it again, and so cannot be a forward range and cannot
1009 have a `save` function.
1013 The header of $(MREF std,range) for tutorials on ranges.
1016 R = type to be tested
1017 E = if present, the elements of the range must be
1018 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
1022 `true` if R is a forward range (possibly with element type `E`), `false` if not
1024 enum bool isForwardRange(R
) = isInputRange
!R
1025 && is(typeof((R r
) { return r
.save
; } (R
.init
)) == R
);
1028 enum bool isForwardRange(R
, E
) =
1029 .isForwardRange
!R
&& isQualifierConvertible
!(ElementType
!R
, E
);
1034 static assert(!isForwardRange
!(int));
1035 static assert( isForwardRange
!(int[]));
1036 static assert( isForwardRange
!(inout(int)[]));
1038 static assert( isForwardRange
!(int[], const int));
1039 static assert(!isForwardRange
!(int[], immutable int));
1041 static assert(!isForwardRange
!(const(int)[], int));
1042 static assert( isForwardRange
!(const(int)[], const int));
1043 static assert(!isForwardRange
!(const(int)[], immutable int));
1045 static assert(!isForwardRange
!(immutable(int)[], int));
1046 static assert( isForwardRange
!(immutable(int)[], const int));
1047 static assert( isForwardRange
!(immutable(int)[], immutable int));
1055 int front() { return 0;}
1057 bool empty() { return false; }
1058 R14544
save() {return this;}
1061 static assert( isForwardRange
!R14544
);
1065 Returns `true` if `R` is a bidirectional range. A bidirectional
1066 range is a forward range that also offers the primitives `back` and
1067 `popBack`. The following code should compile for any bidirectional
1070 The semantics of a bidirectional range (not checkable during
1071 compilation) are assumed to be the following (`r` is an object of
1074 $(UL $(LI `r.back` returns (possibly a reference to) the last
1075 element in the range. Calling `r.back` is allowed only if calling
1076 `r.empty` has, or would have, returned `false`.))
1079 The header of $(MREF std,range) for tutorials on ranges.
1082 R = type to be tested
1083 E = if present, the elements of the range must be
1084 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
1088 `true` if R is a bidirectional range (possibly with element type `E`), `false` if not
1090 enum bool isBidirectionalRange(R
) = isForwardRange
!R
1091 && is(typeof((R r
) => r
.popBack
))
1092 && (is(typeof((return ref R r
) => r
.back
)) ||
is(typeof(ref (return ref R r
) => r
.back
)))
1093 && is(typeof(R
.init
.back
.init
) == ElementType
!R
);
1096 enum bool isBidirectionalRange(R
, E
) =
1097 .isBidirectionalRange
!R
&& isQualifierConvertible
!(ElementType
!R
, E
);
1104 static assert(isForwardRange
!R
); // is forward range
1105 r
.popBack(); // can invoke popBack
1106 auto t
= r
.back
; // can get the back of the range
1108 static assert(is(typeof(t
) == typeof(w
))); // same type for front and back
1110 // Checking the element type
1111 static assert( isBidirectionalRange
!(int[], const int));
1112 static assert(!isBidirectionalRange
!(int[], immutable int));
1114 static assert(!isBidirectionalRange
!(const(int)[], int));
1115 static assert( isBidirectionalRange
!(const(int)[], const int));
1116 static assert(!isBidirectionalRange
!(const(int)[], immutable int));
1118 static assert(!isBidirectionalRange
!(immutable(int)[], int));
1119 static assert( isBidirectionalRange
!(immutable(int)[], const int));
1120 static assert( isBidirectionalRange
!(immutable(int)[], immutable int));
1129 @property bool empty();
1130 @property int front();
1134 @property bool empty();
1137 @property int front();
1139 @property int back();
1141 static assert(!isBidirectionalRange
!(A
));
1142 static assert(!isBidirectionalRange
!(B
));
1143 static assert( isBidirectionalRange
!(C
));
1144 static assert( isBidirectionalRange
!(int[]));
1145 static assert( isBidirectionalRange
!(char[]));
1146 static assert( isBidirectionalRange
!(inout(int)[]));
1150 Returns `true` if `R` is a random-access range. A random-access
1151 range is a bidirectional range that also offers the primitive $(D
1152 opIndex), OR an infinite forward range that offers `opIndex`. In
1153 either case, the range must either offer `length` or be
1154 infinite. The following code should compile for any random-access
1157 The semantics of a random-access range (not checkable during
1158 compilation) are assumed to be the following (`r` is an object of
1159 type `R`): $(UL $(LI `r.opIndex(n)` returns a reference to the
1160 `n`th element in the range.))
1162 Although `char[]` and `wchar[]` (as well as their qualified
1163 versions including `string` and `wstring`) are arrays, $(D
1164 isRandomAccessRange) yields `false` for them because they use
1165 variable-length encodings (UTF-8 and UTF-16 respectively). These types
1166 are bidirectional ranges only.
1169 The header of $(MREF std,range) for tutorials on ranges.
1172 R = type to be tested
1173 E = if present, the elements of the range must be
1174 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
1178 `true` if R is a random-access range (possibly with element type `E`), `false` if not
1180 enum bool isRandomAccessRange(R
) =
1181 is(typeof(lvalueOf
!R
[1]) == ElementType
!R
)
1182 && !(isAutodecodableString
!R
&& !isAggregateType
!R
)
1184 && (isBidirectionalRange
!R || isInfinite
!R
)
1185 && (hasLength
!R || isInfinite
!R
)
1186 && (isInfinite
!R ||
!is(typeof(lvalueOf
!R
[$ - 1]))
1187 ||
is(typeof(lvalueOf
!R
[$ - 1]) == ElementType
!R
));
1190 enum bool isRandomAccessRange(R
, E
) =
1191 .isRandomAccessRange
!R
&& isQualifierConvertible
!(ElementType
!R
, E
);
1196 import std
.traits
: isAggregateType
, isAutodecodableString
;
1200 // range is finite and bidirectional or infinite and forward.
1201 static assert(isBidirectionalRange
!R ||
1202 isForwardRange
!R
&& isInfinite
!R
);
1205 auto e
= r
[1]; // can index
1207 static assert(is(typeof(e
) == typeof(f
))); // same type for indexed and front
1208 static assert(!(isAutodecodableString
!R
&& !isAggregateType
!R
)); // narrow strings cannot be indexed as ranges
1209 static assert(hasLength
!R || isInfinite
!R
); // must have length or be infinite
1211 // $ must work as it does with arrays if opIndex works with $
1212 static if (is(typeof(r
[$])))
1214 static assert(is(typeof(f
) == typeof(r
[$])));
1216 // $ - 1 doesn't make sense with infinite ranges but needs to work
1217 // with finite ones.
1218 static if (!isInfinite
!R
)
1219 static assert(is(typeof(f
) == typeof(r
[$ - 1])));
1222 // Checking the element type
1223 static assert( isRandomAccessRange
!(int[], const int));
1224 static assert(!isRandomAccessRange
!(int[], immutable int));
1226 static assert(!isRandomAccessRange
!(const(int)[], int));
1227 static assert( isRandomAccessRange
!(const(int)[], const int));
1228 static assert(!isRandomAccessRange
!(const(int)[], immutable int));
1230 static assert(!isRandomAccessRange
!(immutable(int)[], int));
1231 static assert( isRandomAccessRange
!(immutable(int)[], const int));
1232 static assert( isRandomAccessRange
!(immutable(int)[], immutable int));
1241 @property bool empty();
1242 @property int front();
1247 @property bool empty();
1248 @property int front();
1250 @property int back();
1254 @property bool empty();
1256 @property int front();
1258 @property int back();
1260 ref int opIndex(uint);
1261 @property size_t
length();
1262 alias opDollar
= length
;
1263 //int opSlice(uint, uint);
1273 ref int opIndex(uint);
1275 alias opDollar
= length
;
1276 //int opSlice(uint, uint);
1278 static assert(!isRandomAccessRange
!(A
));
1279 static assert(!isRandomAccessRange
!(B
));
1280 static assert(!isRandomAccessRange
!(C
));
1281 static assert( isRandomAccessRange
!(D
));
1282 static assert( isRandomAccessRange
!(E
));
1283 static assert( isRandomAccessRange
!(int[]));
1284 static assert( isRandomAccessRange
!(inout(int)[]));
1289 // Test fix for bug 6935.
1294 @property bool empty() const { return false; }
1295 @property int front() const { return 0; }
1298 @property R
save() { return this; }
1300 @property int back() const { return 0; }
1303 int opIndex(size_t n
) const { return 0; }
1304 @property size_t
length() const { return 0; }
1305 alias opDollar
= length
;
1309 static assert(isInputRange
!R
);
1310 static assert(isForwardRange
!R
);
1311 static assert(isBidirectionalRange
!R
);
1312 static assert(isRandomAccessRange
!R
);
1313 static assert(isOutputRange
!(R
, int));
1317 Returns `true` iff `R` is an input range that supports the
1318 `moveFront` primitive, as well as `moveBack` and `moveAt` if it's a
1319 bidirectional or random access range. These may be explicitly implemented, or
1320 may work via the default behavior of the module level functions `moveFront`
1321 and friends. The following code should compile for any range
1322 with mobile elements.
1325 alias E = ElementType!R;
1327 static assert(isInputRange!R);
1328 static assert(is(typeof(moveFront(r)) == E));
1329 static if (isBidirectionalRange!R)
1330 static assert(is(typeof(moveBack(r)) == E));
1331 static if (isRandomAccessRange!R)
1332 static assert(is(typeof(moveAt(r, 0)) == E));
1335 enum bool hasMobileElements(R
) =
1337 && is(typeof(moveFront(lvalueOf
!R
)) == ElementType
!R
)
1338 && (!isBidirectionalRange
!R
1339 ||
is(typeof(moveBack(lvalueOf
!R
)) == ElementType
!R
))
1340 && (!isRandomAccessRange
!R
1341 ||
is(typeof(moveAt(lvalueOf
!R
, 0)) == ElementType
!R
));
1346 import std
.algorithm
.iteration
: map
;
1347 import std
.range
: iota
, repeat
;
1349 static struct HasPostblit
1354 auto nonMobile
= map
!"a"(repeat(HasPostblit
.init
));
1355 static assert(!hasMobileElements
!(typeof(nonMobile
)));
1356 static assert( hasMobileElements
!(int[]));
1357 static assert( hasMobileElements
!(inout(int)[]));
1358 static assert( hasMobileElements
!(typeof(iota(1000))));
1360 static assert( hasMobileElements
!( string
));
1361 static assert( hasMobileElements
!(dstring
));
1362 static assert( hasMobileElements
!( char[]));
1363 static assert( hasMobileElements
!(dchar[]));
1367 The element type of `R`. `R` does not have to be a range. The
1368 element type is determined as the type yielded by `r.front` for an
1369 object `r` of type `R`. For example, `ElementType!(T[])` is
1370 `T` if `T[]` isn't a narrow string; if it is, the element type is
1371 `dchar`. If `R` doesn't have `front`, `ElementType!R` is
1374 template ElementType(R
)
1376 static if (is(typeof(R
.init
.front
.init
) T
))
1377 alias ElementType
= T
;
1379 alias ElementType
= void;
1385 import std
.range
: iota
;
1387 // Standard arrays: returns the type of the elements of the array
1388 static assert(is(ElementType
!(int[]) == int));
1390 // Accessing .front retrieves the decoded dchar
1391 static assert(is(ElementType
!(char[]) == dchar)); // rvalue
1392 static assert(is(ElementType
!(dchar[]) == dchar)); // lvalue
1395 static assert(is(ElementType
!(string
) == dchar));
1396 static assert(is(ElementType
!(dstring
) == immutable(dchar)));
1398 // For ranges it gets the type of .front.
1399 auto range
= iota(0, 10);
1400 static assert(is(ElementType
!(typeof(range
)) == int));
1405 static assert(is(ElementType
!(byte[]) == byte));
1406 static assert(is(ElementType
!(wchar[]) == dchar)); // rvalue
1407 static assert(is(ElementType
!(wstring
) == dchar));
1412 enum XYZ
: string
{ a
= "foo" }
1413 auto x
= XYZ
.a
.front
;
1414 immutable char[3] a
= "abc";
1417 static assert(is(ElementType
!(XYZ
) == dchar));
1418 static assert(is(ElementType
!(typeof(a
)) == dchar));
1419 static assert(is(ElementType
!(typeof(i
)) == int));
1420 static assert(is(ElementType
!(typeof(buf
)) == void));
1421 static assert(is(ElementType
!(inout(int)[]) == inout(int)));
1422 static assert(is(ElementType
!(inout(int[])) == inout(int)));
1427 static assert(is(ElementType
!(int[5]) == int));
1428 static assert(is(ElementType
!(int[0]) == int));
1429 static assert(is(ElementType
!(char[5]) == dchar));
1430 static assert(is(ElementType
!(char[0]) == dchar));
1433 // https://issues.dlang.org/show_bug.cgi?id=11336
1438 this(this) @disable;
1440 static assert(is(ElementType
!(S
[]) == S
));
1443 // https://issues.dlang.org/show_bug.cgi?id=11401
1446 // ElementType should also work for non-@propety 'front'
1447 struct E
{ ushort id
; }
1450 E
front() { return E
.init
; }
1452 static assert(is(ElementType
!R
== E
));
1456 The encoding element type of `R`. For narrow strings (`char[]`,
1457 `wchar[]` and their qualified variants including `string` and
1458 `wstring`), `ElementEncodingType` is the character type of the
1459 string. For all other types, `ElementEncodingType` is the same as
1462 template ElementEncodingType(R
)
1464 static if (is(StringTypeOf
!R
) && is(R
: E
[], E
))
1465 alias ElementEncodingType
= E
;
1467 alias ElementEncodingType
= ElementType
!R
;
1473 import std
.range
: iota
;
1474 // internally the range stores the encoded type
1475 static assert(is(ElementEncodingType
!(char[]) == char));
1477 static assert(is(ElementEncodingType
!(wstring
) == immutable(wchar)));
1479 static assert(is(ElementEncodingType
!(byte[]) == byte));
1481 auto range
= iota(0, 10);
1482 static assert(is(ElementEncodingType
!(typeof(range
)) == int));
1487 static assert(is(ElementEncodingType
!(wchar[]) == wchar));
1488 static assert(is(ElementEncodingType
!(dchar[]) == dchar));
1489 static assert(is(ElementEncodingType
!(string
) == immutable(char)));
1490 static assert(is(ElementEncodingType
!(dstring
) == immutable(dchar)));
1491 static assert(is(ElementEncodingType
!(int[]) == int));
1496 enum XYZ
: string
{ a
= "foo" }
1497 auto x
= XYZ
.a
.front
;
1498 immutable char[3] a
= "abc";
1501 static assert(is(ElementType
!(XYZ
) : dchar));
1502 static assert(is(ElementEncodingType
!(char[]) == char));
1503 static assert(is(ElementEncodingType
!(string
) == immutable char));
1504 static assert(is(ElementType
!(typeof(a
)) : dchar));
1505 static assert(is(ElementType
!(typeof(i
)) == int));
1506 static assert(is(ElementEncodingType
!(typeof(i
)) == int));
1507 static assert(is(ElementType
!(typeof(buf
)) : void));
1509 static assert(is(ElementEncodingType
!(inout char[]) : inout(char)));
1514 static assert(is(ElementEncodingType
!(int[5]) == int));
1515 static assert(is(ElementEncodingType
!(int[0]) == int));
1516 static assert(is(ElementEncodingType
!(char[5]) == char));
1517 static assert(is(ElementEncodingType
!(char[0]) == char));
1521 Returns `true` if `R` is an input range and has swappable
1522 elements. The following code should compile for any range
1523 with swappable elements.
1527 static assert(isInputRange!R);
1528 swap(r.front, r.front);
1529 static if (isBidirectionalRange!R) swap(r.back, r.front);
1530 static if (isRandomAccessRange!R) swap(r[0], r.front);
1533 template hasSwappableElements(R
)
1535 import std
.algorithm
.mutation
: swap
;
1536 enum bool hasSwappableElements
= isInputRange
!R
1537 && is(typeof((ref R r
) => swap(r
.front
, r
.front
)))
1538 && (!isBidirectionalRange
!R
1539 ||
is(typeof((ref R r
) => swap(r
.back
, r
.front
))))
1540 && (!isRandomAccessRange
!R
1541 ||
is(typeof((ref R r
) => swap(r
[0], r
.front
))));
1547 static assert(!hasSwappableElements
!(const int[]));
1548 static assert(!hasSwappableElements
!(const(int)[]));
1549 static assert(!hasSwappableElements
!(inout(int)[]));
1550 static assert( hasSwappableElements
!(int[]));
1552 static assert(!hasSwappableElements
!( string
));
1553 static assert(!hasSwappableElements
!(dstring
));
1554 static assert(!hasSwappableElements
!( char[]));
1555 static assert( hasSwappableElements
!(dchar[]));
1559 Returns `true` if `R` is an input range and has mutable
1560 elements. The following code should compile for any range
1561 with assignable elements.
1565 static assert(isInputRange!R);
1567 static if (isBidirectionalRange!R) r.back = r.front;
1568 static if (isRandomAccessRange!R) r[0] = r.front;
1571 enum bool hasAssignableElements(R
) = isInputRange
!R
1572 && is(typeof(lvalueOf
!R
.front
= lvalueOf
!R
.front
))
1573 && (!isBidirectionalRange
!R
1574 ||
is(typeof(lvalueOf
!R
.back
= lvalueOf
!R
.back
)))
1575 && (!isRandomAccessRange
!R
1576 ||
is(typeof(lvalueOf
!R
[0] = lvalueOf
!R
.front
)));
1581 static assert(!hasAssignableElements
!(const int[]));
1582 static assert(!hasAssignableElements
!(const(int)[]));
1583 static assert( hasAssignableElements
!(int[]));
1584 static assert(!hasAssignableElements
!(inout(int)[]));
1586 static assert(!hasAssignableElements
!( string
));
1587 static assert(!hasAssignableElements
!(dstring
));
1588 static assert(!hasAssignableElements
!( char[]));
1589 static assert( hasAssignableElements
!(dchar[]));
1593 Tests whether the range `R` has lvalue elements. These are defined as
1594 elements that can be passed by reference and have their address taken.
1595 The following code should compile for any range with lvalue elements.
1597 void passByRef(ref ElementType!R stuff);
1599 static assert(isInputRange!R);
1601 static if (isBidirectionalRange!R) passByRef(r.back);
1602 static if (isRandomAccessRange!R) passByRef(r[0]);
1605 enum bool hasLvalueElements(R
) = isInputRange
!R
1606 && is(typeof(isLvalue(lvalueOf
!R
.front
)))
1607 && (!isBidirectionalRange
!R
1608 ||
is(typeof(isLvalue(lvalueOf
!R
.back
))))
1609 && (!isRandomAccessRange
!R
1610 ||
is(typeof(isLvalue(lvalueOf
!R
[0]))));
1612 /* Compile successfully if argument of type T is an lvalue
1614 private void isLvalue(T
)(T
)
1617 private void isLvalue(T
)(ref T
)
1623 import std
.range
: iota
, chain
;
1625 static assert( hasLvalueElements
!(int[]));
1626 static assert( hasLvalueElements
!(const(int)[]));
1627 static assert( hasLvalueElements
!(inout(int)[]));
1628 static assert( hasLvalueElements
!(immutable(int)[]));
1629 static assert(!hasLvalueElements
!(typeof(iota(3))));
1631 static assert(!hasLvalueElements
!( string
));
1632 static assert( hasLvalueElements
!(dstring
));
1633 static assert(!hasLvalueElements
!( char[]));
1634 static assert( hasLvalueElements
!(dchar[]));
1636 auto c
= chain([1, 2, 3], [4, 5, 6]);
1637 static assert( hasLvalueElements
!(typeof(c
)));
1643 struct S
{ immutable int value
; }
1644 static assert( isInputRange
!(S
[]));
1645 static assert( hasLvalueElements
!(S
[]));
1649 Yields `true` if `R` has a `length` member that returns a value of `size_t`
1650 type. `R` does not have to be a range. If `R` is a range, algorithms in the
1651 standard library are only guaranteed to support `length` with type `size_t`.
1653 Note that `length` is an optional primitive as no range must implement it. Some
1654 ranges do not store their length explicitly, some cannot compute it without
1655 actually exhausting the range (e.g. socket streams), and some other ranges may
1658 Although narrow string types (`char[]`, `wchar[]`, and their qualified
1659 derivatives) do define a `length` property, `hasLength` yields `false` for them.
1660 This is because a narrow string's length does not reflect the number of
1661 characters, but instead the number of encoding units, and as such is not useful
1662 with range-oriented algorithms. To use strings as random-access ranges with
1663 length, use $(REF representation, std, string) or $(REF byCodeUnit, std, utf).
1665 template hasLength(R
)
1667 static if (is(typeof(((R
* r
) => r
.length
)(null)) Length
))
1668 enum bool hasLength
= is(Length
== size_t
) &&
1669 !(isAutodecodableString
!R
&& !isAggregateType
!R
);
1671 enum bool hasLength
= false;
1677 static assert(!hasLength
!(char[]));
1678 static assert( hasLength
!(int[]));
1679 static assert( hasLength
!(inout(int)[]));
1681 struct A
{ size_t
length() { return 0; } }
1682 struct B
{ @property size_t
length() { return 0; } }
1683 static assert( hasLength
!(A
));
1684 static assert( hasLength
!(B
));
1687 // test combinations which are invalid on some platforms
1690 struct A
{ ulong length
; }
1691 struct B
{ @property uint length() { return 0; } }
1693 static if (is(size_t
== uint))
1695 static assert(!hasLength
!(A
));
1696 static assert(hasLength
!(B
));
1698 else static if (is(size_t
== ulong))
1700 static assert(hasLength
!(A
));
1701 static assert(!hasLength
!(B
));
1705 // test combinations which are invalid on all platforms
1708 struct A
{ long length
; }
1709 struct B
{ int length
; }
1710 struct C
{ ubyte length
; }
1711 struct D
{ char length
; }
1712 static assert(!hasLength
!(A
));
1713 static assert(!hasLength
!(B
));
1714 static assert(!hasLength
!(C
));
1715 static assert(!hasLength
!(D
));
1719 Returns `true` if `R` is an infinite input range. An
1720 infinite input range is an input range that has a statically-defined
1721 enumerated member called `empty` that is always `false`,
1725 struct MyInfiniteRange
1727 enum bool empty = false;
1733 template isInfinite(R
)
1735 static if (isInputRange
!R
&& __traits(compiles
, { enum e
= R
.empty
; }))
1736 enum bool isInfinite
= !R
.empty
;
1738 enum bool isInfinite
= false;
1744 import std
.range
: Repeat
;
1745 static assert(!isInfinite
!(int[]));
1746 static assert( isInfinite
!(Repeat
!(int)));
1750 Returns `true` if `R` offers a slicing operator with integral boundaries
1751 that returns a forward range type.
1753 For finite ranges, the result of `opSlice` must be of the same type as the
1754 original range type. If the range defines `opDollar`, then it must support
1757 For infinite ranges, when $(I not) using `opDollar`, the result of `opSlice`
1758 may be a forward range of any type. However, when using `opDollar`, the result
1759 of `opSlice` must be of the same type as the original range type.
1761 The following expression must be true for `hasSlicing` to be `true`:
1765 && !(isAutodecodableString!R && !isAggregateType!R)
1766 && is(typeof((R r) { return r[1 .. 1].length; } (R.init)) == size_t)
1767 && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
1768 && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
1769 && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
1770 || is(typeof(lvalueOf!R[0 .. $ - 1]) == R))
1771 && is(typeof((ref R r)
1773 static assert(isForwardRange!(typeof(r[1 .. 2])));
1777 enum bool hasSlicing(R
) = isForwardRange
!R
1778 && !(isAutodecodableString
!R
&& !isAggregateType
!R
)
1779 && is(typeof((R r
) { return r
[1 .. 1].length
; } (R
.init
)) == size_t
)
1780 && (is(typeof(lvalueOf
!R
[1 .. 1]) == R
) || isInfinite
!R
)
1781 && (!is(typeof(lvalueOf
!R
[0 .. $])) ||
is(typeof(lvalueOf
!R
[0 .. $]) == R
))
1782 && (!is(typeof(lvalueOf
!R
[0 .. $])) || isInfinite
!R
1783 ||
is(typeof(lvalueOf
!R
[0 .. $ - 1]) == R
))
1784 && is(typeof((ref R r
)
1786 static assert(isForwardRange
!(typeof(r
[1 .. 2])));
1792 import std
.range
: takeExactly
;
1793 static assert( hasSlicing
!(int[]));
1794 static assert( hasSlicing
!(const(int)[]));
1795 static assert(!hasSlicing
!(const int[]));
1796 static assert( hasSlicing
!(inout(int)[]));
1797 static assert(!hasSlicing
!(inout int []));
1798 static assert( hasSlicing
!(immutable(int)[]));
1799 static assert(!hasSlicing
!(immutable int[]));
1800 static assert(!hasSlicing
!string
);
1801 static assert( hasSlicing
!dstring
);
1803 enum rangeFuncs
= "@property int front();" ~
1804 "void popFront();" ~
1805 "@property bool empty();" ~
1806 "@property auto save() { return this; }" ~
1807 "@property size_t length();";
1809 struct A
{ mixin(rangeFuncs
); int opSlice(size_t
, size_t
); }
1810 struct B
{ mixin(rangeFuncs
); B
opSlice(size_t
, size_t
); }
1811 struct C
{ mixin(rangeFuncs
); @disable this(); C
opSlice(size_t
, size_t
); }
1812 struct D
{ mixin(rangeFuncs
); int[] opSlice(size_t
, size_t
); }
1813 static assert(!hasSlicing
!(A
));
1814 static assert( hasSlicing
!(B
));
1815 static assert( hasSlicing
!(C
));
1816 static assert(!hasSlicing
!(D
));
1822 @property int front() { return 1; }
1823 @property InfOnes
save() { return this; }
1824 auto opSlice(size_t i
, size_t j
) { return takeExactly(this, j
- i
); }
1825 auto opSlice(size_t i
, Dollar d
) { return this; }
1828 Dollar
opDollar() const { return Dollar
.init
; }
1831 static assert(hasSlicing
!InfOnes
);
1834 // https://issues.dlang.org/show_bug.cgi?id=24348
1840 bool empty() => length
== 0;
1842 void popFront() { --length
; }
1843 Slice
save() => this;
1846 static struct InfZeros
1851 InfZeros
save() => this;
1853 Slice
opIndex(size_t
[2] bounds
)
1855 size_t i
= bounds
[0], j
= bounds
[1];
1856 size_t length
= i
<= j ? j
- i
: 0;
1857 return Slice(length
);
1860 size_t
[2] opSlice(size_t dim
: 0)(size_t i
, size_t j
) => [i
, j
];
1863 static assert(hasSlicing
!InfZeros
);
1867 This is a best-effort implementation of `length` for any kind of
1870 If `hasLength!Range`, simply returns `range.length` without
1871 checking `upTo` (when specified).
1873 Otherwise, walks the range through its length and returns the number
1874 of elements seen. Performes $(BIGOH n) evaluations of `range.empty`
1875 and `range.popFront()`, where `n` is the effective length of $(D
1878 The `upTo` parameter is useful to "cut the losses" in case
1879 the interest is in seeing whether the range has at least some number
1880 of elements. If the parameter `upTo` is specified, stops if $(D
1881 upTo) steps have been taken and returns `upTo`.
1883 Infinite ranges are compatible, provided the parameter `upTo` is
1884 specified, in which case the implementation simply returns upTo.
1886 auto walkLength(Range
)(Range range
)
1887 if (isInputRange
!Range
&& !isInfinite
!Range
)
1889 static if (hasLength
!Range
)
1890 return range
.length
;
1894 static if (autodecodeStrings
&& isNarrowString
!Range
)
1896 import std
.utf
: codeUnitLimit
;
1897 result
= range
.length
;
1898 foreach (const i
, const c
; range
)
1900 if (c
>= codeUnitLimit
!Range
)
1906 range
= range
[result
.. $];
1908 for ( ; !range
.empty
; range
.popFront() )
1914 auto walkLength(Range
)(Range range
, const size_t upTo
)
1915 if (isInputRange
!Range
)
1917 static if (hasLength
!Range
)
1918 return range
.length
;
1919 else static if (isInfinite
!Range
)
1924 static if (autodecodeStrings
&& isNarrowString
!Range
)
1926 import std
.utf
: codeUnitLimit
;
1927 result
= upTo
> range
.length ? range
.length
: upTo
;
1928 foreach (const i
, const c
; range
[0 .. result
])
1930 if (c
>= codeUnitLimit
!Range
)
1936 range
= range
[result
.. $];
1938 for ( ; result
< upTo
&& !range
.empty
; range
.popFront() )
1947 import std
.range
: iota
;
1949 assert(10.iota
.walkLength
== 10);
1950 // iota has a length function, and therefore the
1951 // doesn't have to be walked, and the upTo
1952 // parameter is ignored
1953 assert(10.iota
.walkLength(5) == 10);
1958 import std
.algorithm
.iteration
: filter
;
1959 import std
.range
: recurrence
, take
;
1962 int[] a
= [ 1, 2, 3 ];
1963 assert(walkLength(a
) == 3);
1964 assert(walkLength(a
, 0) == 3);
1965 assert(walkLength(a
, 2) == 3);
1966 assert(walkLength(a
, 4) == 3);
1969 auto b
= filter
!"true"([1, 2, 3, 4]);
1970 assert(b
.walkLength() == 4);
1971 assert(b
.walkLength(0) == 0);
1972 assert(b
.walkLength(2) == 2);
1973 assert(b
.walkLength(4) == 4);
1974 assert(b
.walkLength(6) == 4);
1977 auto fibs
= recurrence
!"a[n-1] + a[n-2]"(1, 1);
1978 assert(!__traits(compiles
, fibs
.walkLength()));
1979 assert(fibs
.take(10).walkLength() == 10);
1980 assert(fibs
.walkLength(55) == 55);
1984 `popFrontN` eagerly advances `r` itself (not a copy) up to `n` times
1985 (by calling `r.popFront`). `popFrontN` takes `r` by `ref`,
1986 so it mutates the original range. Completes in $(BIGOH 1) steps for ranges
1987 that support slicing and have length.
1988 Completes in $(BIGOH n) time for all other ranges.
1990 `popBackN` behaves the same as `popFrontN` but instead removes
1991 elements from the back of the (bidirectional) range instead of the front.
1994 How much `r` was actually advanced, which may be less than `n` if
1995 `r` did not have at least `n` elements.
1997 See_Also: $(REF drop, std, range), $(REF dropBack, std, range)
1999 size_t
popFrontN(Range
)(ref Range r
, size_t n
)
2000 if (isInputRange
!Range
)
2002 static if (hasLength
!Range
)
2004 n
= cast(size_t
) (n
< r
.length ? n
: r
.length
);
2007 static if (hasSlicing
!Range
&& is(typeof(r
= r
[n
.. $])))
2011 else static if (hasSlicing
!Range
&& hasLength
!Range
) //TODO: Remove once hasSlicing forces opDollar.
2013 r
= r
[n
.. r
.length
];
2017 static if (hasLength
!Range
)
2026 if (r
.empty
) return i
;
2035 size_t
popBackN(Range
)(ref Range r
, size_t n
)
2036 if (isBidirectionalRange
!Range
)
2038 static if (hasLength
!Range
)
2040 n
= cast(size_t
) (n
< r
.length ? n
: r
.length
);
2043 static if (hasSlicing
!Range
&& is(typeof(r
= r
[0 .. $ - n
])))
2047 else static if (hasSlicing
!Range
&& hasLength
!Range
) //TODO: Remove once hasSlicing forces opDollar.
2049 r
= r
[0 .. r
.length
- n
];
2053 static if (hasLength
!Range
)
2062 if (r
.empty
) return i
;
2073 int[] a
= [ 1, 2, 3, 4, 5 ];
2075 assert(a
== [ 3, 4, 5 ]);
2083 import std
.algorithm
.comparison
: equal
;
2084 import std
.range
: iota
;
2085 auto LL
= iota(1L, 7L);
2086 auto r
= popFrontN(LL
, 2);
2087 assert(equal(LL
, [3L, 4L, 5L, 6L]));
2094 int[] a
= [ 1, 2, 3, 4, 5 ];
2096 assert(a
== [ 1, 2, 3 ]);
2104 import std
.algorithm
.comparison
: equal
;
2105 import std
.range
: iota
;
2106 auto LL
= iota(1L, 7L);
2107 auto r
= popBackN(LL
, 2);
2108 assert(equal(LL
, [1L, 2L, 3L, 4L]));
2113 Eagerly advances `r` itself (not a copy) exactly `n` times (by
2114 calling `r.popFront`). `popFrontExactly` takes `r` by `ref`,
2115 so it mutates the original range. Completes in $(BIGOH 1) steps for ranges
2116 that support slicing, and have either length or are infinite.
2117 Completes in $(BIGOH n) time for all other ranges.
2119 Note: Unlike $(LREF popFrontN), `popFrontExactly` will assume that the
2120 range holds at least `n` elements. This makes `popFrontExactly`
2121 faster than `popFrontN`, but it also means that if `range` does
2122 not contain at least `n` elements, it will attempt to call `popFront`
2123 on an empty range, which is undefined behavior. So, only use
2124 `popFrontExactly` when it is guaranteed that `range` holds at least
2127 `popBackExactly` will behave the same but instead removes elements from
2128 the back of the (bidirectional) range instead of the front.
2130 See_Also: $(REF dropExactly, std, range), $(REF dropBackExactly, std, range)
2132 void popFrontExactly(Range
)(ref Range r
, size_t n
)
2133 if (isInputRange
!Range
)
2135 static if (hasLength
!Range
)
2136 assert(n
<= r
.length
, "range is smaller than amount of items to pop");
2138 static if (hasSlicing
!Range
&& is(typeof(r
= r
[n
.. $])))
2140 else static if (hasSlicing
!Range
&& hasLength
!Range
) //TODO: Remove once hasSlicing forces opDollar.
2141 r
= r
[n
.. r
.length
];
2148 void popBackExactly(Range
)(ref Range r
, size_t n
)
2149 if (isBidirectionalRange
!Range
)
2151 static if (hasLength
!Range
)
2152 assert(n
<= r
.length
, "range is smaller than amount of items to pop");
2154 static if (hasSlicing
!Range
&& is(typeof(r
= r
[0 .. $ - n
])))
2156 else static if (hasSlicing
!Range
&& hasLength
!Range
) //TODO: Remove once hasSlicing forces opDollar.
2157 r
= r
[0 .. r
.length
- n
];
2166 import std
.algorithm
.comparison
: equal
;
2167 import std
.algorithm
.iteration
: filterBidirectional
;
2170 a
.popFrontExactly(1);
2171 assert(a
== [2, 3]);
2172 a
.popBackExactly(1);
2176 s
.popFrontExactly(1);
2178 s
.popBackExactly(1);
2181 auto bd
= filterBidirectional
!"true"([1, 2, 3]);
2182 bd
.popFrontExactly(1);
2183 assert(bd
.equal([2, 3]));
2184 bd
.popBackExactly(1);
2185 assert(bd
.equal([2]));
2189 Moves the front of `r` out and returns it.
2191 If `r.front` is a struct with a destructor or copy constructor defined, it
2192 is reset to its `.init` value after its value is moved. Otherwise, it is
2195 In either case, `r.front` is left in a destroyable state that does not
2196 allocate any resources.
2198 ElementType
!R
moveFront(R
)(R r
)
2200 static if (is(typeof(&r
.moveFront
)))
2202 return r
.moveFront();
2204 else static if (!hasElaborateCopyConstructor
!(ElementType
!R
))
2208 else static if (is(typeof(&(r
.front())) == ElementType
!R
*))
2210 import std
.algorithm
.mutation
: move
;
2211 return move(r
.front
);
2216 "Cannot move front of a range with a postblit and an rvalue front.");
2223 auto a
= [ 1, 2, 3 ];
2224 assert(moveFront(a
) == 1);
2225 assert(a
.length
== 3);
2227 // define a perfunctory input range
2230 enum bool empty
= false;
2233 int moveFront() { return 43; }
2236 // calls r.moveFront
2237 assert(moveFront(r
) == 43);
2244 @property ref int front() { static int x
= 42; return x
; }
2248 assert(moveFront(r
) == 42);
2252 Moves the back of `r` out and returns it. Leaves `r.back` in a
2253 destroyable state that does not allocate any resources (usually equal
2254 to its `.init` value).
2256 ElementType
!R
moveBack(R
)(R r
)
2258 static if (is(typeof(&r
.moveBack
)))
2260 return r
.moveBack();
2262 else static if (!hasElaborateCopyConstructor
!(ElementType
!R
))
2266 else static if (is(typeof(&(r
.back())) == ElementType
!R
*))
2268 import std
.algorithm
.mutation
: move
;
2269 return move(r
.back
);
2274 "Cannot move back of a range with a postblit and an rvalue back.");
2284 @property bool empty() { return false; }
2285 @property TestRange
save() { return this; }
2286 @property ref int front() return { return payload
; }
2287 @property ref int back() return { return payload
; }
2291 static assert(isBidirectionalRange
!TestRange
);
2293 auto x
= moveBack(r
);
2298 Moves element at index `i` of `r` out and returns it. Leaves $(D
2299 r[i]) in a destroyable state that does not allocate any resources
2300 (usually equal to its `.init` value).
2302 ElementType
!R
moveAt(R
)(R r
, size_t i
)
2304 static if (is(typeof(&r
.moveAt
)))
2308 else static if (!hasElaborateCopyConstructor
!(ElementType
!(R
)))
2312 else static if (is(typeof(&r
[i
]) == ElementType
!R
*))
2314 import std
.algorithm
.mutation
: move
;
2320 "Cannot move element of a range with a postblit and rvalue elements.");
2328 foreach (idx
, it
; a
)
2330 assert(it
== moveAt(a
, idx
));
2336 import std
.internal
.test.dummyrange
;
2338 foreach (DummyType
; AllDummyRanges
)
2340 auto d
= DummyType
.init
;
2341 assert(moveFront(d
) == 1);
2343 static if (isBidirectionalRange
!DummyType
)
2345 assert(moveBack(d
) == 10);
2348 static if (isRandomAccessRange
!DummyType
)
2350 assert(moveAt(d
, 2) == 3);
2356 Implements the range interface primitive `empty` for types that
2357 obey $(LREF hasLength) property and for narrow strings. Due to the
2358 fact that nonmember functions can be called with the first argument
2359 using the dot notation, `a.empty` is equivalent to `empty(a)`.
2361 @property bool empty(T
)(auto ref scope T a
)
2362 if (is(typeof(a
.length
) : size_t
))
2368 @safe pure nothrow unittest
2370 auto a
= [ 1, 2, 3 ];
2372 assert(a
[3 .. $].empty
);
2381 Implements the range interface primitive `save` for built-in
2382 arrays. Due to the fact that nonmember functions can be called with
2383 the first argument using the dot notation, `array.save` is
2384 equivalent to `save(array)`. The function does not duplicate the
2385 content of the array, it simply returns its argument.
2387 @property inout(T
)[] save(T
)(return scope inout(T
)[] a
) @safe pure nothrow @nogc
2393 @safe pure nothrow unittest
2395 auto a
= [ 1, 2, 3 ];
2401 Implements the range interface primitive `popFront` for built-in
2402 arrays. Due to the fact that nonmember functions can be called with
2403 the first argument using the dot notation, `array.popFront` is
2404 equivalent to `popFront(array)`. For $(GLOSSARY narrow strings),
2405 `popFront` automatically advances to the next $(GLOSSARY code
2408 void popFront(T
)(scope ref inout(T
)[] a
) @safe pure nothrow @nogc
2409 if (!isAutodecodableString
!(T
[]) && !is(T
[] == void[]))
2411 assert(a
.length
, "Attempting to popFront() past the end of an array of " ~ T
.stringof
);
2416 @safe pure nothrow unittest
2418 auto a
= [ 1, 2, 3 ];
2420 assert(a
== [ 2, 3 ]);
2425 static assert(!is(typeof({ int[4] a
; popFront(a
); })));
2426 static assert(!is(typeof({ immutable int[] a
; popFront(a
); })));
2427 static assert(!is(typeof({ void[] a
; popFront(a
); })));
2431 void popFront(C
)(scope ref inout(C
)[] str) @trusted pure nothrow
2432 if (isAutodecodableString
!(C
[]))
2434 import std
.algorithm
.comparison
: min
;
2436 assert(str.length
, "Attempting to popFront() past the end of an array of " ~ C
.stringof
);
2438 static if (is(immutable C
== immutable char))
2440 static immutable ubyte[] charWidthTab
= [
2441 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2442 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2443 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2444 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
2447 immutable c
= str[0];
2448 immutable charWidth
= c
< 192 ?
1 : charWidthTab
.ptr
[c
- 192];
2449 str = str.ptr
[min(str.length
, charWidth
) .. str.length
];
2451 else static if (is(immutable C
== immutable wchar))
2453 immutable u
= str[0];
2454 immutable seqLen
= 1 + (u
>= 0xD800 && u
<= 0xDBFF);
2455 str = str.ptr
[min(seqLen
, str.length
) .. str.length
];
2457 else static assert(0, "Bad template constraint.");
2462 import std
.meta
: AliasSeq
;
2464 static foreach (S
; AliasSeq
!(string
, wstring
, dstring
))
2466 S s
= "\xC2\xA9hello";
2468 assert(s
== "hello");
2470 S
str = "hello\U00010143\u0100\U00010143";
2471 foreach (dchar c
; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143'])
2473 assert(str.front
== c
);
2478 static assert(!is(typeof({ immutable S a
; popFront(a
); })));
2479 static assert(!is(typeof({ typeof(S
.init
[0])[4] a
; popFront(a
); })));
2482 C
[] _eatString(C
)(C
[] str)
2489 enum checkCTFE
= _eatString("ウェブサイト@La_Verité.com");
2490 static assert(checkCTFE
.empty
);
2491 enum checkCTFEW
= _eatString("ウェブサイト@La_Verité.com"w
);
2492 static assert(checkCTFEW
.empty
);
2495 // https://issues.dlang.org/show_bug.cgi?id=16090
2498 string s
= "\u00E4";
2499 assert(s
.length
== 2);
2501 assert(s
.length
== 1);
2508 wstring s
= "\U00010000";
2509 assert(s
.length
== 2);
2511 assert(s
.length
== 1);
2517 Implements the range interface primitive `popBack` for built-in
2518 arrays. Due to the fact that nonmember functions can be called with
2519 the first argument using the dot notation, `array.popBack` is
2520 equivalent to `popBack(array)`. For $(GLOSSARY narrow strings), $(D
2521 popFront) automatically eliminates the last $(GLOSSARY code point).
2523 void popBack(T
)(scope ref inout(T
)[] a
) @safe pure nothrow @nogc
2524 if (!isAutodecodableString
!(T
[]) && !is(T
[] == void[]))
2531 @safe pure nothrow unittest
2533 auto a
= [ 1, 2, 3 ];
2535 assert(a
== [ 1, 2 ]);
2540 static assert(!is(typeof({ immutable int[] a
; popBack(a
); })));
2541 static assert(!is(typeof({ int[4] a
; popBack(a
); })));
2542 static assert(!is(typeof({ void[] a
; popBack(a
); })));
2546 void popBack(T
)(scope ref inout(T
)[] a
) @safe pure
2547 if (isAutodecodableString
!(T
[]))
2549 import std
.utf
: strideBack
;
2550 assert(a
.length
, "Attempting to popBack() past the front of an array of " ~ T
.stringof
);
2551 a
= a
[0 .. $ - strideBack(a
, $)];
2556 import std
.meta
: AliasSeq
;
2558 static foreach (S
; AliasSeq
!(string
, wstring
, dstring
))
2560 S s
= "hello\xE2\x89\xA0";
2562 assert(s
== "hello");
2563 S s3
= "\xE2\x89\xA0";
2565 assert(c
== cast(dchar)'\u2260');
2569 S
str = "\U00010143\u0100\U00010143hello";
2570 foreach (dchar ch
; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143'])
2572 assert(str.back
== ch
);
2577 static assert(!is(typeof({ immutable S a
; popBack(a
); })));
2578 static assert(!is(typeof({ typeof(S
.init
[0])[4] a
; popBack(a
); })));
2583 EXPERIMENTAL: to try out removing autodecoding, set the version
2584 `NoAutodecodeStrings`. Most things are expected to fail with this version
2587 version (NoAutodecodeStrings
)
2589 enum autodecodeStrings
= false;
2594 enum autodecodeStrings
= true;
2598 Implements the range interface primitive `front` for built-in
2599 arrays. Due to the fact that nonmember functions can be called with
2600 the first argument using the dot notation, `array.front` is
2601 equivalent to `front(array)`. For $(GLOSSARY narrow strings), $(D
2602 front) automatically returns the first $(GLOSSARY code point) as _a $(D
2605 @property ref inout(T
) front(T
)(return scope inout(T
)[] a
) @safe pure nothrow @nogc
2606 if (!isAutodecodableString
!(T
[]) && !is(T
[] == void[]))
2608 assert(a
.length
, "Attempting to fetch the front of an empty array of " ~ T
.stringof
);
2613 @safe pure nothrow unittest
2615 int[] a
= [ 1, 2, 3 ];
2616 assert(a
.front
== 1);
2619 @safe pure nothrow unittest
2623 assert(a
.front
== 4);
2624 assert(a
== [ 4, 2 ]);
2626 immutable b
= [ 1, 2 ];
2627 assert(b
.front
== 1);
2629 int[2] c
= [ 1, 2 ];
2630 assert(c
.front
== 1);
2634 @property dchar front(T
)(scope const(T
)[] a
) @safe pure
2635 if (isAutodecodableString
!(T
[]))
2637 import std
.utf
: decode
;
2638 assert(a
.length
, "Attempting to fetch the front of an empty array of " ~ T
.stringof
);
2640 return decode(a
, i
);
2644 Implements the range interface primitive `back` for built-in
2645 arrays. Due to the fact that nonmember functions can be called with
2646 the first argument using the dot notation, `array.back` is
2647 equivalent to `back(array)`. For $(GLOSSARY narrow strings), $(D
2648 back) automatically returns the last $(GLOSSARY code point) as _a $(D
2651 @property ref inout(T
) back(T
)(return scope inout(T
)[] a
) @safe pure nothrow @nogc
2652 if (!isAutodecodableString
!(T
[]) && !is(T
[] == void[]))
2654 assert(a
.length
, "Attempting to fetch the back of an empty array of " ~ T
.stringof
);
2659 @safe pure nothrow unittest
2661 int[] a
= [ 1, 2, 3 ];
2662 assert(a
.back
== 3);
2664 assert(a
.back
== 7);
2667 @safe pure nothrow unittest
2669 immutable b
= [ 1, 2, 3 ];
2670 assert(b
.back
== 3);
2672 int[3] c
= [ 1, 2, 3 ];
2673 assert(c
.back
== 3);
2677 // Specialization for strings
2678 @property dchar back(T
)(scope const(T
)[] a
) @safe pure
2679 if (isAutodecodableString
!(T
[]))
2681 import std
.utf
: decode
, strideBack
;
2682 assert(a
.length
, "Attempting to fetch the back of an empty array of " ~ T
.stringof
);
2683 size_t i
= a
.length
- strideBack(a
, a
.length
);
2684 return decode(a
, i
);
2688 Implements `length` for a range by forwarding it to `member`.
2690 package(std
) mixin template ImplementLength(alias member
)
2692 static if (hasLength
!(typeof(member
)))
2694 @property auto length()
2696 return member
.length
;
2698 alias opDollar
= length
;
2704 import std
.meta
: AliasSeq
;
2706 foreach (alias E
; AliasSeq
!(noreturn
, const(noreturn
), immutable(noreturn
) ))
2710 static assert(isInputRange
!R
);
2711 static assert(isForwardRange
!R
);
2712 static assert(isBidirectionalRange
!R
);
2713 static assert(isRandomAccessRange
!R
);
2716 static assert(isOutputRange
!(noreturn
[], noreturn
));