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