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