1 // Written in the D programming language.
2 
3 /**
4 This module defines the notion of a range. Ranges generalize the concept of
5 arrays, lists, or anything that involves sequential access. This abstraction
6 enables the same set of algorithms (see $(MREF std, algorithm)) to be used
7 with a vast variety of different concrete types. For example,
8 a linear search algorithm such as $(REF find, std, algorithm, searching)
9 works not just for arrays, but for linked-lists, input files,
10 incoming network data, etc.
11 
12 Guides:
13 
14 There are many articles available that can bolster understanding ranges:
15 
16 $(UL
17     $(LI Ali Çehreli's $(HTTP ddili.org/ders/d.en/ranges.html, tutorial on ranges)
18         for the basics of working with and creating range-based code.)
19     $(LI Jonathan M. Davis $(LINK2 http://dconf.org/2015/talks/davis.html, $(I Introduction to Ranges))
20         talk at DConf 2015 a vivid introduction from its core constructs to practical advice.)
21     $(LI The DLang Tour's $(LINK2 http://tour.dlang.org/tour/en/basics/ranges, chapter on ranges)
22         for an interactive introduction.)
23     $(LI H. S. Teoh's $(LINK2 http://wiki.dlang.org/Component_programming_with_ranges, tutorial on
24         component programming with ranges) for a real-world showcase of the influence
25         of range-based programming on complex algorithms.)
26     $(LI Andrei Alexandrescu's article
27         $(LINK2 http://www.informit.com/articles/printerfriendly.aspx?p=1407357$(AMP)rll=1,
28         $(I On Iteration)) for conceptual aspect of ranges and the motivation
29     )
30 )
31 
32 Submodules:
33 
34 This module has two submodules:
35 
36 The $(MREF std, range, primitives) submodule
37 provides basic range functionality. It defines several templates for testing
38 whether a given object is a range, what kind of range it is, and provides
39 some common range operations.
40 
41 The $(MREF std, range, interfaces) submodule
42 provides object-based interfaces for working with ranges via runtime
43 polymorphism.
44 
45 The remainder of this module provides a rich set of range creation and
46 composition templates that let you construct new ranges out of existing ranges:
47 
48 
49 $(SCRIPT inhibitQuickIndex = 1;)
50 $(DIVC quickindex,
51 $(BOOKTABLE ,
52     $(TR $(TD $(LREF chain))
53         $(TD Concatenates several ranges into a single range.
54     ))
55     $(TR $(TD $(LREF choose))
56         $(TD Chooses one of two ranges at runtime based on a boolean condition.
57     ))
58     $(TR $(TD $(LREF chooseAmong))
59         $(TD Chooses one of several ranges at runtime based on an index.
60     ))
61     $(TR $(TD $(LREF chunks))
62         $(TD Creates a range that returns fixed-size chunks of the original
63         range.
64     ))
65     $(TR $(TD $(LREF cycle))
66         $(TD Creates an infinite range that repeats the given forward range
67         indefinitely. Good for implementing circular buffers.
68     ))
69     $(TR $(TD $(LREF drop))
70         $(TD Creates the range that results from discarding the first $(I n)
71         elements from the given range.
72     ))
73     $(TR $(TD $(LREF dropBack))
74         $(TD Creates the range that results from discarding the last $(I n)
75         elements from the given range.
76     ))
77     $(TR $(TD $(LREF dropExactly))
78         $(TD Creates the range that results from discarding exactly $(I n)
79         of the first elements from the given range.
80     ))
81     $(TR $(TD $(LREF dropBackExactly))
82         $(TD Creates the range that results from discarding exactly $(I n)
83         of the last elements from the given range.
84     ))
85     $(TR $(TD $(LREF dropOne))
86         $(TD Creates the range that results from discarding
87         the first element from the given range.
88     ))
89     $(TR $(TD $(D $(LREF dropBackOne)))
90         $(TD Creates the range that results from discarding
91         the last element from the given range.
92     ))
93     $(TR $(TD $(LREF enumerate))
94         $(TD Iterates a range with an attached index variable.
95     ))
96     $(TR $(TD $(LREF evenChunks))
97         $(TD Creates a range that returns a number of chunks of
98         approximately equal length from the original range.
99     ))
100     $(TR $(TD $(LREF frontTransversal))
101         $(TD Creates a range that iterates over the first elements of the
102         given ranges.
103     ))
104     $(TR $(TD $(LREF generate))
105         $(TD Creates a range by successive calls to a given function. This
106         allows to create ranges as a single delegate.
107     ))
108     $(TR $(TD $(LREF indexed))
109         $(TD Creates a range that offers a view of a given range as though
110         its elements were reordered according to a given range of indices.
111     ))
112     $(TR $(TD $(LREF iota))
113         $(TD Creates a range consisting of numbers between a starting point
114         and ending point, spaced apart by a given interval.
115     ))
116     $(TR $(TD $(LREF lockstep))
117         $(TD Iterates $(I n) ranges in lockstep, for use in a `foreach`
118         loop. Similar to `zip`, except that `lockstep` is designed
119         especially for `foreach` loops.
120     ))
121     $(TR $(TD $(LREF nullSink))
122         $(TD An output range that discards the data it receives.
123     ))
124     $(TR $(TD $(LREF only))
125         $(TD Creates a range that iterates over the given arguments.
126     ))
127     $(TR $(TD $(LREF padLeft))
128         $(TD Pads a range to a specified length by adding a given element to
129         the front of the range. Is lazy if the range has a known length.
130     ))
131     $(TR $(TD $(LREF padRight))
132         $(TD Lazily pads a range to a specified length by adding a given element to
133         the back of the range.
134     ))
135     $(TR $(TD $(LREF radial))
136         $(TD Given a random-access range and a starting point, creates a
137         range that alternately returns the next left and next right element to
138         the starting point.
139     ))
140     $(TR $(TD $(LREF recurrence))
141         $(TD Creates a forward range whose values are defined by a
142         mathematical recurrence relation.
143     ))
144     $(TR $(TD $(LREF refRange))
145         $(TD Pass a range by reference. Both the original range and the RefRange
146         will always have the exact same elements.
147         Any operation done on one will affect the other.
148     ))
149     $(TR $(TD $(LREF repeat))
150         $(TD Creates a range that consists of a single element repeated $(I n)
151         times, or an infinite range repeating that element indefinitely.
152     ))
153     $(TR $(TD $(LREF retro))
154         $(TD Iterates a bidirectional range backwards.
155     ))
156     $(TR $(TD $(LREF roundRobin))
157         $(TD Given $(I n) ranges, creates a new range that return the $(I n)
158         first elements of each range, in turn, then the second element of each
159         range, and so on, in a round-robin fashion.
160     ))
161     $(TR $(TD $(LREF sequence))
162         $(TD Similar to `recurrence`, except that a random-access range is
163         created.
164     ))
165     $(TR $(TD $(D $(LREF slide)))
166         $(TD Creates a range that returns a fixed-size sliding window
167         over the original range. Unlike chunks,
168         it advances a configurable number of items at a time,
169         not one chunk at a time.
170     ))
171     $(TR $(TD $(LREF stride))
172         $(TD Iterates a range with stride $(I n).
173     ))
174     $(TR $(TD $(LREF tail))
175         $(TD Return a range advanced to within `n` elements of the end of
176         the given range.
177     ))
178     $(TR $(TD $(LREF take))
179         $(TD Creates a sub-range consisting of only up to the first $(I n)
180         elements of the given range.
181     ))
182     $(TR $(TD $(LREF takeExactly))
183         $(TD Like `take`, but assumes the given range actually has $(I n)
184         elements, and therefore also defines the `length` property.
185     ))
186     $(TR $(TD $(LREF takeNone))
187         $(TD Creates a random-access range consisting of zero elements of the
188         given range.
189     ))
190     $(TR $(TD $(LREF takeOne))
191         $(TD Creates a random-access range consisting of exactly the first
192         element of the given range.
193     ))
194     $(TR $(TD $(LREF tee))
195         $(TD Creates a range that wraps a given range, forwarding along
196         its elements while also calling a provided function with each element.
197     ))
198     $(TR $(TD $(LREF transposed))
199         $(TD Transposes a range of ranges.
200     ))
201     $(TR $(TD $(LREF transversal))
202         $(TD Creates a range that iterates over the $(I n)'th elements of the
203         given random-access ranges.
204     ))
205     $(TR $(TD $(LREF zip))
206         $(TD Given $(I n) ranges, creates a range that successively returns a
207         tuple of all the first elements, a tuple of all the second elements,
208         etc.
209     ))
210 ))
211 
212 Sortedness:
213 
214 Ranges whose elements are sorted afford better efficiency with certain
215 operations. For this, the $(LREF assumeSorted) function can be used to
216 construct a $(LREF SortedRange) from a pre-sorted range. The $(REF
217 sort, std, algorithm, sorting) function also conveniently
218 returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional
219 range operations that take advantage of the fact that the range is sorted.
220 
221 Source: $(PHOBOSSRC std/range/package.d)
222 
223 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
224 
225 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha,
226          $(HTTP jmdavisprog.com, Jonathan M Davis), and Jack Stouffer. Credit
227          for some of the ideas in building this module goes to
228          $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
229  */
230 module std.range;
231 
232 public import std.array;
233 public import std.range.interfaces;
234 public import std.range.primitives;
235 public import std.typecons : Flag, Yes, No, Rebindable, rebindable;
236 
237 import std.internal.attributes : betterC;
238 import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap;
239 import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral,
240     isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf;
241 
242 
243 /**
244 Iterates a bidirectional range backwards. The original range can be
245 accessed by using the `source` property. Applying retro twice to
246 the same range yields the original range.
247 
248 Params:
249     r = the bidirectional range to iterate backwards
250 
251 Returns:
252     A bidirectional range with length if `r` also provides a length. Or,
253     if `r` is a random access range, then the return value will be random
254     access as well.
255 See_Also:
256     $(REF reverse, std,algorithm,mutation) for mutating the source range directly.
257  */
258 auto retro(Range)(Range r)
259 if (isBidirectionalRange!(Unqual!Range))
260 {
261     // Check for retro(retro(r)) and just return r in that case
262     static if (is(typeof(retro(r.source)) == Range))
263     {
264         return r.source;
265     }
266     else
267     {
268         static struct Result()
269         {
270             private alias R = Unqual!Range;
271 
272             // User code can get and set source, too
273             R source;
274 
275             static if (hasLength!R)
276             {
277                 size_t retroIndex(size_t n)
278                 {
279                     return source.length - n - 1;
280                 }
281             }
282 
283         public:
284             alias Source = R;
285 
286             @property bool empty() { return source.empty; }
287             @property auto save()
288             {
289                 return Result(source.save);
290             }
291             @property auto ref front() { return source.back; }
292             void popFront() { source.popBack(); }
293             @property auto ref back() { return source.front; }
294             void popBack() { source.popFront(); }
295 
296             static if (is(typeof(source.moveBack())))
297             {
298                 ElementType!R moveFront()
299                 {
300                     return source.moveBack();
301                 }
302             }
303 
304             static if (is(typeof(source.moveFront())))
305             {
306                 ElementType!R moveBack()
307                 {
308                     return source.moveFront();
309                 }
310             }
311 
312             static if (hasAssignableElements!R)
313             {
314                 @property void front(ElementType!R val)
315                 {
316                     import core.lifetime : forward;
317 
318                     // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
319                     source.back = __ctfe ? val : forward!val;
320                 }
321 
322                 @property void back(ElementType!R val)
323                 {
324                     import core.lifetime : forward;
325 
326                     // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
327                     source.front = __ctfe ? val : forward!val;
328                 }
329             }
330 
331             static if (isRandomAccessRange!(R) && hasLength!(R))
332             {
333                 auto ref opIndex(size_t n) { return source[retroIndex(n)]; }
334 
335                 static if (hasAssignableElements!R)
336                 {
337                     void opIndexAssign(ElementType!R val, size_t n)
338                     {
339                         import core.lifetime : forward;
340 
341                         // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
342                         source[retroIndex(n)] = __ctfe ? val : forward!val;
343                     }
344                 }
345 
346                 static if (is(typeof(source.moveAt(0))))
347                 {
348                     ElementType!R moveAt(size_t index)
349                     {
350                         return source.moveAt(retroIndex(index));
351                     }
352                 }
353 
354                 static if (hasSlicing!R)
355                     typeof(this) opSlice(size_t a, size_t b)
356                     {
357                         return typeof(this)(source[source.length - b .. source.length - a]);
358                     }
359             }
360 
361             mixin ImplementLength!source;
362         }
363 
364         return Result!()(r);
365     }
366 }
367 
368 
369 ///
370 pure @safe nothrow @nogc unittest
371 {
372     import std.algorithm.comparison : equal;
373     int[5] a = [ 1, 2, 3, 4, 5 ];
374     int[5] b = [ 5, 4, 3, 2, 1 ];
375     assert(equal(retro(a[]), b[]));
376     assert(retro(a[]).source is a[]);
377     assert(retro(retro(a[])) is a[]);
378 }
379 
380 pure @safe nothrow unittest
381 {
382     import std.algorithm.comparison : equal;
383     static assert(isBidirectionalRange!(typeof(retro("hello"))));
384     int[] a;
385     static assert(is(typeof(a) == typeof(retro(retro(a)))));
386     assert(retro(retro(a)) is a);
387     static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
388     void test(int[] input, int[] witness)
389     {
390         auto r = retro(input);
391         assert(r.front == witness.front);
392         assert(r.back == witness.back);
393         assert(equal(r, witness));
394     }
395     test([ 1 ], [ 1 ]);
396     test([ 1, 2 ], [ 2, 1 ]);
397     test([ 1, 2, 3 ], [ 3, 2, 1 ]);
398     test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
399     test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
400     test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
401 
402     immutable foo = [1,2,3].idup;
403     auto r = retro(foo);
404     assert(equal(r, [3, 2, 1]));
405 }
406 
407 pure @safe nothrow unittest
408 {
409     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
410         ReturnBy;
411 
412     foreach (DummyType; AllDummyRanges)
413     {
414         static if (!isBidirectionalRange!DummyType)
415         {
416             static assert(!__traits(compiles, Retro!DummyType));
417         }
418         else
419         {
420             DummyType dummyRange;
421             dummyRange.reinit();
422 
423             auto myRetro = retro(dummyRange);
424             static assert(propagatesRangeType!(typeof(myRetro), DummyType));
425             assert(myRetro.front == 10);
426             assert(myRetro.back == 1);
427             assert(myRetro.moveFront() == 10);
428             assert(myRetro.moveBack() == 1);
429 
430             static if (isRandomAccessRange!DummyType && hasLength!DummyType)
431             {
432                 assert(myRetro[0] == myRetro.front);
433                 assert(myRetro.moveAt(2) == 8);
434 
435                 static if (DummyType.r == ReturnBy.Reference)
436                 {
437                     {
438                         myRetro[9]++;
439                         scope(exit) myRetro[9]--;
440                         assert(dummyRange[0] == 2);
441                         myRetro.front++;
442                         scope(exit) myRetro.front--;
443                         assert(myRetro.front == 11);
444                         myRetro.back++;
445                         scope(exit) myRetro.back--;
446                         assert(myRetro.back == 3);
447                     }
448 
449                     {
450                         myRetro.front = 0xFF;
451                         scope(exit) myRetro.front = 10;
452                         assert(dummyRange.back == 0xFF);
453 
454                         myRetro.back = 0xBB;
455                         scope(exit) myRetro.back = 1;
456                         assert(dummyRange.front == 0xBB);
457 
458                         myRetro[1] = 11;
459                         scope(exit) myRetro[1] = 8;
460                         assert(dummyRange[8] == 11);
461                     }
462                 }
463             }
464         }
465     }
466 }
467 
468 pure @safe nothrow @nogc unittest
469 {
470     import std.algorithm.comparison : equal;
471     auto LL = iota(1L, 4L);
472     auto r = retro(LL);
473     long[3] excepted = [3, 2, 1];
474     assert(equal(r, excepted[]));
475 }
476 
477 // https://issues.dlang.org/show_bug.cgi?id=12662
478 pure @safe nothrow @nogc unittest
479 {
480     int[3] src = [1,2,3];
481     int[] data = src[];
482     foreach_reverse (x; data) {}
483     foreach (x; data.retro) {}
484 }
485 
486 pure @safe nothrow unittest
487 {
488     import std.algorithm.comparison : equal;
489 
490     static struct S {
491         int v;
492         @disable this(this);
493     }
494 
495     immutable foo = [S(1), S(2), S(3)];
496     auto r = retro(foo);
497     assert(equal(r, [S(3), S(2), S(1)]));
498 }
499 
500 // https://issues.dlang.org/show_bug.cgi?id=24481
501 @safe unittest
502 {
503     bool called;
504     struct Handle
505     {
506         int entry;
507         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
508     }
509 
510     const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
511     auto range = arr[].retro();
512 
513     called = false;
514     range.front = Handle(42);
515     assert(called);
516 
517     called = false;
518     range.back = Handle(42);
519     assert(called);
520 
521     called = false;
522     range[2] = Handle(42);
523     assert(called);
524 }
525 
526 /**
527 Iterates range `r` with stride `n`. If the range is a
528 random-access range, moves by indexing into the range; otherwise,
529 moves by successive calls to `popFront`. Applying stride twice to
530 the same range results in a stride with a step that is the
531 product of the two applications. It is an error for `n` to be 0.
532 
533 Params:
534     r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over
535     n = the number of elements to skip over
536 
537 Returns:
538     At minimum, an input range. The resulting range will adopt the
539     range primitives of the underlying range as long as
540     $(REF hasLength, std,range,primitives) is `true`.
541  */
542 auto stride(Range)(Range r, size_t n)
543 if (isInputRange!(Unqual!Range))
544 in
545 {
546     assert(n != 0, "stride cannot have step zero.");
547 }
548 do
549 {
550     import std.algorithm.comparison : min;
551 
552     static if (is(typeof(stride(r.source, n)) == Range))
553     {
554         // stride(stride(r, n1), n2) is stride(r, n1 * n2)
555         return stride(r.source, r._n * n);
556     }
557     else
558     {
559         static struct Result
560         {
561             private alias R = Unqual!Range;
562             public R source;
563             private size_t _n;
564 
565             // Chop off the slack elements at the end
566             static if (hasLength!R &&
567                     (isRandomAccessRange!R && hasSlicing!R
568                             || isBidirectionalRange!R))
569                 private void eliminateSlackElements()
570                 {
571                     auto slack = source.length % _n;
572 
573                     if (slack)
574                     {
575                         slack--;
576                     }
577                     else if (!source.empty)
578                     {
579                         slack = min(_n, source.length) - 1;
580                     }
581                     else
582                     {
583                         slack = 0;
584                     }
585                     if (!slack) return;
586                     static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
587                     {
588                         source = source[0 .. source.length - slack];
589                     }
590                     else static if (isBidirectionalRange!R)
591                     {
592                         foreach (i; 0 .. slack)
593                         {
594                             source.popBack();
595                         }
596                     }
597                 }
598 
599             static if (isForwardRange!R)
600             {
601                 @property auto save()
602                 {
603                     return Result(source.save, _n);
604                 }
605             }
606 
607             static if (isInfinite!R)
608             {
609                 enum bool empty = false;
610             }
611             else
612             {
613                 @property bool empty()
614                 {
615                     return source.empty;
616                 }
617             }
618 
619             @property auto ref front()
620             {
621                 return source.front;
622             }
623 
624             static if (is(typeof(.moveFront(source))))
625             {
626                 ElementType!R moveFront()
627                 {
628                     return source.moveFront();
629                 }
630             }
631 
632             static if (hasAssignableElements!R)
633             {
634                 @property void front(ElementType!R val)
635                 {
636                     import core.lifetime : forward;
637 
638                     // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
639                     source.front = __ctfe ? val : forward!val;
640                 }
641             }
642 
643             void popFront()
644             {
645                 source.popFrontN(_n);
646             }
647 
648             static if (isBidirectionalRange!R && hasLength!R)
649             {
650                 void popBack()
651                 {
652                     popBackN(source, _n);
653                 }
654 
655                 @property auto ref back()
656                 {
657                     eliminateSlackElements();
658                     return source.back;
659                 }
660 
661                 static if (is(typeof(.moveBack(source))))
662                 {
663                     ElementType!R moveBack()
664                     {
665                         eliminateSlackElements();
666                         return source.moveBack();
667                     }
668                 }
669 
670                 static if (hasAssignableElements!R)
671                 {
672                     @property void back(ElementType!R val)
673                     {
674                         eliminateSlackElements();
675                         source.back = val;
676                     }
677                 }
678             }
679 
680             static if (isRandomAccessRange!R && hasLength!R)
681             {
682                 auto ref opIndex(size_t n)
683                 {
684                     return source[_n * n];
685                 }
686 
687                 /**
688                    Forwards to $(D moveAt(source, n)).
689                 */
690                 static if (is(typeof(source.moveAt(0))))
691                 {
692                     ElementType!R moveAt(size_t n)
693                     {
694                         return source.moveAt(_n * n);
695                     }
696                 }
697 
698                 static if (hasAssignableElements!R)
699                 {
700                     void opIndexAssign(ElementType!R val, size_t n)
701                     {
702                         source[_n * n] = val;
703                     }
704                 }
705             }
706 
707             static if (hasSlicing!R && hasLength!R)
708                 typeof(this) opSlice(size_t lower, size_t upper)
709                 {
710                     assert(upper >= lower && upper <= length,
711                         "Attempt to get out-of-bounds slice of `stride` range");
712                     immutable translatedUpper = (upper == 0) ? 0 :
713                         (upper * _n - (_n - 1));
714                     immutable translatedLower = min(lower * _n, translatedUpper);
715 
716                     assert(translatedLower <= translatedUpper,
717                         "Overflow when calculating slice of `stride` range");
718 
719                     return typeof(this)(source[translatedLower .. translatedUpper], _n);
720                 }
721 
722             static if (hasLength!R)
723             {
724                 @property auto length()
725                 {
726                     return (source.length + _n - 1) / _n;
727                 }
728 
729                 alias opDollar = length;
730             }
731         }
732         return Result(r, n);
733     }
734 }
735 
736 ///
737 pure @safe nothrow unittest
738 {
739     import std.algorithm.comparison : equal;
740 
741     int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
742     assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
743     assert(stride(stride(a, 2), 3) == stride(a, 6));
744 }
745 
746 pure @safe nothrow @nogc unittest
747 {
748     import std.algorithm.comparison : equal;
749 
750     int[4] testArr = [1,2,3,4];
751     static immutable result = [1, 3];
752     assert(equal(testArr[].stride(2), result));
753 }
754 
755 debug pure nothrow @system unittest
756 {//check the contract
757     int[4] testArr = [1,2,3,4];
758     bool passed = false;
759     scope (success) assert(passed);
760     import core.exception : AssertError;
761     //std.exception.assertThrown won't do because it can't infer nothrow
762     // https://issues.dlang.org/show_bug.cgi?id=12647
763     try
764     {
765         auto unused = testArr[].stride(0);
766     }
767     catch (AssertError unused)
768     {
769         passed = true;
770     }
771 }
772 
773 pure @safe nothrow unittest
774 {
775     import std.algorithm.comparison : equal;
776     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
777         ReturnBy;
778 
779     static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
780     void test(size_t n, int[] input, int[] witness)
781     {
782         assert(equal(stride(input, n), witness));
783     }
784     test(1, [], []);
785     int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
786     assert(stride(stride(arr, 2), 3) is stride(arr, 6));
787     test(1, arr, arr);
788     test(2, arr, [1, 3, 5, 7, 9]);
789     test(3, arr, [1, 4, 7, 10]);
790     test(4, arr, [1, 5, 9]);
791 
792     // Test slicing.
793     auto s1 = stride(arr, 1);
794     assert(equal(s1[1 .. 4], [2, 3, 4]));
795     assert(s1[1 .. 4].length == 3);
796     assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
797     assert(s1[1 .. 5].length == 4);
798     assert(s1[0 .. 0].empty);
799     assert(s1[3 .. 3].empty);
800     // assert(s1[$ .. $].empty);
801     assert(s1[s1.opDollar .. s1.opDollar].empty);
802 
803     auto s2 = stride(arr, 2);
804     assert(equal(s2[0 .. 2], [1,3]));
805     assert(s2[0 .. 2].length == 2);
806     assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
807     assert(s2[1 .. 5].length == 4);
808     assert(s2[0 .. 0].empty);
809     assert(s2[3 .. 3].empty);
810     // assert(s2[$ .. $].empty);
811     assert(s2[s2.opDollar .. s2.opDollar].empty);
812 
813     // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035
814     auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
815     auto col = stride(m, 4);
816     assert(equal(col, [1, 1, 1]));
817     assert(equal(retro(col), [1, 1, 1]));
818 
819     immutable int[] immi = [ 1, 2, 3 ];
820     static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
821 
822     // Check for infiniteness propagation.
823     static assert(isInfinite!(typeof(stride(repeat(1), 3))));
824 
825     foreach (DummyType; AllDummyRanges)
826     {
827         DummyType dummyRange;
828         dummyRange.reinit();
829 
830         auto myStride = stride(dummyRange, 4);
831 
832         // Should fail if no length and bidirectional b/c there's no way
833         // to know how much slack we have.
834         static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
835         {
836             static assert(propagatesRangeType!(typeof(myStride), DummyType));
837         }
838         assert(myStride.front == 1);
839         assert(myStride.moveFront() == 1);
840         assert(equal(myStride, [1, 5, 9]));
841 
842         static if (hasLength!DummyType)
843         {
844             assert(myStride.length == 3);
845         }
846 
847         static if (isBidirectionalRange!DummyType && hasLength!DummyType)
848         {
849             assert(myStride.back == 9);
850             assert(myStride.moveBack() == 9);
851         }
852 
853         static if (isRandomAccessRange!DummyType && hasLength!DummyType)
854         {
855             assert(myStride[0] == 1);
856             assert(myStride[1] == 5);
857             assert(myStride.moveAt(1) == 5);
858             assert(myStride[2] == 9);
859 
860             static assert(hasSlicing!(typeof(myStride)));
861         }
862 
863         static if (DummyType.r == ReturnBy.Reference)
864         {
865             // Make sure reference is propagated.
866 
867             {
868                 myStride.front++;
869                 scope(exit) myStride.front--;
870                 assert(dummyRange.front == 2);
871             }
872             {
873                 myStride.front = 4;
874                 scope(exit) myStride.front = 1;
875                 assert(dummyRange.front == 4);
876             }
877 
878             static if (isBidirectionalRange!DummyType && hasLength!DummyType)
879             {
880                 {
881                     myStride.back++;
882                     scope(exit) myStride.back--;
883                     assert(myStride.back == 10);
884                 }
885                 {
886                     myStride.back = 111;
887                     scope(exit) myStride.back = 9;
888                     assert(myStride.back == 111);
889                 }
890 
891                 static if (isRandomAccessRange!DummyType)
892                 {
893                     {
894                         myStride[1]++;
895                         scope(exit) myStride[1]--;
896                         assert(dummyRange[4] == 6);
897                     }
898                     {
899                         myStride[1] = 55;
900                         scope(exit) myStride[1] = 5;
901                         assert(dummyRange[4] == 55);
902                     }
903                 }
904             }
905         }
906     }
907 }
908 
909 pure @safe nothrow unittest
910 {
911     import std.algorithm.comparison : equal;
912 
913     auto LL = iota(1L, 10L);
914     auto s = stride(LL, 3);
915     assert(equal(s, [1L, 4L, 7L]));
916 }
917 
918 pure @safe nothrow unittest
919 {
920     import std.algorithm.comparison : equal;
921 
922     static struct S {
923         int v;
924         @disable this(this);
925     }
926 
927     immutable foo = [S(1), S(2), S(3), S(4), S(5)];
928     auto r = stride(foo, 3);
929     assert(equal(r, [S(1), S(4)]));
930 }
931 
932 // https://issues.dlang.org/show_bug.cgi?id=24481
933 @safe unittest
934 {
935     bool called;
936     struct Handle
937     {
938         int entry;
939         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
940     }
941 
942     const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
943     auto range = arr[].stride(2);
944 
945     called = false;
946     range.front = Handle(42);
947     assert(called);
948 }
949 
950 /**
951 Spans multiple ranges in sequence. The function `chain` takes any
952 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
953 ranges may be different, but they must have the same element type. The
954 result is a range that offers the `front`, `popFront`, and $(D
955 empty) primitives. If all input ranges offer random access and $(D
956 length), `Chain` offers them as well.
957 
958 Note that repeated random access of the resulting range is likely
959 to perform somewhat badly since lengths of the ranges in the chain have to be
960 added up for each random access operation. Random access to elements of
961 the first remaining range is still efficient.
962 
963 If only one range is offered to `Chain` or `chain`, the $(D
964 Chain) type exits the picture by aliasing itself directly to that
965 range's type.
966 
967 Params:
968     rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together
969 
970 Returns:
971     An input range at minimum. If all of the ranges in `rs` provide
972     a range primitive, the returned range will also provide that range
973     primitive.
974 
975 See_Also: $(LREF only) to chain values to a range
976  */
977 auto chain(Ranges...)(Ranges rs)
978 if (Ranges.length > 0 &&
979     allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
980     !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
981 {
982     static if (Ranges.length == 1)
983     {
984         return rs[0];
985     }
986     else
987     {
988         static struct Result
989         {
990         private:
991             alias R = staticMap!(Unqual, Ranges);
992             alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
993             template sameET(A)
994             {
995                 enum sameET = is(.ElementType!A == RvalueElementType);
996             }
997 
998             enum bool allSameType = allSatisfy!(sameET, R),
999                 bidirectional = allSatisfy!(isBidirectionalRange, R),
1000                 mobileElements = allSatisfy!(hasMobileElements, R),
1001                 assignableElements = allSameType
1002                     && allSatisfy!(hasAssignableElements, R);
1003 
1004             alias ElementType = RvalueElementType;
1005 
1006             static if (allSameType && allSatisfy!(hasLvalueElements, R))
1007             {
1008                 static ref RvalueElementType fixRef(ref RvalueElementType val)
1009                 {
1010                     return val;
1011                 }
1012             }
1013             else
1014             {
1015                 static RvalueElementType fixRef(RvalueElementType val)
1016                 {
1017                     return val;
1018                 }
1019             }
1020 
1021             R source;
1022             size_t frontIndex;
1023             // Always points to index one past the last non-empty range,
1024             // because otherwise decrementing while pointing to first range
1025             // would overflow to size_t.max.
1026             static if (bidirectional) size_t backIndex;
1027             else enum backIndex = source.length;
1028 
1029             this(typeof(Result.tupleof) fields)
1030             {
1031                 this.tupleof = fields;
1032             }
1033 
1034         public:
1035             this(R input)
1036             {
1037                 frontIndex = source.length;
1038                 static if (bidirectional) backIndex = 0;
1039 
1040                 foreach (i, ref v; input) source[i] = v;
1041 
1042                 // We do this separately to avoid invoking `empty` needlessly.
1043                 // While not recommended, a range may depend on side effects of
1044                 // `empty` call.
1045                 foreach (i, ref v; input) if (!v.empty)
1046                 {
1047                     frontIndex = i;
1048                     static if (bidirectional) backIndex = i+1;
1049                     break;
1050                 }
1051 
1052                 // backIndex is already set in the first loop to
1053                 // as frontIndex+1, so we'll use that if we don't find a
1054                 // non-empty range here.
1055                 static if (bidirectional)
1056                     static foreach_reverse (i; 1 .. R.length + 1)
1057                 {
1058                     if (i <= frontIndex + 1) return;
1059                     if (!input[i-1].empty)
1060                     {
1061                         backIndex = i;
1062                         return;
1063                     }
1064                 }
1065             }
1066 
1067             import std.meta : anySatisfy;
1068 
1069             static if (anySatisfy!(isInfinite, R))
1070             {
1071                 // Propagate infiniteness.
1072                 enum bool empty = false;
1073             }
1074             else
1075             {
1076                 @property bool empty()
1077                 {
1078                     if (frontIndex == 0)
1079                     {
1080                         // special handling: we might be in Range.init state!
1081                         // For instance, `format!"%s"` uses Range.init to ensure
1082                         // that formatting is possible.
1083                         // In that case, we must still behave in an internally consistent way.
1084                         return source[0].empty;
1085                     }
1086                     return frontIndex >= backIndex;
1087                 }
1088             }
1089 
1090             static if (allSatisfy!(isForwardRange, R))
1091             {
1092                 @property auto save()
1093                 {
1094                     auto saveI(size_t i)() => source[i].save;
1095 
1096                     // TODO: this has the constructor needlessly refind
1097                     // frontIndex and backIndex. It'd be better to just copy
1098                     // those from `.this`.
1099                     auto saveResult =
1100                         Result(staticMap!(saveI, aliasSeqOf!(R.length.iota)));
1101 
1102                     return saveResult;
1103                 }
1104             }
1105 
1106             void popFront()
1107             {
1108                 sw1: switch (frontIndex)
1109                 {
1110                     static foreach (i; 0 .. R.length)
1111                     {
1112                     case i:
1113                         source[i].popFront();
1114                         break sw1;
1115                     }
1116 
1117                 case R.length:
1118                     assert(0, "Attempt to `popFront` of empty `chain` range");
1119 
1120                 default:
1121                     assert(0, "Internal library error. Please report it.");
1122                 }
1123 
1124                 sw2: switch (frontIndex)
1125                 {
1126                     static foreach (i; 0 .. R.length)
1127                     {
1128                     case i:
1129                         if (source[i].empty)
1130                         {
1131                             frontIndex++;
1132                             goto case;
1133                         }
1134                         else break sw2;
1135                     }
1136 
1137                 // Only possible to reach from goto of previous case.
1138                 case R.length:
1139                     break;
1140 
1141                 default:
1142                     assert(0, "Internal library error. Please report it.");
1143                 }
1144             }
1145 
1146             @property auto ref front()
1147             {
1148                 switch (frontIndex)
1149                 {
1150                     static foreach (i; 0 .. R.length)
1151                     {
1152                     case i:
1153                         return fixRef(source[i].front);
1154                     }
1155 
1156                 case R.length:
1157                     assert(0, "Attempt to get `front` of empty `chain` range");
1158 
1159                 default:
1160                     assert(0, "Internal library error. Please report it.");
1161                 }
1162             }
1163 
1164             static if (assignableElements)
1165             {
1166                 // @@@BUG@@@
1167                 //@property void front(T)(T v) if (is(T : RvalueElementType))
1168 
1169                 @property void front(RvalueElementType v)
1170                 {
1171                     import core.lifetime : forward;
1172 
1173                     sw: switch (frontIndex)
1174                     {
1175                         static foreach (i; 0 .. R.length)
1176                         {
1177                         case i:
1178                             // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
1179                             source[i].front = __ctfe ? v : forward!v;
1180                             break sw;
1181                         }
1182 
1183                     case R.length:
1184                         assert(0, "Attempt to set `front` of empty `chain` range");
1185 
1186                     default:
1187                         assert(0, "Internal library error. Please report it.");
1188                     }
1189                 }
1190             }
1191 
1192             static if (mobileElements)
1193             {
1194                 RvalueElementType moveFront()
1195                 {
1196                     switch (frontIndex)
1197                     {
1198                         static foreach (i; 0 .. R.length)
1199                         {
1200                         case i:
1201                             return source[i].moveFront();
1202                         }
1203 
1204                     case R.length:
1205                         assert(0, "Attempt to `moveFront` of empty `chain` range");
1206 
1207                     default:
1208                         assert(0, "Internal library error. Please report it.");
1209                     }
1210                 }
1211             }
1212 
1213             static if (bidirectional)
1214             {
1215                 @property auto ref back()
1216                 {
1217                     switch (backIndex)
1218                     {
1219                         static foreach_reverse (i; 1 .. R.length + 1)
1220                         {
1221                         case i:
1222                             return fixRef(source[i-1].back);
1223                         }
1224 
1225                     case 0:
1226                         assert(0, "Attempt to get `back` of empty `chain` range");
1227 
1228                     default:
1229                         assert(0, "Internal library error. Please report it.");
1230                     }
1231                 }
1232 
1233                 void popBack()
1234                 {
1235                     sw1: switch (backIndex)
1236                     {
1237                         static foreach_reverse (i; 1 .. R.length + 1)
1238                         {
1239                         case i:
1240                             source[i-1].popBack();
1241                             break sw1;
1242                         }
1243 
1244                     case 0:
1245                         assert(0, "Attempt to `popFront` of empty `chain` range");
1246 
1247                     default:
1248                         assert(0, "Internal library error. Please report it.");
1249                     }
1250 
1251                     sw2: switch (backIndex)
1252                     {
1253                         static foreach_reverse (i; 1 .. R.length + 1)
1254                         {
1255                         case i:
1256                             if (source[i-1].empty)
1257                             {
1258                                 backIndex--;
1259                                 goto case;
1260                             }
1261                             else break sw2;
1262                         }
1263 
1264                     // Only possible to reach from goto of previous case.
1265                     case 0:
1266                         break;
1267 
1268                     default:
1269                         assert(0, "Internal library error. Please report it.");
1270                     }
1271                 }
1272 
1273                 static if (mobileElements)
1274                 {
1275                     RvalueElementType moveBack()
1276                     {
1277                         switch (backIndex)
1278                         {
1279                             static foreach_reverse (i; 1 .. R.length + 1)
1280                             {
1281                             case i:
1282                                 return source[i-1].moveBack();
1283                             }
1284 
1285                         case 0:
1286                             assert(0, "Attempt to `moveBack` of empty `chain` range");
1287 
1288                         default:
1289                             assert(0, "Internal library error. Please report it.");
1290                         }
1291                     }
1292                 }
1293 
1294                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1295                 {
1296                     @property void back(RvalueElementType v)
1297                     {
1298                         import core.lifetime : forward;
1299 
1300                         sw: switch (backIndex)
1301                         {
1302                             static foreach_reverse (i; 1 .. R.length + 1)
1303                             {
1304                             case i:
1305                                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
1306                                 source[i - 1].back = __ctfe ? v : forward!v;
1307                                 break sw;
1308                             }
1309 
1310                         case 0:
1311                             assert(0, "Attempt to set `back` of empty `chain` range");
1312 
1313                         default:
1314                             assert(0, "Internal library error. Please report it.");
1315                         }
1316                     }
1317                 }
1318             }
1319 
1320             static if (allSatisfy!(hasLength, R))
1321             {
1322                 @property size_t length()
1323                 {
1324                     size_t result = 0;
1325                     sw: switch (frontIndex)
1326                     {
1327                         static foreach (i; 0 .. R.length)
1328                         {
1329                         case i:
1330                             result += source[i].length;
1331                             if (backIndex == i+1) break sw;
1332                             else goto case;
1333                         }
1334 
1335                     case R.length:
1336                         break;
1337 
1338                     default:
1339                         assert(0, "Internal library error. Please report it.");
1340                     }
1341 
1342                     return result;
1343                 }
1344 
1345                 alias opDollar = length;
1346             }
1347 
1348             static if (allSatisfy!(isRandomAccessRange, R))
1349             {
1350                 auto ref opIndex(size_t index)
1351                 {
1352                     switch (frontIndex)
1353                     {
1354                         static foreach (i; 0 .. R.length)
1355                         {
1356                         case i:
1357                             static if (!isInfinite!(R[i]))
1358                             {
1359                                 immutable length = source[i].length;
1360                                 if (index >= length)
1361                                 {
1362                                     index -= length;
1363                                     goto case;
1364                                 }
1365                             }
1366 
1367                             return fixRef(source[i][index]);
1368                         }
1369 
1370                     case R.length:
1371                         assert(0, "Attempt to access out-of-bounds index of `chain` range");
1372 
1373                     default:
1374                         assert(0, "Internal library error. Please report it.");
1375                     }
1376                 }
1377 
1378                 static if (mobileElements)
1379                 {
1380                     RvalueElementType moveAt(size_t index)
1381                     {
1382                         switch (frontIndex)
1383                         {
1384                             static foreach (i; 0 .. R.length)
1385                             {
1386                             case i:
1387                                 static if (!isInfinite!(R[i]))
1388                                 {
1389                                     immutable length = source[i].length;
1390                                     if (index >= length)
1391                                     {
1392                                         index -= length;
1393                                         goto case;
1394                                     }
1395                                 }
1396 
1397                                 return source[i].moveAt(index);
1398                             }
1399 
1400                         case R.length:
1401                             assert(0, "Attempt to move out-of-bounds index of `chain` range");
1402 
1403                         default:
1404                             assert(0, "Internal library error. Please report it.");
1405                         }
1406                     }
1407                 }
1408 
1409                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1410                     void opIndexAssign(ElementType v, size_t index)
1411                     {
1412                         import core.lifetime : forward;
1413 
1414                         sw: switch (frontIndex)
1415                         {
1416                             static foreach (i; 0 .. R.length)
1417                             {
1418                             case i:
1419                                 static if (!isInfinite!(R[i]))
1420                                 {
1421                                     immutable length = source[i].length;
1422                                     if (index >= length)
1423                                     {
1424                                         index -= length;
1425                                         goto case;
1426                                     }
1427                                 }
1428 
1429                                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
1430                                 source[i][index] = __ctfe ? v : forward!v;
1431                                 break sw;
1432                             }
1433 
1434                         case R.length:
1435                             assert(0, "Attempt to write out-of-bounds index of `chain` range");
1436 
1437                         default:
1438                             assert(0, "Internal library error. Please report it.");
1439                         }
1440                     }
1441             }
1442 
1443             static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
1444                 auto opSlice(size_t begin, size_t end) return scope
1445                 {
1446                     // force staticMap type conversion to Rebindable
1447                     static struct ResultRanges
1448                     {
1449                         staticMap!(Rebindable, typeof(source)) fields;
1450                     }
1451                     auto sourceI(size_t i)() => rebindable(this.source[i]);
1452                     auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields;
1453                     size_t resultFrontIndex = this.frontIndex;
1454                     static if (bidirectional)
1455                         size_t resultBackIndex = this.backIndex;
1456 
1457                     sw: switch (frontIndex)
1458                     {
1459                         static foreach (i; 0 .. R.length)
1460                         {
1461                         case i:
1462                             immutable len = resultRanges[i].length;
1463                             if (len <= begin)
1464                             {
1465                                 resultRanges[i] = resultRanges[i]
1466                                     [len .. len];
1467                                 begin -= len;
1468                                 resultFrontIndex++;
1469                                 goto case;
1470                             }
1471                             else
1472                             {
1473                                 resultRanges[i] = resultRanges[i]
1474                                     [begin .. len];
1475                                 break sw;
1476                             }
1477                         }
1478 
1479                     case R.length:
1480                         assert(begin == 0,
1481                             "Attempt to access out-of-bounds slice of `chain` range");
1482                         break;
1483 
1484                     default:
1485                         assert(0, "Internal library error. Please report it.");
1486                     }
1487 
1488                     // Overflow intentional if end index too big.
1489                     // This will trigger the bounds check failure below.
1490                     auto cut = length - end;
1491 
1492                     sw2: switch (backIndex)
1493                     {
1494                         static foreach_reverse (i; 1 .. R.length + 1)
1495                         {
1496                         case i:
1497                             immutable len = resultRanges[i-1].length;
1498                             if (len <= cut)
1499                             {
1500                                 resultRanges[i-1] = resultRanges[i-1]
1501                                     [0 .. 0];
1502                                 cut -= len;
1503                                 resultBackIndex--;
1504                                 goto case;
1505                             }
1506                             else
1507                             {
1508                                 resultRanges[i-1] = resultRanges[i-1]
1509                                     [0 .. len - cut];
1510                                 break sw2;
1511                             }
1512                         }
1513 
1514                     case 0:
1515                         assert(cut == 0, end > length?
1516                             "Attempt to access out-of-bounds slice of `chain` range":
1517                             "Attempt to access negative length slice of `chain` range");
1518                         break sw2;
1519 
1520                     default:
1521                         assert(0, "Internal library error. Please report it.");
1522                     }
1523 
1524                     static if (bidirectional)
1525                         return Result(resultRanges, resultFrontIndex, resultBackIndex);
1526                     else
1527                         return Result(resultRanges, resultFrontIndex);
1528                 }
1529         }
1530         return Result(rs);
1531     }
1532 }
1533 
1534 ///
1535 pure @safe nothrow unittest
1536 {
1537     import std.algorithm.comparison : equal;
1538 
1539     int[] arr1 = [ 1, 2, 3, 4 ];
1540     int[] arr2 = [ 5, 6 ];
1541     int[] arr3 = [ 7 ];
1542     auto s = chain(arr1, arr2, arr3);
1543     assert(s.length == 7);
1544     assert(s[5] == 6);
1545     assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1546 }
1547 
1548 /**
1549  * Range primitives are carried over to the returned range if
1550  * all of the ranges provide them
1551  */
1552 pure @safe nothrow unittest
1553 {
1554     import std.algorithm.comparison : equal;
1555     import std.algorithm.sorting : sort;
1556 
1557     int[] arr1 = [5, 2, 8];
1558     int[] arr2 = [3, 7, 9];
1559     int[] arr3 = [1, 4, 6];
1560 
1561     // in-place sorting across all of the arrays
1562     auto s = arr1.chain(arr2, arr3).sort;
1563 
1564     assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1565     assert(arr1.equal([1, 2, 3]));
1566     assert(arr2.equal([4, 5, 6]));
1567     assert(arr3.equal([7, 8, 9]));
1568 }
1569 
1570 /**
1571 Due to safe type promotion in D, chaining together different
1572 character ranges results in a `uint` range.
1573 
1574 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf),
1575 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges
1576 to get the type you need.
1577  */
1578 pure @safe nothrow unittest
1579 {
1580     import std.utf : byChar, byCodeUnit;
1581 
1582     auto s1 = "string one";
1583     auto s2 = "string two";
1584     // s1 and s2 front is dchar because of auto-decoding
1585     static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
1586 
1587     auto r1 = s1.chain(s2);
1588     // chains of ranges of the same character type give that same type
1589     static assert(is(typeof(r1.front) == dchar));
1590 
1591     auto s3 = "string three".byCodeUnit;
1592     static assert(is(typeof(s3.front) == immutable char));
1593     auto r2 = s1.chain(s3);
1594     // chaining ranges of mixed character types gives `dchar`
1595     static assert(is(typeof(r2.front) == dchar));
1596 
1597     // use byChar on character ranges to correctly convert them to UTF-8
1598     auto r3 = s1.byChar.chain(s3);
1599     static assert(is(typeof(r3.front) == immutable char));
1600 }
1601 
1602 pure @safe nothrow unittest
1603 {
1604     import std.algorithm.comparison : equal;
1605     import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1606                                           propagatesRangeType;
1607 
1608     {
1609         int[] arr1 = [ 1, 2, 3, 4 ];
1610         int[] arr2 = [ 5, 6 ];
1611         int[] arr3 = [ 7 ];
1612         int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1613         auto s1 = chain(arr1);
1614         static assert(isRandomAccessRange!(typeof(s1)));
1615         auto s2 = chain(arr1, arr2);
1616         static assert(isBidirectionalRange!(typeof(s2)));
1617         static assert(isRandomAccessRange!(typeof(s2)));
1618         s2.front = 1;
1619         auto s = chain(arr1, arr2, arr3);
1620         assert(s[5] == 6);
1621         assert(equal(s, witness));
1622         assert(s[4 .. 6].equal(arr2));
1623         assert(s[2 .. 5].equal([3, 4, 5]));
1624         assert(s[0 .. 0].empty);
1625         assert(s[7 .. $].empty);
1626         assert(s[5] == 6);
1627     }
1628     {
1629         int[] arr1 = [ 1, 2, 3, 4 ];
1630         int[] witness = [ 1, 2, 3, 4 ];
1631         assert(equal(chain(arr1), witness));
1632     }
1633     {
1634         uint[] foo = [1,2,3,4,5];
1635         uint[] bar = [1,2,3,4,5];
1636         auto c = chain(foo, bar);
1637         c[3] = 42;
1638         assert(c[3] == 42);
1639         assert(c.moveFront() == 1);
1640         assert(c.moveBack() == 5);
1641         assert(c.moveAt(4) == 5);
1642         assert(c.moveAt(5) == 1);
1643     }
1644 
1645 
1646     // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed.
1647     // elements are mutable.
1648     assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1649 
1650     // Test the case where infinite ranges are present.
1651     auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1652     assert(inf[0] == 0);
1653     assert(inf[3] == 4);
1654     assert(inf[6] == 4);
1655     assert(inf[7] == 5);
1656     static assert(isInfinite!(typeof(inf)));
1657 
1658     immutable int[] immi = [ 1, 2, 3 ];
1659     immutable float[] immf = [ 1, 2, 3 ];
1660     static assert(is(typeof(chain(immi, immf))));
1661 
1662     // Check that chain at least instantiates and compiles with every possible
1663     // pair of DummyRange types, in either order.
1664 
1665     foreach (DummyType1; AllDummyRanges)
1666     (){ // workaround slow optimizations for large functions
1667         // https://issues.dlang.org/show_bug.cgi?id=2396
1668         DummyType1 dummy1;
1669         foreach (DummyType2; AllDummyRanges)
1670         {
1671             DummyType2 dummy2;
1672             auto myChain = chain(dummy1, dummy2);
1673 
1674             static assert(
1675                 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1676             );
1677 
1678             assert(myChain.front == 1);
1679             foreach (i; 0 .. dummyLength)
1680             {
1681                 myChain.popFront();
1682             }
1683             assert(myChain.front == 1);
1684 
1685             static if (isBidirectionalRange!DummyType1 &&
1686                       isBidirectionalRange!DummyType2) {
1687                 assert(myChain.back == 10);
1688             }
1689 
1690             static if (isRandomAccessRange!DummyType1 &&
1691                       isRandomAccessRange!DummyType2) {
1692                 assert(myChain[0] == 1);
1693             }
1694 
1695             static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1696             {
1697                 static assert(hasLvalueElements!(typeof(myChain)));
1698             }
1699             else
1700             {
1701                 static assert(!hasLvalueElements!(typeof(myChain)));
1702             }
1703         }
1704     }();
1705 }
1706 
1707 pure @safe nothrow @nogc unittest
1708 {
1709     class Foo{}
1710     immutable(Foo)[] a;
1711     immutable(Foo)[] b;
1712     assert(chain(a, b).empty);
1713 }
1714 
1715 // https://issues.dlang.org/show_bug.cgi?id=18657
1716 pure @safe unittest
1717 {
1718     import std.algorithm.comparison : equal;
1719     string s = "foo";
1720     auto r = refRange(&s).chain("bar");
1721     assert(equal(r.save, "foobar"));
1722     assert(equal(r, "foobar"));
1723 }
1724 
1725 // https://issues.dlang.org/show_bug.cgi?id=23844
1726 pure @safe unittest
1727 {
1728     struct S
1729     {
1730         immutable int value;
1731     }
1732 
1733     auto range = chain(only(S(5)), only(S(6)));
1734     assert(range.array == [S(5), S(6)]);
1735 }
1736 
1737 // https://issues.dlang.org/show_bug.cgi?id=24064
1738 pure @safe nothrow unittest
1739 {
1740     import std.algorithm.comparison : equal;
1741     import std.typecons : Nullable;
1742 
1743     immutable Nullable!string foo = "b";
1744     string[] bar = ["a"];
1745     assert(chain(bar, foo).equal(["a", "b"]));
1746 }
1747 
1748 pure @safe nothrow @nogc unittest
1749 {
1750     // support non-copyable items
1751 
1752     static struct S {
1753         int v;
1754         @disable this(this);
1755     }
1756 
1757     S[2] s0, s1;
1758     foreach (ref el; chain(s0[], s1[]))
1759     {
1760         int n = el.v;
1761     }
1762 
1763     S[] s2, s3;
1764     foreach (ref el; chain(s2, s3))
1765     {
1766         int n = el.v;
1767     }
1768 }
1769 
1770 // https://issues.dlang.org/show_bug.cgi?id=24243
1771 pure @safe nothrow unittest
1772 {
1773     import std.algorithm.iteration : filter;
1774 
1775     auto range = chain([2], [3].filter!"a");
1776 
1777     // This might happen in format!"%s"(range), for instance.
1778     assert(typeof(range).init.empty);
1779 }
1780 
1781 // https://issues.dlang.org/show_bug.cgi?id=24481
1782 @safe unittest
1783 {
1784     bool called;
1785     struct Handle
1786     {
1787         int entry;
1788         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
1789     }
1790 
1791     const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
1792     auto range = arr[0 .. 2].chain(arr[4 .. 5]);
1793 
1794     called = false;
1795     range.front = Handle(42);
1796     assert(called);
1797 
1798     called = false;
1799     range.back = Handle(42);
1800     assert(called);
1801 
1802     called = false;
1803     range[2] = Handle(42);
1804     assert(called);
1805 }
1806 
1807 /**
1808 Choose one of two ranges at runtime depending on a Boolean condition.
1809 
1810 The ranges may be different, but they must have compatible element types (i.e.
1811 `CommonType` must exist for the two element types). The result is a range
1812 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D
1813 R1) is a random-access range and `R2` is a forward range).
1814 
1815 Params:
1816     condition = which range to choose: `r1` if `true`, `r2` otherwise
1817     r1 = the "true" range
1818     r2 = the "false" range
1819 
1820 Returns:
1821     A range type dependent on `R1` and `R2`.
1822  */
1823 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
1824 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1825     !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1826 {
1827     size_t choice = condition? 0: 1;
1828     return ChooseResult!(R1, R2)(choice, r1, r2);
1829 }
1830 
1831 ///
1832 @safe nothrow pure @nogc unittest
1833 {
1834     import std.algorithm.comparison : equal;
1835     import std.algorithm.iteration : filter, map;
1836 
1837     auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
1838     auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
1839 
1840     // choose() is primarily useful when you need to select one of two ranges
1841     // with different types at runtime.
1842     static assert(!is(typeof(data1) == typeof(data2)));
1843 
1844     auto chooseRange(bool pickFirst)
1845     {
1846         // The returned range is a common wrapper type that can be used for
1847         // returning or storing either range without running into a type error.
1848         return choose(pickFirst, data1, data2);
1849 
1850         // Simply returning the chosen range without using choose() does not
1851         // work, because map() and filter() return different types.
1852         //return pickFirst ? data1 : data2; // does not compile
1853     }
1854 
1855     auto result = chooseRange(true);
1856     assert(result.equal(only(1, 2, 4)));
1857 
1858     result = chooseRange(false);
1859     assert(result.equal(only(6, 7, 8, 9)));
1860 }
1861 
1862 
1863 private struct ChooseResult(Ranges...)
1864 {
1865     import std.meta : aliasSeqOf, ApplyLeft;
1866     import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor,
1867         lvalueOf;
1868 
1869     private union
1870     {
1871         Ranges rs;
1872     }
1873     private size_t chosenI;
1874 
1875     private static auto ref actOnChosen(alias foo, ExtraArgs ...)
1876         (ref ChooseResult r, auto ref ExtraArgs extraArgs)
1877     {
1878         ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1879 
1880         switch (r.chosenI)
1881         {
1882             static foreach (candI; 0 .. rs.length)
1883             {
1884                 case candI: return foo(getI!candI(r), extraArgs);
1885             }
1886 
1887             default: assert(false);
1888         }
1889     }
1890 
1891     // @trusted because of assignment of r which overlap each other
1892     this(size_t chosen, return scope Ranges rs) @trusted
1893     {
1894         import core.lifetime : emplace;
1895 
1896         // This should be the only place chosenI is ever assigned
1897         // independently
1898         this.chosenI = chosen;
1899 
1900         // Otherwise the compiler will complain about skipping these fields
1901         static foreach (i; 0 .. rs.length)
1902         {
1903             this.rs[i] = Ranges[i].init;
1904         }
1905 
1906         // The relevant field needs to be initialized last so it will overwrite
1907         // the other initializations and not the other way around.
1908         sw: switch (chosenI)
1909         {
1910             static foreach (i; 0 .. rs.length)
1911             {
1912                 case i:
1913                 emplace(&this.rs[i], rs[i]);
1914                 break sw;
1915             }
1916 
1917             default: assert(false);
1918         }
1919     }
1920 
1921     // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/)
1922     // without this overload the regular constructor would invert the meaning of
1923     // the boolean
1924     static if (rs.length == 2)
1925     pragma(inline, true)
1926     deprecated("Call with size_t (0 = first), or use the choose function")
1927     this(bool firstChosen, Ranges rs)
1928     {
1929         import core.lifetime : move;
1930         this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move);
1931     }
1932 
1933     void opAssign(ChooseResult r)
1934     {
1935         ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1936 
1937         static if (anySatisfy!(hasElaborateDestructor, Ranges))
1938             if (chosenI != r.chosenI)
1939         {
1940             // destroy the current item
1941             actOnChosen!((ref r) => destroy(r))(this);
1942         }
1943         chosenI = r.chosenI;
1944 
1945         sw: switch (chosenI)
1946         {
1947             static foreach (candI; 0 .. rs.length)
1948             {
1949                 case candI: getI!candI(this) = getI!candI(r);
1950                 break sw;
1951             }
1952 
1953             default: assert(false);
1954         }
1955     }
1956 
1957     // Carefully defined postblit to postblit the appropriate range
1958     static if (anySatisfy!(hasElaborateCopyConstructor, Ranges))
1959     this(this)
1960     {
1961         actOnChosen!((ref r) {
1962                 static if (hasElaborateCopyConstructor!(typeof(r))) r.__xpostblit();
1963             })(this);
1964     }
1965 
1966     static if (anySatisfy!(hasElaborateDestructor, Ranges))
1967     ~this()
1968     {
1969         actOnChosen!((ref r) => destroy(r))(this);
1970     }
1971 
1972     // Propagate infiniteness.
1973     static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false;
1974     else @property bool empty()
1975     {
1976         return actOnChosen!(r => r.empty)(this);
1977     }
1978 
1979     @property auto ref front()
1980     {
1981         static auto ref getFront(R)(ref R r) { return r.front; }
1982         return actOnChosen!getFront(this);
1983     }
1984 
1985     void popFront()
1986     {
1987         return actOnChosen!((ref r) { r.popFront; })(this);
1988     }
1989 
1990     static if (allSatisfy!(isForwardRange, Ranges))
1991     @property auto save() // return scope inferred
1992     {
1993         auto saveOrInit(size_t i)()
1994         {
1995             ref getI() @trusted { return rs[i]; }
1996             if (i == chosenI) return getI().save;
1997             else return Ranges[i].init;
1998         }
1999 
2000         return typeof(this)(chosenI, staticMap!(saveOrInit,
2001             aliasSeqOf!(rs.length.iota)));
2002     }
2003 
2004     template front(T)
2005     {
2006         private enum overloadValidFor(alias r) = is(typeof(r.front = T.init));
2007 
2008         static if (allSatisfy!(overloadValidFor, rs))
2009         void front(T v)
2010         {
2011             actOnChosen!((ref r, T v) { r.front = v; })(this, v);
2012         }
2013     }
2014 
2015     static if (allSatisfy!(hasMobileElements, Ranges))
2016     auto moveFront()
2017     {
2018         return actOnChosen!((ref r) => r.moveFront)(this);
2019     }
2020 
2021     static if (allSatisfy!(isBidirectionalRange, Ranges))
2022     {
2023         @property auto ref back()
2024         {
2025             static auto ref getBack(R)(ref R r) { return r.back; }
2026             return actOnChosen!getBack(this);
2027         }
2028 
2029         void popBack()
2030         {
2031             actOnChosen!((ref r) { r.popBack; })(this);
2032         }
2033 
2034         static if (allSatisfy!(hasMobileElements, Ranges))
2035         auto moveBack()
2036         {
2037             return actOnChosen!((ref r) => r.moveBack)(this);
2038         }
2039 
2040         template back(T)
2041         {
2042             private enum overloadValidFor(alias r) = is(typeof(r.back = T.init));
2043 
2044             static if (allSatisfy!(overloadValidFor, rs))
2045             void back(T v)
2046             {
2047                 actOnChosen!((ref r, T v) { r.back = v; })(this, v);
2048             }
2049         }
2050     }
2051 
2052     static if (allSatisfy!(hasLength, Ranges))
2053     {
2054         @property size_t length()
2055         {
2056             return actOnChosen!(r => r.length)(this);
2057         }
2058         alias opDollar = length;
2059     }
2060 
2061     static if (allSatisfy!(isRandomAccessRange, Ranges))
2062     {
2063         auto ref opIndex(size_t index)
2064         {
2065             static auto ref get(R)(ref R r, size_t index) { return r[index]; }
2066             return actOnChosen!get(this, index);
2067         }
2068 
2069         static if (allSatisfy!(hasMobileElements, Ranges))
2070             auto moveAt(size_t index)
2071             {
2072                 return actOnChosen!((ref r, size_t index) => r.moveAt(index))
2073                     (this, index);
2074             }
2075 
2076         private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init));
2077 
2078         template opIndexAssign(T)
2079         if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges))
2080         {
2081             void opIndexAssign(T v, size_t index)
2082             {
2083                 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
2084                     (this, index, v);
2085             }
2086         }
2087     }
2088 
2089     static if (allSatisfy!(hasSlicing, Ranges))
2090     auto opSlice(size_t begin, size_t end)
2091     {
2092         alias Slice(R) = typeof(R.init[0 .. 1]);
2093         alias Slices = staticMap!(Slice, Ranges);
2094 
2095         auto sliceOrInit(size_t i)()
2096         {
2097             ref getI() @trusted { return rs[i]; }
2098             return i == chosenI? getI()[begin .. end]: Slices[i].init;
2099         }
2100 
2101         return chooseAmong(chosenI, staticMap!(sliceOrInit,
2102             aliasSeqOf!(rs.length.iota)));
2103     }
2104 }
2105 
2106 // https://issues.dlang.org/show_bug.cgi?id=18657
2107 pure @safe unittest
2108 {
2109     import std.algorithm.comparison : equal;
2110     string s = "foo";
2111     auto r = choose(true, refRange(&s), "bar");
2112     assert(equal(r.save, "foo"));
2113     assert(equal(r, "foo"));
2114 }
2115 
2116 @safe unittest
2117 {
2118     static void* p;
2119     static struct R
2120     {
2121         void* q;
2122         int front;
2123         bool empty;
2124         void popFront() {}
2125         // `p = q;` is only there to prevent inference of `scope return`.
2126         @property @safe R save() { p = q; return this; }
2127 
2128     }
2129     R r;
2130     choose(true, r, r).save;
2131 }
2132 
2133 // Make sure ChooseResult.save doesn't trust @system user code.
2134 @system unittest // copy is @system
2135 {
2136     static struct R
2137     {
2138         int front;
2139         bool empty;
2140         void popFront() {}
2141         this(this) @system {}
2142         @property R save() { return R(front, empty); }
2143     }
2144     choose(true, R(), R()).save;
2145     choose(true, [0], R()).save;
2146     choose(true, R(), [0]).save;
2147 }
2148 
2149 @safe unittest // copy is @system
2150 {
2151     static struct R
2152     {
2153         int front;
2154         bool empty;
2155         void popFront() {}
2156         this(this) @system {}
2157         @property R save() { return R(front, empty); }
2158     }
2159     static assert(!__traits(compiles, choose(true, R(), R()).save));
2160     static assert(!__traits(compiles, choose(true, [0], R()).save));
2161     static assert(!__traits(compiles, choose(true, R(), [0]).save));
2162 }
2163 
2164 @system unittest // .save is @system
2165 {
2166     static struct R
2167     {
2168         int front;
2169         bool empty;
2170         void popFront() {}
2171         @property R save() @system { return this; }
2172     }
2173     choose(true, R(), R()).save;
2174     choose(true, [0], R()).save;
2175     choose(true, R(), [0]).save;
2176 }
2177 
2178 @safe unittest // .save is @system
2179 {
2180     static struct R
2181     {
2182         int front;
2183         bool empty;
2184         void popFront() {}
2185         @property R save() @system { return this; }
2186     }
2187     static assert(!__traits(compiles, choose(true, R(), R()).save));
2188     static assert(!__traits(compiles, choose(true, [0], R()).save));
2189     static assert(!__traits(compiles, choose(true, R(), [0]).save));
2190 }
2191 
2192 //https://issues.dlang.org/show_bug.cgi?id=19738
2193 @safe nothrow pure @nogc unittest
2194 {
2195     static struct EvilRange
2196     {
2197         enum empty = true;
2198         int front;
2199         void popFront() @safe {}
2200         auto opAssign(const ref EvilRange other)
2201         {
2202             *(cast(uint*) 0xcafebabe) = 0xdeadbeef;
2203             return this;
2204         }
2205     }
2206 
2207     static assert(!__traits(compiles, () @safe
2208     {
2209         auto c1 = choose(true, EvilRange(), EvilRange());
2210         auto c2 = c1;
2211         c1 = c2;
2212     }));
2213 }
2214 
2215 
2216 // https://issues.dlang.org/show_bug.cgi?id=20495
2217 @safe unittest
2218 {
2219     static struct KillableRange
2220     {
2221         int *item;
2222         ref int front() { return *item; }
2223         bool empty() { return *item > 10; }
2224         void popFront() { ++(*item); }
2225         this(this)
2226         {
2227             assert(item is null || cast(size_t) item > 1000);
2228             item = new int(*item);
2229         }
2230         KillableRange save() { return this; }
2231     }
2232 
2233     auto kr = KillableRange(new int(1));
2234     int[] x = [1,2,3,4,5]; // length is first
2235 
2236     auto chosen = choose(true, x, kr);
2237     auto chosen2 = chosen.save;
2238 }
2239 
2240 pure @safe nothrow unittest
2241 {
2242     static struct S {
2243         int v;
2244         @disable this(this);
2245     }
2246 
2247     auto a = [S(1), S(2), S(3)];
2248     auto b = [S(4), S(5), S(6)];
2249 
2250     auto chosen = choose(true, a, b);
2251     assert(chosen.front.v == 1);
2252 
2253     auto chosen2 = choose(false, a, b);
2254     assert(chosen2.front.v == 4);
2255 }
2256 
2257 // https://issues.dlang.org/show_bug.cgi?id=15708
2258 @safe unittest
2259 {
2260     static struct HasPostblit
2261     {
2262         this(this) {}
2263     }
2264 
2265     static struct Range
2266     {
2267         bool empty;
2268         int front;
2269         void popFront() {}
2270         HasPostblit member;
2271     }
2272 
2273     Range range;
2274     int[] arr;
2275 
2276     auto chosen = choose(true, range, arr);
2277     auto copy = chosen;
2278 }
2279 
2280 /**
2281 Choose one of multiple ranges at runtime.
2282 
2283 The ranges may be different, but they must have compatible element types. The
2284 result is a range that offers the weakest capabilities of all `Ranges`.
2285 
2286 Params:
2287     index = which range to choose, must be less than the number of ranges
2288     rs = two or more ranges
2289 
2290 Returns:
2291     The indexed range. If rs consists of only one range, the return type is an
2292     alias of that range's type.
2293  */
2294 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
2295 if (Ranges.length >= 2
2296         && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
2297         && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
2298 {
2299         return ChooseResult!Ranges(index, rs);
2300 }
2301 
2302 ///
2303 @safe nothrow pure @nogc unittest
2304 {
2305     auto test()
2306     {
2307         import std.algorithm.comparison : equal;
2308 
2309         int[4] sarr1 = [1, 2, 3, 4];
2310         int[2] sarr2 = [5, 6];
2311         int[1] sarr3 = [7];
2312         auto arr1 = sarr1[];
2313         auto arr2 = sarr2[];
2314         auto arr3 = sarr3[];
2315 
2316         {
2317             auto s = chooseAmong(0, arr1, arr2, arr3);
2318             auto t = s.save;
2319             assert(s.length == 4);
2320             assert(s[2] == 3);
2321             s.popFront();
2322             assert(equal(t, only(1, 2, 3, 4)));
2323         }
2324         {
2325             auto s = chooseAmong(1, arr1, arr2, arr3);
2326             assert(s.length == 2);
2327             s.front = 8;
2328             assert(equal(s, only(8, 6)));
2329         }
2330         {
2331             auto s = chooseAmong(1, arr1, arr2, arr3);
2332             assert(s.length == 2);
2333             s[1] = 9;
2334             assert(equal(s, only(8, 9)));
2335         }
2336         {
2337             auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
2338             assert(s.length == 2);
2339             assert(equal(s, only(2, 3)));
2340         }
2341         {
2342             auto s = chooseAmong(0, arr1, arr2, arr3);
2343             assert(s.length == 4);
2344             assert(s.back == 4);
2345             s.popBack();
2346             s.back = 5;
2347             assert(equal(s, only(1, 2, 5)));
2348             s.back = 3;
2349             assert(equal(s, only(1, 2, 3)));
2350         }
2351         {
2352             uint[5] foo = [1, 2, 3, 4, 5];
2353             uint[5] bar = [6, 7, 8, 9, 10];
2354             auto c = chooseAmong(1, foo[], bar[]);
2355             assert(c[3] == 9);
2356             c[3] = 42;
2357             assert(c[3] == 42);
2358             assert(c.moveFront() == 6);
2359             assert(c.moveBack() == 10);
2360             assert(c.moveAt(4) == 10);
2361         }
2362         {
2363             import std.range : cycle;
2364             auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
2365             assert(isInfinite!(typeof(s)));
2366             assert(!s.empty);
2367             assert(s[100] == 8);
2368             assert(s[101] == 9);
2369             assert(s[0 .. 3].equal(only(8, 9, 8)));
2370         }
2371         return 0;
2372     }
2373     // works at runtime
2374     auto a = test();
2375     // and at compile time
2376     static b = test();
2377 }
2378 
2379 @safe nothrow pure @nogc unittest
2380 {
2381     int[3] a = [1, 2, 3];
2382     long[3] b = [4, 5, 6];
2383     auto c = chooseAmong(0, a[], b[]);
2384     c[0] = 42;
2385     assert(c[0] == 42);
2386 }
2387 
2388 @safe nothrow pure @nogc unittest
2389 {
2390     static struct RefAccessRange
2391     {
2392         int[] r;
2393         ref front() @property { return r[0]; }
2394         ref back() @property { return r[$ - 1]; }
2395         void popFront() { r = r[1 .. $]; }
2396         void popBack() { r = r[0 .. $ - 1]; }
2397         auto empty() @property { return r.empty; }
2398         ref opIndex(size_t i) { return r[i]; }
2399         auto length() @property { return r.length; }
2400         alias opDollar = length;
2401         auto save() { return this; }
2402     }
2403     static assert(isRandomAccessRange!RefAccessRange);
2404     static assert(isRandomAccessRange!RefAccessRange);
2405     int[4] a = [4, 3, 2, 1];
2406     int[2] b = [6, 5];
2407     auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[]));
2408 
2409     void refFunc(ref int a, int target) { assert(a == target); }
2410 
2411     refFunc(c[2], 2);
2412     refFunc(c.front, 4);
2413     refFunc(c.back, 1);
2414 }
2415 
2416 
2417 /**
2418 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`,
2419 then `r3.front`, after which it pops off one element from each and
2420 continues again from `r1`. For example, if two ranges are involved,
2421 it alternately yields elements off the two ranges. `roundRobin`
2422 stops after it has consumed all ranges (skipping over the ones that
2423 finish early).
2424  */
2425 auto roundRobin(Rs...)(Rs rs)
2426 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
2427 {
2428     struct Result
2429     {
2430         import std.conv : to;
2431 
2432         public Rs source;
2433         private size_t _current = size_t.max;
2434 
2435         @property bool empty()
2436         {
2437             foreach (i, Unused; Rs)
2438             {
2439                 if (!source[i].empty) return false;
2440             }
2441             return true;
2442         }
2443 
2444         @property auto ref front()
2445         {
2446             final switch (_current)
2447             {
2448                 foreach (i, R; Rs)
2449                 {
2450                     case i:
2451                         assert(
2452                             !source[i].empty,
2453                             "Attempting to fetch the front of an empty roundRobin"
2454                         );
2455                         return source[i].front;
2456                 }
2457             }
2458             assert(0);
2459         }
2460 
2461         void popFront()
2462         {
2463             final switch (_current)
2464             {
2465                 foreach (i, R; Rs)
2466                 {
2467                     case i:
2468                         source[i].popFront();
2469                         break;
2470                 }
2471             }
2472 
2473             auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
2474             final switch (next)
2475             {
2476                 foreach (i, R; Rs)
2477                 {
2478                     case i:
2479                         if (!source[i].empty)
2480                         {
2481                             _current = i;
2482                             return;
2483                         }
2484                         if (i == _current)
2485                         {
2486                             _current = _current.max;
2487                             return;
2488                         }
2489                         goto case (i + 1) % Rs.length;
2490                 }
2491             }
2492         }
2493 
2494         static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
2495             @property auto save()
2496             {
2497                 auto saveSource(size_t len)()
2498                 {
2499                     import std.typecons : tuple;
2500                     static assert(len > 0);
2501                     static if (len == 1)
2502                     {
2503                         return tuple(source[0].save);
2504                     }
2505                     else
2506                     {
2507                         return saveSource!(len - 1)() ~
2508                             tuple(source[len - 1].save);
2509                     }
2510                 }
2511                 return Result(saveSource!(Rs.length).expand, _current);
2512             }
2513 
2514         static if (allSatisfy!(hasLength, Rs))
2515         {
2516             @property size_t length()
2517             {
2518                 size_t result;
2519                 foreach (i, R; Rs)
2520                 {
2521                     result += source[i].length;
2522                 }
2523                 return result;
2524             }
2525 
2526             alias opDollar = length;
2527         }
2528     }
2529 
2530     size_t firstNonEmpty = size_t.max;
2531     static foreach (i; 0 .. Rs.length)
2532     {
2533         if (firstNonEmpty == size_t.max && !rs[i].empty)
2534             firstNonEmpty = i;
2535     }
2536 
2537     return Result(rs, firstNonEmpty);
2538 }
2539 
2540 ///
2541 @safe unittest
2542 {
2543     import std.algorithm.comparison : equal;
2544 
2545     int[] a = [ 1, 2, 3 ];
2546     int[] b = [ 10, 20, 30, 40 ];
2547     auto r = roundRobin(a, b);
2548     assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
2549 }
2550 
2551 /**
2552  * roundRobin can be used to create "interleave" functionality which inserts
2553  * an element between each element in a range.
2554  */
2555 @safe unittest
2556 {
2557     import std.algorithm.comparison : equal;
2558 
2559     auto interleave(R, E)(R range, E element)
2560     if ((isInputRange!R && hasLength!R) || isForwardRange!R)
2561     {
2562         static if (hasLength!R)
2563             immutable len = range.length;
2564         else
2565             immutable len = range.save.walkLength;
2566 
2567         return roundRobin(
2568             range,
2569             element.repeat(len - 1)
2570         );
2571     }
2572 
2573     assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
2574 }
2575 
2576 pure @safe unittest
2577 {
2578     import std.algorithm.comparison : equal;
2579     string f = "foo", b = "bar";
2580     auto r = roundRobin(refRange(&f), refRange(&b));
2581     assert(equal(r.save, "fboaor"));
2582     assert(equal(r.save, "fboaor"));
2583 }
2584 pure @safe nothrow unittest
2585 {
2586     import std.algorithm.comparison : equal;
2587 
2588     static struct S {
2589         int v;
2590         @disable this(this);
2591     }
2592 
2593     S[] a = [ S(1), S(2) ];
2594     S[] b = [ S(10), S(20) ];
2595     auto r = roundRobin(a, b);
2596     assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
2597 }
2598 
2599 // https://issues.dlang.org/show_bug.cgi?id=24384
2600 @safe unittest
2601 {
2602     auto r = roundRobin("", "a");
2603     assert(!r.empty);
2604     auto e = r.front;
2605 }
2606 
2607 /**
2608 Iterates a random-access range starting from a given point and
2609 progressively extending left and right from that point. If no initial
2610 point is given, iteration starts from the middle of the
2611 range. Iteration spans the entire range.
2612 
2613 When `startingIndex` is 0 the range will be fully iterated in order
2614 and in reverse order when `r.length` is given.
2615 
2616 Params:
2617     r = a random access range with length and slicing
2618     startingIndex = the index to begin iteration from
2619 
2620 Returns:
2621     A forward range with length
2622  */
2623 auto radial(Range, I)(Range r, I startingIndex)
2624 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
2625 {
2626     if (startingIndex != r.length) ++startingIndex;
2627     return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
2628 }
2629 
2630 /// Ditto
2631 auto radial(R)(R r)
2632 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
2633 {
2634     return .radial(r, (r.length - !r.empty) / 2);
2635 }
2636 
2637 ///
2638 @safe unittest
2639 {
2640     import std.algorithm.comparison : equal;
2641     int[] a = [ 1, 2, 3, 4, 5 ];
2642     assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
2643     a = [ 1, 2, 3, 4 ];
2644     assert(equal(radial(a), [ 2, 3, 1, 4 ]));
2645 
2646     // If the left end is reached first, the remaining elements on the right
2647     // are concatenated in order:
2648     a = [ 0, 1, 2, 3, 4, 5 ];
2649     assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
2650 
2651     // If the right end is reached first, the remaining elements on the left
2652     // are concatenated in reverse order:
2653     assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
2654 }
2655 
2656 @safe unittest
2657 {
2658     import std.algorithm.comparison : equal;
2659     import std.conv : text;
2660     import std.exception : enforce;
2661     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2662 
2663     void test(int[] input, int[] witness)
2664     {
2665         enforce(equal(radial(input), witness),
2666                 text(radial(input), " vs. ", witness));
2667     }
2668     test([], []);
2669     test([ 1 ], [ 1 ]);
2670     test([ 1, 2 ], [ 1, 2 ]);
2671     test([ 1, 2, 3 ], [ 2, 3, 1 ]);
2672     test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
2673     test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
2674     test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
2675 
2676     int[] a = [ 1, 2, 3, 4, 5 ];
2677     assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
2678     assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
2679     assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
2680     static assert(isForwardRange!(typeof(radial(a, 1))));
2681 
2682     auto r = radial([1,2,3,4,5]);
2683     for (auto rr = r.save; !rr.empty; rr.popFront())
2684     {
2685         assert(rr.front == moveFront(rr));
2686     }
2687     r.front = 5;
2688     assert(r.front == 5);
2689 
2690     // Test instantiation without lvalue elements.
2691     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
2692     assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
2693 
2694     // immutable int[] immi = [ 1, 2 ];
2695     // static assert(is(typeof(radial(immi))));
2696 }
2697 
2698 @safe unittest
2699 {
2700     import std.algorithm.comparison : equal;
2701 
2702     auto LL = iota(1L, 6L);
2703     auto r = radial(LL);
2704     assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
2705 }
2706 
2707 /**
2708 Lazily takes only up to `n` elements of a range. This is
2709 particularly useful when using with infinite ranges.
2710 
2711 Unlike $(LREF takeExactly), `take` does not require that there
2712 are `n` or more elements in `input`. As a consequence, length
2713 information is not applied to the result unless `input` also has
2714 length information.
2715 
2716 Params:
2717     input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2718     to iterate over up to `n` times
2719     n = the number of elements to take
2720 
2721 Returns:
2722     At minimum, an input range. If the range offers random access
2723     and `length`, `take` offers them as well.
2724  */
2725 Take!R take(R)(R input, size_t n)
2726 if (isInputRange!(Unqual!R))
2727 {
2728     alias U = Unqual!R;
2729     static if (is(R T == Take!T))
2730     {
2731         import std.algorithm.comparison : min;
2732         return R(input.source, min(n, input._maxAvailable));
2733     }
2734     else static if (!isInfinite!U && hasSlicing!U)
2735     {
2736         import std.algorithm.comparison : min;
2737         return input[0 .. min(n, input.length)];
2738     }
2739     else
2740     {
2741         return Take!R(input, n);
2742     }
2743 }
2744 
2745 /// ditto
2746 struct Take(Range)
2747 if (isInputRange!(Unqual!Range) &&
2748     //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
2749     //take for slicing infinite ranges.
2750     !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
2751 {
2752     private alias R = Unqual!Range;
2753 
2754     /// User accessible in read and write
2755     public R source;
2756 
2757     private size_t _maxAvailable;
2758 
2759     alias Source = R;
2760 
2761     /// Range primitives
2762     @property bool empty()
2763     {
2764         return _maxAvailable == 0 || source.empty;
2765     }
2766 
2767     /// ditto
2768     @property auto ref front()
2769     {
2770         assert(!empty,
2771             "Attempting to fetch the front of an empty "
2772             ~ Take.stringof);
2773         return source.front;
2774     }
2775 
2776     /// ditto
2777     void popFront()
2778     {
2779         assert(!empty,
2780             "Attempting to popFront() past the end of a "
2781             ~ Take.stringof);
2782         source.popFront();
2783         --_maxAvailable;
2784     }
2785 
2786     static if (isForwardRange!R)
2787         /// ditto
2788         @property Take save()
2789         {
2790             return Take(source.save, _maxAvailable);
2791         }
2792 
2793     static if (hasAssignableElements!R)
2794         /// ditto
2795         @property void front(ElementType!R v)
2796         {
2797             import core.lifetime : forward;
2798 
2799             assert(!empty,
2800                 "Attempting to assign to the front of an empty "
2801                 ~ Take.stringof);
2802 
2803             // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
2804             source.front = __ctfe ? v : forward!v;
2805         }
2806 
2807     static if (hasMobileElements!R)
2808     {
2809         /// ditto
2810         auto moveFront()
2811         {
2812             assert(!empty,
2813                 "Attempting to move the front of an empty "
2814                 ~ Take.stringof);
2815             return source.moveFront();
2816         }
2817     }
2818 
2819     static if (isInfinite!R)
2820     {
2821         /// ditto
2822         @property size_t length() const
2823         {
2824             return _maxAvailable;
2825         }
2826 
2827         /// ditto
2828         alias opDollar = length;
2829 
2830         //Note: Due to Take/hasSlicing circular dependency,
2831         //This needs to be a restrained template.
2832         /// ditto
2833         auto opSlice()(size_t i, size_t j)
2834         if (hasSlicing!R)
2835         {
2836             assert(i <= j, "Invalid slice bounds");
2837             assert(j <= length, "Attempting to slice past the end of a "
2838                 ~ Take.stringof);
2839             return source[i .. j];
2840         }
2841     }
2842     else static if (hasLength!R)
2843     {
2844         /// ditto
2845         @property size_t length()
2846         {
2847             import std.algorithm.comparison : min;
2848             return min(_maxAvailable, source.length);
2849         }
2850 
2851         alias opDollar = length;
2852     }
2853 
2854     static if (isRandomAccessRange!R)
2855     {
2856         /// ditto
2857         void popBack()
2858         {
2859             assert(!empty,
2860                 "Attempting to popBack() past the beginning of a "
2861                 ~ Take.stringof);
2862             --_maxAvailable;
2863         }
2864 
2865         /// ditto
2866         @property auto ref back()
2867         {
2868             assert(!empty,
2869                 "Attempting to fetch the back of an empty "
2870                 ~ Take.stringof);
2871             return source[this.length - 1];
2872         }
2873 
2874         /// ditto
2875         auto ref opIndex(size_t index)
2876         {
2877             assert(index < length,
2878                 "Attempting to index out of the bounds of a "
2879                 ~ Take.stringof);
2880             return source[index];
2881         }
2882 
2883         static if (hasAssignableElements!R)
2884         {
2885             /// ditto
2886             @property void back(ElementType!R v)
2887             {
2888                 // This has to return auto instead of void because of
2889                 // https://issues.dlang.org/show_bug.cgi?id=4706
2890                 assert(!empty,
2891                     "Attempting to assign to the back of an empty "
2892                     ~ Take.stringof);
2893                 source[this.length - 1] = v;
2894             }
2895 
2896             /// ditto
2897             void opIndexAssign(ElementType!R v, size_t index)
2898             {
2899                 assert(index < length,
2900                     "Attempting to index out of the bounds of a "
2901                     ~ Take.stringof);
2902                 source[index] = v;
2903             }
2904         }
2905 
2906         static if (hasMobileElements!R)
2907         {
2908             /// ditto
2909             auto moveBack()
2910             {
2911                 assert(!empty,
2912                     "Attempting to move the back of an empty "
2913                     ~ Take.stringof);
2914                 return source.moveAt(this.length - 1);
2915             }
2916 
2917             /// ditto
2918             auto moveAt(size_t index)
2919             {
2920                 assert(index < length,
2921                     "Attempting to index out of the bounds of a "
2922                     ~ Take.stringof);
2923                 return source.moveAt(index);
2924             }
2925         }
2926     }
2927 
2928     /**
2929     Access to maximal length of the range.
2930     Note: the actual length of the range depends on the underlying range.
2931     If it has fewer elements, it will stop before maxLength is reached.
2932     */
2933     @property size_t maxLength() const
2934     {
2935         return _maxAvailable;
2936     }
2937 }
2938 
2939 /// ditto
2940 template Take(R)
2941 if (isInputRange!(Unqual!R) &&
2942     ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2943 {
2944     alias Take = R;
2945 }
2946 
2947 ///
2948 pure @safe nothrow unittest
2949 {
2950     import std.algorithm.comparison : equal;
2951 
2952     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2953     auto s = take(arr1, 5);
2954     assert(s.length == 5);
2955     assert(s[4] == 5);
2956     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2957 }
2958 
2959 /**
2960  * If the range runs out before `n` elements, `take` simply returns the entire
2961  * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2962  * the range ends prematurely):
2963  */
2964 pure @safe nothrow unittest
2965 {
2966     import std.algorithm.comparison : equal;
2967 
2968     int[] arr2 = [ 1, 2, 3 ];
2969     auto t = take(arr2, 5);
2970     assert(t.length == 3);
2971     assert(equal(t, [ 1, 2, 3 ]));
2972 }
2973 
2974 pure @safe nothrow unittest
2975 {
2976     import std.algorithm.comparison : equal;
2977     import std.internal.test.dummyrange : AllDummyRanges;
2978 
2979     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2980     auto s = take(arr1, 5);
2981     assert(s.length == 5);
2982     assert(s[4] == 5);
2983     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2984     assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2985 
2986     // Test fix for bug 4464.
2987     static assert(is(typeof(s) == Take!(int[])));
2988     static assert(is(typeof(s) == int[]));
2989 
2990     // Test using narrow strings.
2991     import std.exception : assumeWontThrow;
2992 
2993     auto myStr = "This is a string.";
2994     auto takeMyStr = take(myStr, 7);
2995     assert(assumeWontThrow(equal(takeMyStr, "This is")));
2996     // Test fix for bug 5052.
2997     auto takeMyStrAgain = take(takeMyStr, 4);
2998     assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2999     static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
3000     takeMyStrAgain = take(takeMyStr, 10);
3001     assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
3002 
3003     foreach (DummyType; AllDummyRanges)
3004     {
3005         DummyType dummy;
3006         auto t = take(dummy, 5);
3007         alias T = typeof(t);
3008 
3009         static if (isRandomAccessRange!DummyType)
3010         {
3011             static assert(isRandomAccessRange!T);
3012             assert(t[4] == 5);
3013 
3014             assert(moveAt(t, 1) == t[1]);
3015             assert(t.back == moveBack(t));
3016         }
3017         else static if (isForwardRange!DummyType)
3018         {
3019             static assert(isForwardRange!T);
3020         }
3021 
3022         for (auto tt = t; !tt.empty; tt.popFront())
3023         {
3024             assert(tt.front == moveFront(tt));
3025         }
3026 
3027         // Bidirectional ranges can't be propagated properly if they don't
3028         // also have random access.
3029 
3030         assert(equal(t, [1,2,3,4,5]));
3031 
3032         //Test that take doesn't wrap the result of take.
3033         assert(take(t, 4) == take(dummy, 4));
3034     }
3035 
3036     immutable myRepeat = repeat(1);
3037     static assert(is(Take!(typeof(myRepeat))));
3038 }
3039 
3040 pure @safe nothrow @nogc unittest
3041 {
3042     //check for correct slicing of Take on an infinite range
3043     import std.algorithm.comparison : equal;
3044     foreach (start; 0 .. 4)
3045         foreach (stop; start .. 4)
3046             assert(iota(4).cycle.take(4)[start .. stop]
3047                 .equal(iota(start, stop)));
3048 }
3049 
3050 pure @safe nothrow @nogc unittest
3051 {
3052     // Check that one can declare variables of all Take types,
3053     // and that they match the return type of the corresponding
3054     // take().
3055     // See https://issues.dlang.org/show_bug.cgi?id=4464
3056     int[] r1;
3057     Take!(int[]) t1;
3058     t1 = take(r1, 1);
3059     assert(t1.empty);
3060 
3061     string r2;
3062     Take!string t2;
3063     t2 = take(r2, 1);
3064     assert(t2.empty);
3065 
3066     Take!(Take!string) t3;
3067     t3 = take(t2, 1);
3068     assert(t3.empty);
3069 }
3070 
3071 pure @safe nothrow @nogc unittest
3072 {
3073     alias R1 = typeof(repeat(1));
3074     alias R2 = typeof(cycle([1]));
3075     alias TR1 = Take!R1;
3076     alias TR2 = Take!R2;
3077     static assert(isBidirectionalRange!TR1);
3078     static assert(isBidirectionalRange!TR2);
3079 }
3080 
3081 // https://issues.dlang.org/show_bug.cgi?id=12731
3082 pure @safe nothrow @nogc unittest
3083 {
3084     auto a = repeat(1);
3085     auto s = a[1 .. 5];
3086     s = s[1 .. 3];
3087     assert(s.length == 2);
3088     assert(s[0] == 1);
3089     assert(s[1] == 1);
3090 }
3091 
3092 // https://issues.dlang.org/show_bug.cgi?id=13151
3093 pure @safe nothrow @nogc unittest
3094 {
3095     import std.algorithm.comparison : equal;
3096 
3097     auto r = take(repeat(1, 4), 3);
3098     assert(r.take(2).equal(repeat(1, 2)));
3099 }
3100 
3101 // https://issues.dlang.org/show_bug.cgi?id=24481
3102 @safe unittest
3103 {
3104     import std.algorithm.iteration : filter;
3105 
3106     bool called;
3107     struct Handle
3108     {
3109         int entry;
3110         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
3111     }
3112 
3113     const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
3114     auto range = arr[].filter!(a => true)().take(3);
3115 
3116     called = false;
3117     range.front = Handle(42);
3118     assert(called);
3119 }
3120 
3121 /**
3122 Similar to $(LREF take), but assumes that `range` has at least $(D
3123 n) elements. Consequently, the result of $(D takeExactly(range, n))
3124 always defines the `length` property (and initializes it to `n`)
3125 even when `range` itself does not define `length`.
3126 
3127 The result of `takeExactly` is identical to that of $(LREF take) in
3128 cases where the original range defines `length` or is infinite.
3129 
3130 Unlike $(LREF take), however, it is illegal to pass a range with less than
3131 `n` elements to `takeExactly`; this will cause an assertion failure.
3132  */
3133 auto takeExactly(R)(R range, size_t n)
3134 if (isInputRange!R)
3135 {
3136     static if (is(typeof(takeExactly(range._input, n)) == R))
3137     {
3138         assert(n <= range._n,
3139                "Attempted to take more than the length of the range with takeExactly.");
3140         // takeExactly(takeExactly(r, n1), n2) has the same type as
3141         // takeExactly(r, n1) and simply returns takeExactly(r, n2)
3142         range._n = n;
3143         return range;
3144     }
3145     //Also covers hasSlicing!R for finite ranges.
3146     else static if (hasLength!R)
3147     {
3148         assert(n <= range.length,
3149                "Attempted to take more than the length of the range with takeExactly.");
3150         return take(range, n);
3151     }
3152     else static if (isInfinite!R)
3153         return Take!R(range, n);
3154     else
3155     {
3156         static struct Result
3157         {
3158             R _input;
3159             private size_t _n;
3160 
3161             @property bool empty() const { return !_n; }
3162             @property auto ref front()
3163             {
3164                 assert(_n > 0, "front() on an empty " ~ Result.stringof);
3165                 return _input.front;
3166             }
3167             void popFront() { _input.popFront(); --_n; }
3168             @property size_t length() const { return _n; }
3169             alias opDollar = length;
3170 
3171             @property auto _takeExactly_Result_asTake()
3172             {
3173                 return take(_input, _n);
3174             }
3175 
3176             alias _takeExactly_Result_asTake this;
3177 
3178             static if (isForwardRange!R)
3179                 @property auto save()
3180                 {
3181                     return Result(_input.save, _n);
3182                 }
3183 
3184             static if (hasMobileElements!R)
3185             {
3186                 auto moveFront()
3187                 {
3188                     assert(!empty,
3189                         "Attempting to move the front of an empty "
3190                         ~ typeof(this).stringof);
3191                     return _input.moveFront();
3192                 }
3193             }
3194 
3195             static if (hasAssignableElements!R)
3196             {
3197                 @property auto ref front(ElementType!R v)
3198                 {
3199                     import core.lifetime : forward;
3200 
3201                     assert(!empty,
3202                         "Attempting to assign to the front of an empty "
3203                         ~ typeof(this).stringof);
3204 
3205                     // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
3206                     return _input.front = __ctfe ? v : forward!v;
3207                 }
3208             }
3209         }
3210 
3211         return Result(range, n);
3212     }
3213 }
3214 
3215 ///
3216 pure @safe nothrow unittest
3217 {
3218     import std.algorithm.comparison : equal;
3219 
3220     auto a = [ 1, 2, 3, 4, 5 ];
3221 
3222     auto b = takeExactly(a, 3);
3223     assert(equal(b, [1, 2, 3]));
3224     static assert(is(typeof(b.length) == size_t));
3225     assert(b.length == 3);
3226     assert(b.front == 1);
3227     assert(b.back == 3);
3228 }
3229 
3230 pure @safe nothrow unittest
3231 {
3232     import std.algorithm.comparison : equal;
3233     import std.algorithm.iteration : filter;
3234 
3235     auto a = [ 1, 2, 3, 4, 5 ];
3236     auto b = takeExactly(a, 3);
3237     assert(equal(b, [1, 2, 3]));
3238     auto c = takeExactly(b, 2);
3239     assert(equal(c, [1, 2]));
3240 
3241 
3242 
3243     auto d = filter!"a > 2"(a);
3244     auto e = takeExactly(d, 3);
3245     assert(equal(e, [3, 4, 5]));
3246     static assert(is(typeof(e.length) == size_t));
3247     assert(e.length == 3);
3248     assert(e.front == 3);
3249 
3250     assert(equal(takeExactly(e, 3), [3, 4, 5]));
3251 }
3252 
3253 pure @safe nothrow unittest
3254 {
3255     import std.algorithm.comparison : equal;
3256     import std.internal.test.dummyrange : AllDummyRanges;
3257 
3258     auto a = [ 1, 2, 3, 4, 5 ];
3259     //Test that take and takeExactly are the same for ranges which define length
3260     //but aren't sliceable.
3261     struct L
3262     {
3263         @property auto front() { return _arr[0]; }
3264         @property bool empty() { return _arr.empty; }
3265         void popFront() { _arr.popFront(); }
3266         @property size_t length() { return _arr.length; }
3267         int[] _arr;
3268     }
3269     static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
3270     assert(take(L(a), 3) == takeExactly(L(a), 3));
3271 
3272     //Test that take and takeExactly are the same for ranges which are sliceable.
3273     static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
3274     assert(take(a, 3) == takeExactly(a, 3));
3275 
3276     //Test that take and takeExactly are the same for infinite ranges.
3277     auto inf = repeat(1);
3278     static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
3279     assert(take(inf, 5) == takeExactly(inf, 5));
3280 
3281     //Test that take and takeExactly are _not_ the same for ranges which don't
3282     //define length.
3283     static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
3284 
3285     foreach (DummyType; AllDummyRanges)
3286     {
3287         {
3288             DummyType dummy;
3289             auto t = takeExactly(dummy, 5);
3290 
3291             //Test that takeExactly doesn't wrap the result of takeExactly.
3292             assert(takeExactly(t, 4) == takeExactly(dummy, 4));
3293         }
3294 
3295         static if (hasMobileElements!DummyType)
3296         {
3297             {
3298                 auto t = takeExactly(DummyType.init, 4);
3299                 assert(t.moveFront() == 1);
3300                 assert(equal(t, [1, 2, 3, 4]));
3301             }
3302         }
3303 
3304         static if (hasAssignableElements!DummyType)
3305         {
3306             {
3307                 auto t = takeExactly(DummyType.init, 4);
3308                 t.front = 9;
3309                 assert(equal(t, [9, 2, 3, 4]));
3310             }
3311         }
3312     }
3313 }
3314 
3315 pure @safe nothrow unittest
3316 {
3317     import std.algorithm.comparison : equal;
3318     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
3319 
3320     alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
3321     auto te = takeExactly(DummyType(), 5);
3322     Take!DummyType t = te;
3323     assert(equal(t, [1, 2, 3, 4, 5]));
3324     assert(equal(t, te));
3325 }
3326 
3327 // https://issues.dlang.org/show_bug.cgi?id=18092
3328 // can't combine take and takeExactly
3329 @safe unittest
3330 {
3331     import std.algorithm.comparison : equal;
3332     import std.internal.test.dummyrange : AllDummyRanges;
3333 
3334     static foreach (Range; AllDummyRanges)
3335     {{
3336         Range r;
3337         assert(r.take(6).takeExactly(2).equal([1, 2]));
3338         assert(r.takeExactly(6).takeExactly(2).equal([1, 2]));
3339         assert(r.takeExactly(6).take(2).equal([1, 2]));
3340     }}
3341 }
3342 
3343 // https://issues.dlang.org/show_bug.cgi?id=24481
3344 @safe unittest
3345 {
3346     import std.algorithm.iteration : filter;
3347 
3348     bool called;
3349     struct Handle
3350     {
3351         int entry;
3352         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
3353     }
3354 
3355     const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
3356     auto range = arr[].filter!(a => true)().takeExactly(3);
3357 
3358     called = false;
3359     range.front = Handle(42);
3360     assert(called);
3361 }
3362 
3363 /**
3364 Returns a range with at most one element; for example, $(D
3365 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
3366 42). Calling `popFront()` off that range renders it empty.
3367 
3368 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in
3369 certain interfaces it is important to know statically that the range may only
3370 have at most one element.
3371 
3372 The type returned by `takeOne` is a random-access range with length
3373 regardless of `R`'s capabilities, as long as it is a forward range.
3374 (another feature that distinguishes `takeOne` from `take`). If
3375 (D R) is an input range but not a forward range, return type is an input
3376 range with all random-access capabilities except save.
3377  */
3378 auto takeOne(R)(R source)
3379 if (isInputRange!R)
3380 {
3381     static if (hasSlicing!R)
3382     {
3383         return source[0 .. !source.empty];
3384     }
3385     else
3386     {
3387         static struct Result
3388         {
3389             private R _source;
3390             private bool _empty = true;
3391             @property bool empty() const { return _empty; }
3392             @property auto ref front()
3393             {
3394                 assert(!empty, "Attempting to fetch the front of an empty takeOne");
3395                 return _source.front;
3396             }
3397             void popFront()
3398             {
3399                 assert(!empty, "Attempting to popFront an empty takeOne");
3400                 _source.popFront();
3401                 _empty = true;
3402             }
3403             void popBack()
3404             {
3405                 assert(!empty, "Attempting to popBack an empty takeOne");
3406                 _source.popFront();
3407                 _empty = true;
3408             }
3409             static if (isForwardRange!(Unqual!R))
3410             {
3411                 @property auto save() { return Result(_source.save, empty); }
3412             }
3413             @property auto ref back()
3414             {
3415                 assert(!empty, "Attempting to fetch the back of an empty takeOne");
3416                 return _source.front;
3417             }
3418             @property size_t length() const { return !empty; }
3419             alias opDollar = length;
3420             auto ref opIndex(size_t n)
3421             {
3422                 assert(n < length, "Attempting to index a takeOne out of bounds");
3423                 return _source.front;
3424             }
3425             auto opSlice(size_t m, size_t n)
3426             {
3427                 assert(
3428                     m <= n,
3429                     "Attempting to slice a takeOne range with a larger first argument than the second."
3430                 );
3431                 assert(
3432                     n <= length,
3433                     "Attempting to slice using an out of bounds index on a takeOne range."
3434                     );
3435                 return n > m ? this : Result(_source, true);
3436             }
3437             // Non-standard property
3438             @property R source() { return _source; }
3439         }
3440 
3441         return Result(source, source.empty);
3442     }
3443 }
3444 
3445 ///
3446 pure @safe nothrow unittest
3447 {
3448     auto s = takeOne([42, 43, 44]);
3449     static assert(isRandomAccessRange!(typeof(s)));
3450     assert(s.length == 1);
3451     assert(!s.empty);
3452     assert(s.front == 42);
3453     s.front = 43;
3454     assert(s.front == 43);
3455     assert(s.back == 43);
3456     assert(s[0] == 43);
3457     s.popFront();
3458     assert(s.length == 0);
3459     assert(s.empty);
3460 }
3461 
3462 pure @safe nothrow @nogc unittest
3463 {
3464     struct NonForwardRange
3465     {
3466         enum empty = false;
3467         int front() { return 42; }
3468         void popFront() {}
3469     }
3470 
3471     static assert(!isForwardRange!NonForwardRange);
3472 
3473     auto s = takeOne(NonForwardRange());
3474     assert(s.length == 1);
3475     assert(!s.empty);
3476     assert(s.front == 42);
3477     assert(s.back == 42);
3478     assert(s[0] == 42);
3479 
3480     auto t = s[0 .. 0];
3481     assert(t.empty);
3482     assert(t.length == 0);
3483 
3484     auto u = s[1 .. 1];
3485     assert(u.empty);
3486     assert(u.length == 0);
3487 
3488     auto v = s[0 .. 1];
3489     s.popFront();
3490     assert(s.length == 0);
3491     assert(s.empty);
3492     assert(!v.empty);
3493     assert(v.front == 42);
3494     v.popBack();
3495     assert(v.empty);
3496     assert(v.length == 0);
3497 }
3498 
3499 pure @safe nothrow @nogc unittest
3500 {
3501     struct NonSlicingForwardRange
3502     {
3503         enum empty = false;
3504         int front() { return 42; }
3505         void popFront() {}
3506         @property auto save() { return this; }
3507     }
3508 
3509     static assert(isForwardRange!NonSlicingForwardRange);
3510     static assert(!hasSlicing!NonSlicingForwardRange);
3511 
3512     auto s = takeOne(NonSlicingForwardRange());
3513     assert(s.length == 1);
3514     assert(!s.empty);
3515     assert(s.front == 42);
3516     assert(s.back == 42);
3517     assert(s[0] == 42);
3518     auto t = s.save;
3519     s.popFront();
3520     assert(s.length == 0);
3521     assert(s.empty);
3522     assert(!t.empty);
3523     assert(t.front == 42);
3524     t.popBack();
3525     assert(t.empty);
3526     assert(t.length == 0);
3527 }
3528 
3529 // Test that asserts trigger correctly
3530 @system unittest
3531 {
3532     import std.exception : assertThrown;
3533     import core.exception : AssertError;
3534 
3535     struct NonForwardRange
3536     {
3537         enum empty = false;
3538         int front() { return 42; }
3539         void popFront() {}
3540     }
3541 
3542     auto s = takeOne(NonForwardRange());
3543 
3544     assertThrown!AssertError(s[1]);
3545     assertThrown!AssertError(s[0 .. 2]);
3546 
3547     size_t one = 1;     // Avoid style warnings triggered by literals
3548     size_t zero = 0;
3549     assertThrown!AssertError(s[one .. zero]);
3550 
3551     s.popFront;
3552     assert(s.empty);
3553     assertThrown!AssertError(s.front);
3554     assertThrown!AssertError(s.back);
3555     assertThrown!AssertError(s.popFront);
3556     assertThrown!AssertError(s.popBack);
3557 }
3558 
3559 // https://issues.dlang.org/show_bug.cgi?id=16999
3560 pure @safe unittest
3561 {
3562     auto myIota = new class
3563     {
3564         int front = 0;
3565         @safe void popFront(){front++;}
3566         enum empty = false;
3567     };
3568     auto iotaPart = myIota.takeOne;
3569     int sum;
3570     foreach (var; chain(iotaPart, iotaPart, iotaPart))
3571     {
3572         sum += var;
3573     }
3574     assert(sum == 3);
3575     assert(iotaPart.front == 3);
3576 }
3577 
3578 /++
3579     Returns an empty range which is statically known to be empty and is
3580     guaranteed to have `length` and be random access regardless of `R`'s
3581     capabilities.
3582   +/
3583 auto takeNone(R)()
3584 if (isInputRange!R)
3585 {
3586     return typeof(takeOne(R.init)).init;
3587 }
3588 
3589 ///
3590 pure @safe nothrow @nogc unittest
3591 {
3592     auto range = takeNone!(int[])();
3593     assert(range.length == 0);
3594     assert(range.empty);
3595 }
3596 
3597 pure @safe nothrow @nogc unittest
3598 {
3599     enum ctfe = takeNone!(int[])();
3600     static assert(ctfe.length == 0);
3601     static assert(ctfe.empty);
3602 }
3603 
3604 
3605 /++
3606     Creates an empty range from the given range in $(BIGOH 1). If it can, it
3607     will return the same range type. If not, it will return
3608     $(D takeExactly(range, 0)).
3609   +/
3610 auto takeNone(R)(R range)
3611 if (isInputRange!R)
3612 {
3613     import std.traits : isDynamicArray;
3614     //Makes it so that calls to takeNone which don't use UFCS still work with a
3615     //member version if it's defined.
3616     static if (is(typeof(R.takeNone)))
3617         auto retval = range.takeNone();
3618     // https://issues.dlang.org/show_bug.cgi?id=8339
3619     else static if (isDynamicArray!R)/+ ||
3620                    (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
3621     {
3622         auto retval = R.init;
3623     }
3624     //An infinite range sliced at [0 .. 0] would likely still not be empty...
3625     else static if (hasSlicing!R && !isInfinite!R)
3626         auto retval = range[0 .. 0];
3627     else
3628         auto retval = takeExactly(range, 0);
3629 
3630     // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being
3631     // done in an out block.
3632     assert(retval.empty);
3633     return retval;
3634 }
3635 
3636 ///
3637 pure @safe nothrow unittest
3638 {
3639     import std.algorithm.iteration : filter;
3640     assert(takeNone([42, 27, 19]).empty);
3641     assert(takeNone("dlang.org").empty);
3642     assert(takeNone(filter!"true"([42, 27, 19])).empty);
3643 }
3644 
3645 @safe unittest
3646 {
3647     import std.algorithm.iteration : filter;
3648     import std.meta : AliasSeq;
3649 
3650     struct Dummy
3651     {
3652         mixin template genInput()
3653         {
3654         @safe:
3655             @property bool empty() { return _arr.empty; }
3656             @property auto front() { return _arr.front; }
3657             void popFront() { _arr.popFront(); }
3658             static assert(isInputRange!(typeof(this)));
3659         }
3660     }
3661     alias genInput = Dummy.genInput;
3662 
3663     static struct NormalStruct
3664     {
3665         //Disabled to make sure that the takeExactly version is used.
3666         @disable this();
3667         this(int[] arr) { _arr = arr; }
3668         mixin genInput;
3669         int[] _arr;
3670     }
3671 
3672     static struct SliceStruct
3673     {
3674         @disable this();
3675         this(int[] arr) { _arr = arr; }
3676         mixin genInput;
3677         @property auto save() { return this; }
3678         auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
3679         @property size_t length() { return _arr.length; }
3680         int[] _arr;
3681     }
3682 
3683     static struct InitStruct
3684     {
3685         mixin genInput;
3686         int[] _arr;
3687     }
3688 
3689     static struct TakeNoneStruct
3690     {
3691         this(int[] arr) { _arr = arr; }
3692         @disable this();
3693         mixin genInput;
3694         auto takeNone() { return typeof(this)(null); }
3695         int[] _arr;
3696     }
3697 
3698     static class NormalClass
3699     {
3700         this(int[] arr) {_arr = arr;}
3701         mixin genInput;
3702         int[] _arr;
3703     }
3704 
3705     static class SliceClass
3706     {
3707     @safe:
3708         this(int[] arr) { _arr = arr; }
3709         mixin genInput;
3710         @property auto save() { return new typeof(this)(_arr); }
3711         auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
3712         @property size_t length() { return _arr.length; }
3713         int[] _arr;
3714     }
3715 
3716     static class TakeNoneClass
3717     {
3718     @safe:
3719         this(int[] arr) { _arr = arr; }
3720         mixin genInput;
3721         auto takeNone() { return new typeof(this)(null); }
3722         int[] _arr;
3723     }
3724 
3725     import std.format : format;
3726 
3727     static foreach (range; AliasSeq!([1, 2, 3, 4, 5],
3728                              "hello world",
3729                              "hello world"w,
3730                              "hello world"d,
3731                              SliceStruct([1, 2, 3]),
3732                              // https://issues.dlang.org/show_bug.cgi?id=8339
3733                              // forces this to be takeExactly `InitStruct([1, 2, 3]),
3734                              TakeNoneStruct([1, 2, 3])))
3735     {
3736         static assert(takeNone(range).empty, typeof(range).stringof);
3737         assert(takeNone(range).empty);
3738         static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
3739     }
3740 
3741     static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
3742                              InitStruct([1, 2, 3])))
3743     {
3744         static assert(takeNone(range).empty, typeof(range).stringof);
3745         assert(takeNone(range).empty);
3746         static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
3747     }
3748 
3749     //Don't work in CTFE.
3750     auto normal = new NormalClass([1, 2, 3]);
3751     assert(takeNone(normal).empty);
3752     static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
3753 
3754     auto slice = new SliceClass([1, 2, 3]);
3755     assert(takeNone(slice).empty);
3756     static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
3757 
3758     auto taken = new TakeNoneClass([1, 2, 3]);
3759     assert(takeNone(taken).empty);
3760     static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
3761 
3762     auto filtered = filter!"true"([1, 2, 3, 4, 5]);
3763     assert(takeNone(filtered).empty);
3764     // https://issues.dlang.org/show_bug.cgi?id=8339 and
3765     // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly
3766     //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
3767 }
3768 
3769 /++
3770  + Return a range advanced to within `_n` elements of the end of
3771  + `range`.
3772  +
3773  + Intended as the range equivalent of the Unix
3774  + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
3775  + of `range` is less than or equal to `_n`, `range` is returned
3776  + as-is.
3777  +
3778  + Completes in $(BIGOH 1) steps for ranges that support slicing and have
3779  + length. Completes in $(BIGOH range.length) time for all other ranges.
3780  +
3781  + Params:
3782  +    range = range to get _tail of
3783  +    n = maximum number of elements to include in _tail
3784  +
3785  + Returns:
3786  +    Returns the _tail of `range` augmented with length information
3787  +/
3788 auto tail(Range)(Range range, size_t n)
3789 if (isInputRange!Range && !isInfinite!Range &&
3790     (hasLength!Range || isForwardRange!Range))
3791 {
3792     static if (hasLength!Range)
3793     {
3794         immutable length = range.length;
3795         if (n >= length)
3796             return range.takeExactly(length);
3797         else
3798             return range.drop(length - n).takeExactly(n);
3799     }
3800     else
3801     {
3802         Range scout = range.save;
3803         foreach (immutable i; 0 .. n)
3804         {
3805             if (scout.empty)
3806                 return range.takeExactly(i);
3807             scout.popFront();
3808         }
3809 
3810         auto tail = range.save;
3811         while (!scout.empty)
3812         {
3813             assert(!tail.empty);
3814             scout.popFront();
3815             tail.popFront();
3816         }
3817 
3818         return tail.takeExactly(n);
3819     }
3820 }
3821 
3822 ///
3823 pure @safe nothrow unittest
3824 {
3825     // tail -c n
3826     assert([1, 2, 3].tail(1) == [3]);
3827     assert([1, 2, 3].tail(2) == [2, 3]);
3828     assert([1, 2, 3].tail(3) == [1, 2, 3]);
3829     assert([1, 2, 3].tail(4) == [1, 2, 3]);
3830     assert([1, 2, 3].tail(0).length == 0);
3831 
3832     // tail --lines=n
3833     import std.algorithm.comparison : equal;
3834     import std.algorithm.iteration : joiner;
3835     import std.exception : assumeWontThrow;
3836     import std.string : lineSplitter;
3837     assert("one\ntwo\nthree"
3838         .lineSplitter
3839         .tail(2)
3840         .joiner("\n")
3841         .equal("two\nthree")
3842         .assumeWontThrow);
3843 }
3844 
3845 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408
3846 pure nothrow @safe /+@nogc+/ unittest
3847 {
3848     import std.algorithm.comparison : equal;
3849     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
3850         RangeType, ReturnBy;
3851 
3852     static immutable cheatsheet = [6, 7, 8, 9, 10];
3853 
3854     foreach (R; AllDummyRanges)
3855     {
3856         static if (isInputRange!R && !isInfinite!R &&
3857                    (hasLength!R || isForwardRange!R))
3858         {
3859             assert(R.init.tail(5).equal(cheatsheet));
3860             static assert(R.init.tail(5).equal(cheatsheet));
3861 
3862             assert(R.init.tail(0).length == 0);
3863             assert(R.init.tail(10).equal(R.init));
3864             assert(R.init.tail(11).equal(R.init));
3865         }
3866     }
3867 
3868     // Infinite ranges are not supported
3869     static assert(!__traits(compiles, repeat(0).tail(0)));
3870 
3871     // Neither are non-forward ranges without length
3872     static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
3873         RangeType.Input).init.tail(5)));
3874 }
3875 
3876 pure @safe nothrow @nogc unittest
3877 {
3878     static immutable input = [1, 2, 3];
3879     static immutable expectedOutput = [2, 3];
3880     assert(input.tail(2) == expectedOutput);
3881 }
3882 
3883 /++
3884     Convenience function which calls
3885     $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`.
3886     `drop` makes it easier to pop elements from a range
3887     and then pass it to another function within a single expression,
3888     whereas `popFrontN` would require multiple statements.
3889 
3890     `dropBack` provides the same functionality but instead calls
3891     $(REF popBackN, std, range, primitives)`(range, n)`
3892 
3893     Note: `drop` and `dropBack` will only pop $(I up to)
3894     `n` elements but will stop if the range is empty first.
3895     In other languages this is sometimes called `skip`.
3896 
3897     Params:
3898         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3899         n = the number of elements to drop
3900 
3901     Returns:
3902         `range` with up to `n` elements dropped
3903 
3904     See_Also:
3905         $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives)
3906   +/
3907 R drop(R)(R range, size_t n)
3908 if (isInputRange!R)
3909 {
3910     range.popFrontN(n);
3911     return range;
3912 }
3913 
3914 ///
3915 @safe unittest
3916 {
3917     import std.algorithm.comparison : equal;
3918 
3919     assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
3920     assert("hello world".drop(6) == "world");
3921     assert("hello world".drop(50).empty);
3922     assert("hello world".take(6).drop(3).equal("lo "));
3923 }
3924 
3925 /// ditto
3926 R dropBack(R)(R range, size_t n)
3927 if (isBidirectionalRange!R)
3928 {
3929     range.popBackN(n);
3930     return range;
3931 }
3932 
3933 ///
3934 @safe unittest
3935 {
3936     import std.algorithm.comparison : equal;
3937 
3938     assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
3939     assert("hello world".dropBack(6) == "hello");
3940     assert("hello world".dropBack(50).empty);
3941     assert("hello world".drop(4).dropBack(4).equal("o w"));
3942 }
3943 
3944 @safe unittest
3945 {
3946     import std.algorithm.comparison : equal;
3947     import std.container.dlist : DList;
3948 
3949     //Remove all but the first two elements
3950     auto a = DList!int(0, 1, 9, 9, 9, 9);
3951     a.remove(a[].drop(2));
3952     assert(a[].equal(a[].take(2)));
3953 }
3954 
3955 @safe unittest
3956 {
3957     import std.algorithm.comparison : equal;
3958     import std.algorithm.iteration : filter;
3959 
3960     assert(drop("", 5).empty);
3961     assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3962 }
3963 
3964 @safe unittest
3965 {
3966     import std.algorithm.comparison : equal;
3967     import std.container.dlist : DList;
3968 
3969     //insert before the last two elements
3970     auto a = DList!int(0, 1, 2, 5, 6);
3971     a.insertAfter(a[].dropBack(2), [3, 4]);
3972     assert(a[].equal(iota(0, 7)));
3973 }
3974 
3975 /++
3976     Similar to $(LREF drop) and `dropBack` but they call
3977     $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)`
3978     instead.
3979 
3980     Note: Unlike `drop`, `dropExactly` will assume that the
3981     range holds at least `n` elements. This makes `dropExactly`
3982     faster than `drop`, but it also means that if `range` does
3983     not contain at least `n` elements, it will attempt to call `popFront`
3984     on an empty range, which is undefined behavior. So, only use
3985     `popFrontExactly` when it is guaranteed that `range` holds at least
3986     `n` elements.
3987 
3988     Params:
3989         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3990         n = the number of elements to drop
3991 
3992     Returns:
3993         `range` with `n` elements dropped
3994 
3995     See_Also:
3996         $(REF popFrontExcatly, std, range, primitives),
3997         $(REF popBackExcatly, std, range, primitives)
3998 +/
3999 R dropExactly(R)(R range, size_t n)
4000 if (isInputRange!R)
4001 {
4002     popFrontExactly(range, n);
4003     return range;
4004 }
4005 /// ditto
4006 R dropBackExactly(R)(R range, size_t n)
4007 if (isBidirectionalRange!R)
4008 {
4009     popBackExactly(range, n);
4010     return range;
4011 }
4012 
4013 ///
4014 @safe unittest
4015 {
4016     import std.algorithm.comparison : equal;
4017     import std.algorithm.iteration : filterBidirectional;
4018 
4019     auto a = [1, 2, 3];
4020     assert(a.dropExactly(2) == [3]);
4021     assert(a.dropBackExactly(2) == [1]);
4022 
4023     string s = "日本語";
4024     assert(s.dropExactly(2) == "語");
4025     assert(s.dropBackExactly(2) == "日");
4026 
4027     auto bd = filterBidirectional!"true"([1, 2, 3]);
4028     assert(bd.dropExactly(2).equal([3]));
4029     assert(bd.dropBackExactly(2).equal([1]));
4030 }
4031 
4032 /++
4033     Convenience function which calls
4034     `range.popFront()` and returns `range`. `dropOne`
4035     makes it easier to pop an element from a range
4036     and then pass it to another function within a single expression,
4037     whereas `popFront` would require multiple statements.
4038 
4039     `dropBackOne` provides the same functionality but instead calls
4040     `range.popBack()`.
4041 +/
4042 R dropOne(R)(R range)
4043 if (isInputRange!R)
4044 {
4045     range.popFront();
4046     return range;
4047 }
4048 /// ditto
4049 R dropBackOne(R)(R range)
4050 if (isBidirectionalRange!R)
4051 {
4052     range.popBack();
4053     return range;
4054 }
4055 
4056 ///
4057 pure @safe nothrow unittest
4058 {
4059     import std.algorithm.comparison : equal;
4060     import std.algorithm.iteration : filterBidirectional;
4061     import std.container.dlist : DList;
4062 
4063     auto dl = DList!int(9, 1, 2, 3, 9);
4064     assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
4065 
4066     auto a = [1, 2, 3];
4067     assert(a.dropOne() == [2, 3]);
4068     assert(a.dropBackOne() == [1, 2]);
4069 
4070     string s = "日本語";
4071     import std.exception : assumeWontThrow;
4072     assert(assumeWontThrow(s.dropOne() == "本語"));
4073     assert(assumeWontThrow(s.dropBackOne() == "日本"));
4074 
4075     auto bd = filterBidirectional!"true"([1, 2, 3]);
4076     assert(bd.dropOne().equal([2, 3]));
4077     assert(bd.dropBackOne().equal([1, 2]));
4078 }
4079 
4080 /**
4081 Create a range which repeats one value.
4082 
4083 Params:
4084     value = the _value to repeat
4085     n = the number of times to repeat `value`
4086 
4087 Returns:
4088     If `n` is not defined, an infinite random access range
4089     with slicing.
4090 
4091     If `n` is defined, a random access range with slicing.
4092 */
4093 struct Repeat(T)
4094 {
4095 private:
4096     import std.typecons : Rebindable2;
4097 
4098     // Store a rebindable T to make Repeat assignable.
4099     Rebindable2!T _value;
4100 
4101 public:
4102     /// Range primitives
4103     @property inout(T) front() inout { return _value.get; }
4104 
4105     /// ditto
4106     @property inout(T) back() inout { return _value.get; }
4107 
4108     /// ditto
4109     enum bool empty = false;
4110 
4111     /// ditto
4112     void popFront() {}
4113 
4114     /// ditto
4115     void popBack() {}
4116 
4117     /// ditto
4118     @property auto save() inout { return this; }
4119 
4120     /// ditto
4121     inout(T) opIndex(size_t) inout { return _value.get; }
4122 
4123     /// ditto
4124     auto opSlice(size_t i, size_t j)
4125     in
4126     {
4127         assert(
4128             i <= j,
4129             "Attempting to slice a Repeat with a larger first argument than the second."
4130         );
4131     }
4132     do
4133     {
4134         return this.takeExactly(j - i);
4135     }
4136     private static struct DollarToken {}
4137 
4138     /// ditto
4139     enum opDollar = DollarToken.init;
4140 
4141     /// ditto
4142     auto opSlice(size_t, DollarToken) inout { return this; }
4143 }
4144 
4145 /// Ditto
4146 Repeat!T repeat(T)(T value)
4147 {
4148     import std.typecons : Rebindable2;
4149 
4150     return Repeat!T(Rebindable2!T(value));
4151 }
4152 
4153 ///
4154 pure @safe nothrow unittest
4155 {
4156     import std.algorithm.comparison : equal;
4157 
4158     assert(5.repeat().take(4).equal([5, 5, 5, 5]));
4159 }
4160 
4161 pure @safe nothrow unittest
4162 {
4163     import std.algorithm.comparison : equal;
4164 
4165     auto  r = repeat(5);
4166     alias R = typeof(r);
4167     static assert(isBidirectionalRange!R);
4168     static assert(isForwardRange!R);
4169     static assert(isInfinite!R);
4170     static assert(hasSlicing!R);
4171 
4172     assert(r.back == 5);
4173     assert(r.front == 5);
4174     assert(r.take(4).equal([ 5, 5, 5, 5 ]));
4175     assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
4176 
4177     R r2 = r[5 .. $];
4178     assert(r2.back == 5);
4179     assert(r2.front == 5);
4180 }
4181 
4182 /// ditto
4183 Take!(Repeat!T) repeat(T)(T value, size_t n)
4184 {
4185     return take(repeat(value), n);
4186 }
4187 
4188 ///
4189 pure @safe nothrow unittest
4190 {
4191     import std.algorithm.comparison : equal;
4192 
4193     assert(5.repeat(4).equal([5, 5, 5, 5]));
4194 }
4195 
4196 // https://issues.dlang.org/show_bug.cgi?id=12007
4197 pure @safe nothrow unittest
4198 {
4199     static class C{}
4200     Repeat!(immutable int) ri;
4201     ri = ri.save;
4202     Repeat!(immutable C) rc;
4203     rc = rc.save;
4204 
4205     import std.algorithm.setops : cartesianProduct;
4206     import std.algorithm.comparison : equal;
4207     import std.typecons : tuple;
4208     immutable int[] A = [1,2,3];
4209     immutable int[] B = [4,5,6];
4210 
4211     assert(equal(cartesianProduct(A,B),
4212         [
4213             tuple(1, 4), tuple(1, 5), tuple(1, 6),
4214             tuple(2, 4), tuple(2, 5), tuple(2, 6),
4215             tuple(3, 4), tuple(3, 5), tuple(3, 6),
4216         ]));
4217 }
4218 
4219 /**
4220 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
4221 whose front is defined by successive calls to `fun()`.
4222 This is especially useful to call function with global side effects (random
4223 functions), or to create ranges expressed as a single delegate, rather than
4224 an entire `front`/`popFront`/`empty` structure.
4225 `fun` maybe be passed either a template alias parameter (existing
4226 function, delegate, struct type defining `static opCall`) or
4227 a run-time value argument (delegate, function object).
4228 The result range models an InputRange
4229 ($(REF isInputRange, std,range,primitives)).
4230 The resulting range will call `fun()` on construction, and every call to
4231 `popFront`, and the cached value will be returned when `front` is called.
4232 
4233 Returns: an `inputRange` where each element represents another call to fun.
4234 */
4235 auto generate(Fun)(Fun fun)
4236 if (isCallable!fun)
4237 {
4238     auto gen = Generator!(Fun)(fun);
4239     gen.popFront(); // prime the first element
4240     return gen;
4241 }
4242 
4243 /// ditto
4244 auto generate(alias fun)()
4245 if (isCallable!fun)
4246 {
4247     auto gen = Generator!(fun)();
4248     gen.popFront(); // prime the first element
4249     return gen;
4250 }
4251 
4252 ///
4253 @safe pure nothrow unittest
4254 {
4255     import std.algorithm.comparison : equal;
4256     import std.algorithm.iteration : map;
4257 
4258     int i = 1;
4259     auto powersOfTwo = generate!(() => i *= 2)().take(10);
4260     assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
4261 }
4262 
4263 ///
4264 @safe pure nothrow unittest
4265 {
4266     import std.algorithm.comparison : equal;
4267 
4268     //Returns a run-time delegate
4269     auto infiniteIota(T)(T low, T high)
4270     {
4271         T i = high;
4272         return (){if (i == high) i = low; return i++;};
4273     }
4274     //adapted as a range.
4275     assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
4276 }
4277 
4278 ///
4279 @safe unittest
4280 {
4281     import std.format : format;
4282     import std.random : uniform;
4283 
4284     auto r = generate!(() => uniform(0, 6)).take(10);
4285     format("%(%s %)", r);
4286 }
4287 
4288 private struct Generator(Fun...)
4289 {
4290     static assert(Fun.length == 1);
4291     static assert(isInputRange!Generator);
4292     import std.traits : FunctionAttribute, functionAttributes, ReturnType;
4293 
4294 private:
4295     static if (is(Fun[0]))
4296         Fun[0] fun;
4297     else
4298         alias fun = Fun[0];
4299 
4300     enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
4301 
4302     import std.traits : hasIndirections;
4303     static if (!hasIndirections!(ReturnType!fun))
4304         alias RetType = Unqual!(ReturnType!fun);
4305     else
4306         alias RetType = ReturnType!fun;
4307 
4308     static if (returnByRef_)
4309         RetType *elem_;
4310     else
4311         RetType elem_;
4312 public:
4313     /// Range primitives
4314     enum empty = false;
4315 
4316     static if (returnByRef_)
4317     {
4318         /// ditto
4319         ref front() @property
4320         {
4321             return *elem_;
4322         }
4323         /// ditto
4324         void popFront()
4325         {
4326             elem_ = &fun();
4327         }
4328     }
4329     else
4330     {
4331         /// ditto
4332         auto front() @property
4333         {
4334             return elem_;
4335         }
4336         /// ditto
4337         void popFront()
4338         {
4339             elem_ = fun();
4340         }
4341     }
4342 }
4343 
4344 @safe nothrow unittest
4345 {
4346     import std.algorithm.comparison : equal;
4347 
4348     struct StaticOpCall
4349     {
4350         static ubyte opCall() { return 5 ; }
4351     }
4352 
4353     assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
4354 }
4355 
4356 @safe pure unittest
4357 {
4358     import std.algorithm.comparison : equal;
4359 
4360     struct OpCall
4361     {
4362         ubyte opCall() @safe pure { return 5 ; }
4363     }
4364 
4365     OpCall op;
4366     assert(equal(generate(op).take(10), repeat(5).take(10)));
4367 }
4368 
4369 // verify ref mechanism works
4370 @system nothrow unittest
4371 {
4372     int[10] arr;
4373     int idx;
4374 
4375     ref int fun() {
4376         auto x = idx++;
4377         idx %= arr.length;
4378         return arr[x];
4379     }
4380     int y = 1;
4381     foreach (ref x; generate!(fun).take(20))
4382     {
4383         x += y++;
4384     }
4385     import std.algorithm.comparison : equal;
4386     assert(equal(arr[], iota(12, 32, 2)));
4387 }
4388 
4389 // assure front isn't the mechanism to make generate go to the next element.
4390 @safe unittest
4391 {
4392     int i;
4393     auto g = generate!(() => ++i);
4394     auto f = g.front;
4395     assert(f == g.front);
4396     g = g.drop(5); // reassign because generate caches
4397     assert(g.front == f + 5);
4398 }
4399 
4400 // https://issues.dlang.org/show_bug.cgi?id=23319
4401 @safe pure nothrow unittest
4402 {
4403     auto b = generate!(() => const(int)(42));
4404     assert(b.front == 42);
4405 }
4406 
4407 /**
4408 Repeats the given forward range ad infinitum. If the original range is
4409 infinite (fact that would make `Cycle` the identity application),
4410 `Cycle` detects that and aliases itself to the range type
4411 itself. That works for non-forward ranges too.
4412 If the original range has random access, `Cycle` offers
4413 random access and also offers a constructor taking an initial position
4414 `index`. `Cycle` works with static arrays in addition to ranges,
4415 mostly for performance reasons.
4416 
4417 Note: The input range must not be empty.
4418 
4419 Tip: This is a great way to implement simple circular buffers.
4420 */
4421 struct Cycle(R)
4422 if (isForwardRange!R && !isInfinite!R)
4423 {
4424     static if (isRandomAccessRange!R && hasLength!R)
4425     {
4426         private R _original;
4427         private size_t _index;
4428 
4429         /// Range primitives
4430         this(R input, size_t index = 0)
4431         {
4432             _original = input;
4433             _index = index % _original.length;
4434         }
4435 
4436         /// ditto
4437         @property auto ref front()
4438         {
4439             return _original[_index];
4440         }
4441 
4442         static if (is(typeof((cast(const R)_original)[_index])))
4443         {
4444             /// ditto
4445             @property auto ref front() const
4446             {
4447                 return _original[_index];
4448             }
4449         }
4450 
4451         static if (hasAssignableElements!R)
4452         {
4453             /// ditto
4454             @property void front(ElementType!R val)
4455             {
4456                 import core.lifetime : forward;
4457 
4458                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
4459                 _original[_index] = __ctfe ? val : forward!val;
4460             }
4461         }
4462 
4463         /// ditto
4464         enum bool empty = false;
4465 
4466         /// ditto
4467         void popFront()
4468         {
4469             ++_index;
4470             if (_index >= _original.length)
4471                 _index = 0;
4472         }
4473 
4474         /// ditto
4475         auto ref opIndex(size_t n)
4476         {
4477             return _original[(n + _index) % _original.length];
4478         }
4479 
4480         static if (is(typeof((cast(const R)_original)[_index])) &&
4481                    is(typeof((cast(const R)_original).length)))
4482         {
4483             /// ditto
4484             auto ref opIndex(size_t n) const
4485             {
4486                 return _original[(n + _index) % _original.length];
4487             }
4488         }
4489 
4490         static if (hasAssignableElements!R)
4491         {
4492             /// ditto
4493             void opIndexAssign(ElementType!R val, size_t n)
4494             {
4495                 _original[(n + _index) % _original.length] = val;
4496             }
4497         }
4498 
4499         /// ditto
4500         @property Cycle save()
4501         {
4502             //No need to call _original.save, because Cycle never actually modifies _original
4503             return Cycle(_original, _index);
4504         }
4505 
4506         private static struct DollarToken {}
4507 
4508         /// ditto
4509         enum opDollar = DollarToken.init;
4510 
4511         static if (hasSlicing!R)
4512         {
4513             /// ditto
4514             auto opSlice(size_t i, size_t j)
4515             in
4516             {
4517                 assert(i <= j);
4518             }
4519             do
4520             {
4521                 return this[i .. $].takeExactly(j - i);
4522             }
4523 
4524             /// ditto
4525             auto opSlice(size_t i, DollarToken)
4526             {
4527                 return typeof(this)(_original, _index + i);
4528             }
4529         }
4530     }
4531     else
4532     {
4533         private R _original;
4534         private R _current;
4535 
4536         /// ditto
4537         this(R input)
4538         {
4539             _original = input;
4540             _current = input.save;
4541         }
4542 
4543         private this(R original, R current)
4544         {
4545             _original = original;
4546             _current = current;
4547         }
4548 
4549         /// ditto
4550         @property auto ref front()
4551         {
4552             return _current.front;
4553         }
4554 
4555         static if (is(typeof((cast(const R)_current).front)))
4556         {
4557             /// ditto
4558             @property auto ref front() const
4559             {
4560                 return _current.front;
4561             }
4562         }
4563 
4564         static if (hasAssignableElements!R)
4565         {
4566             /// ditto
4567             @property auto front(ElementType!R val)
4568             {
4569                 import core.lifetime : forward;
4570 
4571                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
4572                 return _current.front = __ctfe ? val : forward!val;
4573             }
4574         }
4575 
4576         /// ditto
4577         enum bool empty = false;
4578 
4579         /// ditto
4580         void popFront()
4581         {
4582             _current.popFront();
4583             if (_current.empty)
4584                 _current = _original.save;
4585         }
4586 
4587         /// ditto
4588         @property Cycle save()
4589         {
4590             //No need to call _original.save, because Cycle never actually modifies _original
4591             return Cycle(_original, _current.save);
4592         }
4593     }
4594 }
4595 
4596 /// ditto
4597 template Cycle(R)
4598 if (isInfinite!R)
4599 {
4600     alias Cycle = R;
4601 }
4602 
4603 /// ditto
4604 struct Cycle(R)
4605 if (isStaticArray!R)
4606 {
4607     private alias ElementType = typeof(R.init[0]);
4608     private ElementType* _ptr;
4609     private size_t _index;
4610 
4611 nothrow:
4612 
4613     /// Range primitives
4614     this(ref R input, size_t index = 0) @system
4615     {
4616         _ptr = input.ptr;
4617         _index = index % R.length;
4618     }
4619 
4620     /// ditto
4621     @property ref inout(ElementType) front() inout @safe
4622     {
4623         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4624         {
4625             return p[idx];
4626         }
4627         return trustedPtrIdx(_ptr, _index);
4628     }
4629 
4630     /// ditto
4631     enum bool empty = false;
4632 
4633     /// ditto
4634     void popFront() @safe
4635     {
4636         ++_index;
4637         if (_index >= R.length)
4638             _index = 0;
4639     }
4640 
4641     /// ditto
4642     ref inout(ElementType) opIndex(size_t n) inout @safe
4643     {
4644         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4645         {
4646             return p[idx % R.length];
4647         }
4648         return trustedPtrIdx(_ptr, n + _index);
4649     }
4650 
4651     /// ditto
4652     @property inout(Cycle) save() inout @safe
4653     {
4654         return this;
4655     }
4656 
4657     private static struct DollarToken {}
4658     /// ditto
4659     enum opDollar = DollarToken.init;
4660 
4661     /// ditto
4662     auto opSlice(size_t i, size_t j) @safe
4663     in
4664     {
4665         assert(
4666             i <= j,
4667             "Attempting to slice a Repeat with a larger first argument than the second."
4668         );
4669     }
4670     do
4671     {
4672         return this[i .. $].takeExactly(j - i);
4673     }
4674 
4675     /// ditto
4676     inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
4677     {
4678         static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
4679         {
4680             return cast(inout) Cycle(*cast(R*)(p), idx);
4681         }
4682         return trustedCtor(_ptr, _index + i);
4683     }
4684 }
4685 
4686 /// Ditto
4687 auto cycle(R)(R input)
4688 if (isInputRange!R)
4689 {
4690     static assert(isForwardRange!R || isInfinite!R,
4691         "Cycle requires a forward range argument unless it's statically known"
4692          ~ " to be infinite");
4693     assert(!input.empty, "Attempting to pass an empty input to cycle");
4694     static if (isInfinite!R) return input;
4695     else return Cycle!R(input);
4696 }
4697 
4698 ///
4699 @safe unittest
4700 {
4701     import std.algorithm.comparison : equal;
4702     import std.range : cycle, take;
4703 
4704     // Here we create an infinitive cyclic sequence from [1, 2]
4705     // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
4706     // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
4707     // and compare them with the expected values for equality.
4708     assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
4709 }
4710 
4711 /// Ditto
4712 Cycle!R cycle(R)(R input, size_t index = 0)
4713 if (isRandomAccessRange!R && !isInfinite!R)
4714 {
4715     assert(!input.empty, "Attempting to pass an empty input to cycle");
4716     return Cycle!R(input, index);
4717 }
4718 
4719 /// Ditto
4720 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
4721 if (isStaticArray!R)
4722 {
4723     return Cycle!R(input, index);
4724 }
4725 
4726 @safe nothrow unittest
4727 {
4728     import std.algorithm.comparison : equal;
4729     import std.internal.test.dummyrange : AllDummyRanges;
4730 
4731     static assert(isForwardRange!(Cycle!(uint[])));
4732 
4733     // Make sure ref is getting propagated properly.
4734     int[] nums = [1,2,3];
4735     auto c2 = cycle(nums);
4736     c2[3]++;
4737     assert(nums[0] == 2);
4738 
4739     immutable int[] immarr = [1, 2, 3];
4740 
4741     foreach (DummyType; AllDummyRanges)
4742     {
4743         static if (isForwardRange!DummyType)
4744         {
4745             DummyType dummy;
4746             auto cy = cycle(dummy);
4747             static assert(isForwardRange!(typeof(cy)));
4748             auto t = take(cy, 20);
4749             assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
4750 
4751             const cRange = cy;
4752             assert(cRange.front == 1);
4753 
4754             static if (hasAssignableElements!DummyType)
4755             {
4756                 {
4757                     cy.front = 66;
4758                     scope(exit) cy.front = 1;
4759                     assert(dummy.front == 66);
4760                 }
4761 
4762                 static if (isRandomAccessRange!DummyType)
4763                 {
4764                     {
4765                         cy[10] = 66;
4766                         scope(exit) cy[10] = 1;
4767                         assert(dummy.front == 66);
4768                     }
4769 
4770                     assert(cRange[10] == 1);
4771                 }
4772             }
4773 
4774             static if (hasSlicing!DummyType)
4775             {
4776                 auto slice = cy[5 .. 15];
4777                 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
4778                 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
4779 
4780                 auto infSlice = cy[7 .. $];
4781                 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
4782                 static assert(isInfinite!(typeof(infSlice)));
4783             }
4784         }
4785     }
4786 }
4787 
4788 @system nothrow unittest // For static arrays.
4789 {
4790     import std.algorithm.comparison : equal;
4791 
4792     int[3] a = [ 1, 2, 3 ];
4793     static assert(isStaticArray!(typeof(a)));
4794     auto c = cycle(a);
4795     assert(a.ptr == c._ptr);
4796     assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
4797     static assert(isForwardRange!(typeof(c)));
4798 
4799     // Test qualifiers on slicing.
4800     alias C = typeof(c);
4801     static assert(is(typeof(c[1 .. $]) == C));
4802     const cConst = c;
4803     static assert(is(typeof(cConst[1 .. $]) == const(C)));
4804 }
4805 
4806 @safe nothrow unittest // For infinite ranges
4807 {
4808     struct InfRange
4809     {
4810         void popFront() { }
4811         @property int front() { return 0; }
4812         enum empty = false;
4813         auto save() { return this; }
4814     }
4815     struct NonForwardInfRange
4816     {
4817         void popFront() { }
4818         @property int front() { return 0; }
4819         enum empty = false;
4820     }
4821 
4822     InfRange i;
4823     NonForwardInfRange j;
4824     auto c = cycle(i);
4825     assert(c == i);
4826     //make sure it can alias out even non-forward infinite ranges
4827     static assert(is(typeof(j.cycle) == typeof(j)));
4828 }
4829 
4830 @safe unittest
4831 {
4832     import std.algorithm.comparison : equal;
4833 
4834     int[5] arr = [0, 1, 2, 3, 4];
4835     auto cleD = cycle(arr[]); //Dynamic
4836     assert(equal(cleD[5 .. 10], arr[]));
4837 
4838     //n is a multiple of 5 worth about 3/4 of size_t.max
4839     auto n = size_t.max/4 + size_t.max/2;
4840     n -= n % 5;
4841 
4842     //Test index overflow
4843     foreach (_ ; 0 .. 10)
4844     {
4845         cleD = cleD[n .. $];
4846         assert(equal(cleD[5 .. 10], arr[]));
4847     }
4848 }
4849 
4850 @system @nogc nothrow unittest
4851 {
4852     import std.algorithm.comparison : equal;
4853 
4854     int[5] arr = [0, 1, 2, 3, 4];
4855     auto cleS = cycle(arr);   //Static
4856     assert(equal(cleS[5 .. 10], arr[]));
4857 
4858     //n is a multiple of 5 worth about 3/4 of size_t.max
4859     auto n = size_t.max/4 + size_t.max/2;
4860     n -= n % 5;
4861 
4862     //Test index overflow
4863     foreach (_ ; 0 .. 10)
4864     {
4865         cleS = cleS[n .. $];
4866         assert(equal(cleS[5 .. 10], arr[]));
4867     }
4868 }
4869 
4870 @system unittest
4871 {
4872     import std.algorithm.comparison : equal;
4873 
4874     int[1] arr = [0];
4875     auto cleS = cycle(arr);
4876     cleS = cleS[10 .. $];
4877     assert(equal(cleS[5 .. 10], 0.repeat(5)));
4878     assert(cleS.front == 0);
4879 }
4880 
4881 // https://issues.dlang.org/show_bug.cgi?id=10845
4882 @system unittest
4883 {
4884     import std.algorithm.comparison : equal;
4885     import std.algorithm.iteration : filter;
4886 
4887     auto a = inputRangeObject(iota(3).filter!"true");
4888     assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
4889 }
4890 
4891 // https://issues.dlang.org/show_bug.cgi?id=12177
4892 @safe unittest
4893 {
4894     static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
4895 }
4896 
4897 // https://issues.dlang.org/show_bug.cgi?id=13390
4898 @system unittest
4899 {
4900     import core.exception : AssertError;
4901     import std.exception : assertThrown;
4902     assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
4903 }
4904 
4905 // https://issues.dlang.org/show_bug.cgi?id=18657
4906 pure @safe unittest
4907 {
4908     import std.algorithm.comparison : equal;
4909     string s = "foo";
4910     auto r = refRange(&s).cycle.take(4);
4911     assert(equal(r.save, "foof"));
4912     assert(equal(r.save, "foof"));
4913 }
4914 
4915 // https://issues.dlang.org/show_bug.cgi?id=24481
4916 @safe unittest
4917 {
4918     import std.algorithm.iteration : filter;
4919 
4920     bool called;
4921     struct Handle
4922     {
4923         int entry;
4924         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
4925     }
4926 
4927     const(Handle)[3] arr = [Handle(0), Handle(1), Handle(2)];
4928     {
4929         auto range = arr[].cycle().take(5);
4930 
4931         called = false;
4932         range.front = Handle(42);
4933         assert(called);
4934     }
4935     {
4936         auto range = arr[].filter!(a => true)().cycle().take(5);
4937 
4938         called = false;
4939         range.front = Handle(42);
4940         assert(called);
4941     }
4942 }
4943 
4944 private alias lengthType(R) = typeof(R.init.length.init);
4945 
4946 /**
4947    Iterate several ranges in lockstep. The element type is a proxy tuple
4948    that allows accessing the current element in the `n`th range by
4949    using `e[n]`.
4950 
4951    `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
4952    bundle its elements and uses the `opApply` protocol.
4953    `lockstep` allows reference access to the elements in
4954    `foreach` iterations.
4955 
4956     Params:
4957         sp = controls what `zip` will do if the ranges are different lengths
4958         ranges = the ranges to zip together
4959     Returns:
4960         At minimum, an input range. `Zip` offers the lowest range facilities
4961         of all components, e.g. it offers random access iff all ranges offer
4962         random access, and also offers mutation and swapping if all ranges offer
4963         it. Due to this, `Zip` is extremely powerful because it allows manipulating
4964         several ranges in lockstep.
4965     Throws:
4966         An `Exception` if all of the ranges are not the same length and
4967         `sp` is set to `StoppingPolicy.requireSameLength`.
4968 
4969     Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for
4970     the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This
4971     limitation is not shared by the anonymous range returned by the `zip`
4972     function when not given an explicit `StoppingPolicy` as an argument.
4973 */
4974 struct Zip(Ranges...)
4975 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4976 {
4977     import std.format : format; //for generic mixins
4978     import std.typecons : Tuple;
4979 
4980     alias R = Ranges;
4981     private R ranges;
4982     alias ElementType = Tuple!(staticMap!(.ElementType, R));
4983     private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
4984 
4985 /**
4986    Builds an object. Usually this is invoked indirectly by using the
4987    $(LREF zip) function.
4988  */
4989     this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
4990     {
4991         ranges[] = rs[];
4992         stoppingPolicy = s;
4993     }
4994 
4995 /**
4996    Returns `true` if the range is at end. The test depends on the
4997    stopping policy.
4998 */
4999     static if (allSatisfy!(isInfinite, R))
5000     {
5001         // BUG:  Doesn't propagate infiniteness if only some ranges are infinite
5002         //       and s == StoppingPolicy.longest.  This isn't fixable in the
5003         //       current design since StoppingPolicy is known only at runtime.
5004         enum bool empty = false;
5005     }
5006     else
5007     {
5008         ///
5009         @property bool empty()
5010         {
5011             import std.exception : enforce;
5012             import std.meta : anySatisfy;
5013 
5014             final switch (stoppingPolicy)
5015             {
5016             case StoppingPolicy.shortest:
5017                 foreach (i, Unused; R)
5018                 {
5019                     if (ranges[i].empty) return true;
5020                 }
5021                 return false;
5022             case StoppingPolicy.longest:
5023                 static if (anySatisfy!(isInfinite, R))
5024                 {
5025                     return false;
5026                 }
5027                 else
5028                 {
5029                     foreach (i, Unused; R)
5030                     {
5031                         if (!ranges[i].empty) return false;
5032                     }
5033                     return true;
5034                 }
5035             case StoppingPolicy.requireSameLength:
5036                 foreach (i, Unused; R[1 .. $])
5037                 {
5038                     enforce(ranges[0].empty ==
5039                             ranges[i + 1].empty,
5040                             "Inequal-length ranges passed to Zip");
5041                 }
5042                 return ranges[0].empty;
5043             }
5044             assert(false);
5045         }
5046     }
5047 
5048     static if (allSatisfy!(isForwardRange, R))
5049     {
5050         ///
5051         @property Zip save()
5052         {
5053             //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
5054             return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
5055         }
5056     }
5057 
5058     private .ElementType!(R[i]) tryGetInit(size_t i)()
5059     {
5060         alias E = .ElementType!(R[i]);
5061         static if (!is(typeof({static E i;})))
5062             throw new Exception("Range with non-default constructable elements exhausted.");
5063         else
5064             return E.init;
5065     }
5066 
5067 /**
5068    Returns the current iterated element.
5069 */
5070     @property ElementType front()
5071     {
5072         @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
5073         //ElementType(tryGetFront!0, tryGetFront!1, ...)
5074         return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
5075     }
5076 
5077 /**
5078    Sets the front of all iterated ranges.
5079 */
5080     static if (allSatisfy!(hasAssignableElements, R))
5081     {
5082         @property void front(ElementType v)
5083         {
5084             foreach (i, Unused; R)
5085             {
5086                 if (!ranges[i].empty)
5087                 {
5088                     ranges[i].front = v[i];
5089                 }
5090             }
5091         }
5092     }
5093 
5094 /**
5095    Moves out the front.
5096 */
5097     static if (allSatisfy!(hasMobileElements, R))
5098     {
5099         ElementType moveFront()
5100         {
5101             @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
5102             //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
5103             return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
5104         }
5105     }
5106 
5107 /**
5108    Returns the rightmost element.
5109 */
5110     static if (allSatisfy!(isBidirectionalRange, R))
5111     {
5112         @property ElementType back()
5113         {
5114             //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
5115 
5116             @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
5117             //ElementType(tryGetBack!0, tryGetBack!1, ...)
5118             return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
5119         }
5120 
5121 /**
5122    Moves out the back.
5123 */
5124         static if (allSatisfy!(hasMobileElements, R))
5125         {
5126             ElementType moveBack()
5127             {
5128                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
5129 
5130                 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();}
5131                 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
5132                 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
5133             }
5134         }
5135 
5136 /**
5137    Returns the current iterated element.
5138 */
5139         static if (allSatisfy!(hasAssignableElements, R))
5140         {
5141             @property void back(ElementType v)
5142             {
5143                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
5144                 //Not sure the call is even legal for StoppingPolicy.longest
5145 
5146                 foreach (i, Unused; R)
5147                 {
5148                     if (!ranges[i].empty)
5149                     {
5150                         ranges[i].back = v[i];
5151                     }
5152                 }
5153             }
5154         }
5155     }
5156 
5157 /**
5158    Advances to the next element in all controlled ranges.
5159 */
5160     void popFront()
5161     {
5162         import std.exception : enforce;
5163 
5164         final switch (stoppingPolicy)
5165         {
5166         case StoppingPolicy.shortest:
5167             foreach (i, Unused; R)
5168             {
5169                 assert(!ranges[i].empty);
5170                 ranges[i].popFront();
5171             }
5172             break;
5173         case StoppingPolicy.longest:
5174             foreach (i, Unused; R)
5175             {
5176                 if (!ranges[i].empty) ranges[i].popFront();
5177             }
5178             break;
5179         case StoppingPolicy.requireSameLength:
5180             foreach (i, Unused; R)
5181             {
5182                 enforce(!ranges[i].empty, "Invalid Zip object");
5183                 ranges[i].popFront();
5184             }
5185             break;
5186         }
5187     }
5188 
5189 /**
5190    Calls `popBack` for all controlled ranges.
5191 */
5192     static if (allSatisfy!(isBidirectionalRange, R))
5193     {
5194         void popBack()
5195         {
5196             //TODO: Fixme! In case of jaggedness, this is wrong.
5197             import std.exception : enforce;
5198 
5199             final switch (stoppingPolicy)
5200             {
5201             case StoppingPolicy.shortest:
5202                 foreach (i, Unused; R)
5203                 {
5204                     assert(!ranges[i].empty);
5205                     ranges[i].popBack();
5206                 }
5207                 break;
5208             case StoppingPolicy.longest:
5209                 foreach (i, Unused; R)
5210                 {
5211                     if (!ranges[i].empty) ranges[i].popBack();
5212                 }
5213                 break;
5214             case StoppingPolicy.requireSameLength:
5215                 foreach (i, Unused; R)
5216                 {
5217                     enforce(!ranges[i].empty, "Invalid Zip object");
5218                     ranges[i].popBack();
5219                 }
5220                 break;
5221             }
5222         }
5223     }
5224 
5225 /**
5226    Returns the length of this range. Defined only if all ranges define
5227    `length`.
5228 */
5229     static if (allSatisfy!(hasLength, R))
5230     {
5231         @property auto length()
5232         {
5233             static if (Ranges.length == 1)
5234                 return ranges[0].length;
5235             else
5236             {
5237                 if (stoppingPolicy == StoppingPolicy.requireSameLength)
5238                     return ranges[0].length;
5239 
5240                 //[min|max](ranges[0].length, ranges[1].length, ...)
5241                 import std.algorithm.comparison : min, max;
5242                 if (stoppingPolicy == StoppingPolicy.shortest)
5243                     return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5244                 else
5245                     return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5246             }
5247         }
5248 
5249         alias opDollar = length;
5250     }
5251 
5252 /**
5253    Returns a slice of the range. Defined only if all range define
5254    slicing.
5255 */
5256     static if (allSatisfy!(hasSlicing, R))
5257     {
5258         auto opSlice(size_t from, size_t to)
5259         {
5260             //Slicing an infinite range yields the type Take!R
5261             //For finite ranges, the type Take!R aliases to R
5262             alias ZipResult = Zip!(staticMap!(Take, R));
5263 
5264             //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
5265             return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
5266         }
5267     }
5268 
5269 /**
5270    Returns the `n`th element in the composite range. Defined if all
5271    ranges offer random access.
5272 */
5273     static if (allSatisfy!(isRandomAccessRange, R))
5274     {
5275         ElementType opIndex(size_t n)
5276         {
5277             //TODO: Fixme! This may create an out of bounds access
5278             //for StoppingPolicy.longest
5279 
5280             //ElementType(ranges[0][n], ranges[1][n], ...)
5281             return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
5282         }
5283 
5284 /**
5285    Assigns to the `n`th element in the composite range. Defined if
5286    all ranges offer random access.
5287 */
5288         static if (allSatisfy!(hasAssignableElements, R))
5289         {
5290             void opIndexAssign(ElementType v, size_t n)
5291             {
5292                 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
5293                 foreach (i, Range; R)
5294                 {
5295                     ranges[i][n] = v[i];
5296                 }
5297             }
5298         }
5299 
5300 /**
5301    Destructively reads the `n`th element in the composite
5302    range. Defined if all ranges offer random access.
5303 */
5304         static if (allSatisfy!(hasMobileElements, R))
5305         {
5306             ElementType moveAt(size_t n)
5307             {
5308                 //TODO: Fixme! This may create an out of bounds access
5309                 //for StoppingPolicy.longest
5310 
5311                 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
5312                 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
5313             }
5314         }
5315     }
5316 }
5317 
5318 /// Ditto
5319 auto zip(Ranges...)(Ranges ranges)
5320 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5321 {
5322     import std.meta : anySatisfy, templateOr;
5323     static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1)
5324     {
5325         return ZipShortest!(Ranges)(ranges);
5326     }
5327     else static if (allSatisfy!(isBidirectionalRange, Ranges))
5328     {
5329         static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)
5330             && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges)
5331             && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges)))
5332         {
5333             // If all the ranges are bidirectional, if possible slice them to
5334             // the same length to simplify the implementation.
5335             static assert(anySatisfy!(hasLength, Ranges));
5336             static foreach (i, Range; Ranges)
5337                 static if (hasLength!Range)
5338                 {
5339                     static if (!is(typeof(minLen) == size_t))
5340                         size_t minLen = ranges[i].length;
5341                     else
5342                     {{
5343                         const x = ranges[i].length;
5344                         if (x < minLen) minLen = x;
5345                     }}
5346                 }
5347             import std.format : format;
5348             static if (!anySatisfy!(isInfinite, Ranges))
5349                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5350                     `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length)));
5351             else
5352                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5353                     `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length)));
5354         }
5355         else static if (allSatisfy!(isRandomAccessRange, Ranges))
5356         {
5357             // We can't slice but we can still use random access to ensure
5358             // "back" is retrieving the same index for each range.
5359             return ZipShortest!(Ranges)(ranges);
5360         }
5361         else
5362         {
5363             // If bidirectional range operations would not be supported by
5364             // ZipShortest that might have actually been a bug since Zip
5365             // supported `back` without verifying that each range had the
5366             // same length, but for the sake of backwards compatibility
5367             // use the old Zip to continue supporting them.
5368             return Zip!Ranges(ranges);
5369         }
5370     }
5371     else
5372     {
5373         return ZipShortest!(Ranges)(ranges);
5374     }
5375 }
5376 
5377 ///
5378 @nogc nothrow pure @safe unittest
5379 {
5380     import std.algorithm.comparison : equal;
5381     import std.algorithm.iteration : map;
5382 
5383     // pairwise sum
5384     auto arr = only(0, 1, 2);
5385     auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
5386     assert(part1.equal(only(1, 3)));
5387 }
5388 
5389 ///
5390 nothrow pure @safe unittest
5391 {
5392     import std.conv : to;
5393 
5394     int[] a = [ 1, 2, 3 ];
5395     string[] b = [ "a", "b", "c" ];
5396     string[] result;
5397 
5398     foreach (tup; zip(a, b))
5399     {
5400         result ~= tup[0].to!string ~ tup[1];
5401     }
5402 
5403     assert(result == [ "1a", "2b", "3c" ]);
5404 
5405     size_t idx = 0;
5406     // unpacking tuple elements with foreach
5407     foreach (e1, e2; zip(a, b))
5408     {
5409         assert(e1 == a[idx]);
5410         assert(e2 == b[idx]);
5411         ++idx;
5412     }
5413 }
5414 
5415 /// `zip` is powerful - the following code sorts two arrays in parallel:
5416 nothrow pure @safe unittest
5417 {
5418     import std.algorithm.sorting : sort;
5419 
5420     int[] a = [ 1, 2, 3 ];
5421     string[] b = [ "a", "c", "b" ];
5422     zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
5423 
5424     assert(a == [ 3, 2, 1 ]);
5425     // b is sorted according to a's sorting
5426     assert(b == [ "b", "c", "a" ]);
5427 }
5428 
5429 /// Ditto
5430 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
5431 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5432 {
5433     return Zip!Ranges(ranges, sp);
5434 }
5435 
5436 /**
5437    Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop.
5438    By default stop at the end of the shortest of all ranges.
5439 */
5440 enum StoppingPolicy
5441 {
5442     /// Stop when the shortest range is exhausted
5443     shortest,
5444     /// Stop when the longest range is exhausted
5445     longest,
5446     /// Require that all ranges are equal
5447     requireSameLength,
5448 }
5449 
5450 ///
5451 pure @safe unittest
5452 {
5453     import std.algorithm.comparison : equal;
5454     import std.exception : assertThrown;
5455     import std.range.primitives;
5456     import std.typecons : tuple;
5457 
5458     auto a = [1, 2, 3];
5459     auto b = [4, 5, 6, 7];
5460 
5461     auto shortest = zip(StoppingPolicy.shortest, a, b);
5462     assert(shortest.equal([
5463         tuple(1, 4),
5464         tuple(2, 5),
5465         tuple(3, 6)
5466     ]));
5467 
5468     auto longest = zip(StoppingPolicy.longest, a, b);
5469     assert(longest.equal([
5470         tuple(1, 4),
5471         tuple(2, 5),
5472         tuple(3, 6),
5473         tuple(0, 7)
5474     ]));
5475 
5476     auto same = zip(StoppingPolicy.requireSameLength, a, b);
5477     same.popFrontN(3);
5478     assertThrown!Exception(same.popFront);
5479 }
5480 
5481 /+
5482 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest`
5483 except it properly implements `back` and `popBack` in the
5484 case of uneven ranges or disables those operations when
5485 it is not possible to guarantee they are correct.
5486 +/
5487 package template ZipShortest(Ranges...)
5488 if (Ranges.length && __traits(compiles,
5489     {
5490         static assert(allSatisfy!(isInputRange, Ranges));
5491     }))
5492 {
5493     alias ZipShortest = .ZipShortest!(
5494         Ranges.length == 1 || allSatisfy!(isInfinite, Ranges)
5495             ? Yes.allKnownSameLength
5496             : No.allKnownSameLength,
5497         Ranges);
5498 }
5499 /+ non-public, ditto +/
5500 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...)
5501 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5502 {
5503     import std.format : format; //for generic mixins
5504     import std.meta : anySatisfy, templateOr;
5505     import std.typecons : Tuple;
5506 
5507     deprecated("Use of an undocumented alias R.")
5508     alias R = Ranges; // Unused here but defined in case library users rely on it.
5509     private Ranges ranges;
5510     alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
5511 
5512     /+
5513        Builds an object. Usually this is invoked indirectly by using the
5514        $(LREF zip) function.
5515     +/
5516     this(Ranges rs)
5517     {
5518         ranges[] = rs[];
5519     }
5520 
5521     /+
5522        Returns `true` if the range is at end.
5523     +/
5524     static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges)
5525         : allSatisfy!(isInfinite, Ranges))
5526     {
5527         enum bool empty = false;
5528     }
5529     else
5530     {
5531         @property bool empty()
5532         {
5533             static if (allKnownSameLength)
5534             {
5535                 return ranges[0].empty;
5536             }
5537             else
5538             {
5539                 static foreach (i; 0 .. Ranges.length)
5540                 {
5541                     if (ranges[i].empty)
5542                         return true;
5543                 }
5544                 return false;
5545             }
5546         }
5547     }
5548 
5549     /+
5550        Forward range primitive. Only present if each constituent range is a
5551        forward range.
5552     +/
5553     static if (allSatisfy!(isForwardRange, Ranges))
5554     @property typeof(this) save()
5555     {
5556         return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length)));
5557     }
5558 
5559     /+
5560        Returns the current iterated element.
5561     +/
5562     @property ElementType front()
5563     {
5564         return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length)));
5565     }
5566 
5567     /+
5568        Sets the front of all iterated ranges. Only present if each constituent
5569        range has assignable elements.
5570     +/
5571     static if (allSatisfy!(hasAssignableElements, Ranges))
5572     @property void front()(ElementType v)
5573     {
5574         static foreach (i; 0 .. Ranges.length)
5575             ranges[i].front = v[i];
5576     }
5577 
5578     /+
5579        Moves out the front. Present if each constituent range has mobile elements.
5580     +/
5581     static if (allSatisfy!(hasMobileElements, Ranges))
5582     ElementType moveFront()()
5583     {
5584         return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length)));
5585     }
5586 
5587     private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges)
5588         && (allKnownSameLength
5589             || allSatisfy!(isRandomAccessRange, Ranges)
5590             // Could also add the case where there is one non-infinite bidirectional
5591             // range that defines `length` and all others are infinite random access
5592             // ranges. Adding this would require appropriate branches in
5593             // back/moveBack/popBack.
5594             );
5595 
5596     /+
5597        Returns the rightmost element. Present if all constituent ranges are
5598        bidirectional and either there is a compile-time guarantee that all
5599        ranges have the same length (in `allKnownSameLength`) or all ranges
5600        provide random access to elements.
5601     +/
5602     static if (isBackWellDefined)
5603     @property ElementType back()
5604     {
5605         static if (allKnownSameLength)
5606         {
5607             return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length)));
5608         }
5609         else
5610         {
5611             const backIndex = length - 1;
5612             return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length)));
5613         }
5614     }
5615 
5616     /+
5617        Moves out the back. Present if `back` is defined and
5618        each constituent range has mobile elements.
5619     +/
5620     static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges))
5621     ElementType moveBack()()
5622     {
5623         static if (allKnownSameLength)
5624         {
5625             return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length)));
5626         }
5627         else
5628         {
5629             const backIndex = length - 1;
5630             return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length)));
5631         }
5632     }
5633 
5634     /+
5635        Sets the rightmost element. Only present if `back` is defined and
5636        each constituent range has assignable elements.
5637     +/
5638     static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges))
5639     @property void back()(ElementType v)
5640     {
5641         static if (allKnownSameLength)
5642         {
5643             static foreach (i; 0 .. Ranges.length)
5644                 ranges[i].back = v[i];
5645         }
5646         else
5647         {
5648             const backIndex = length - 1;
5649             static foreach (i; 0 .. Ranges.length)
5650                 ranges[i][backIndex] = v[i];
5651         }
5652     }
5653 
5654     /+
5655        Calls `popFront` on each constituent range.
5656     +/
5657     void popFront()
5658     {
5659         static foreach (i; 0 .. Ranges.length)
5660             ranges[i].popFront();
5661     }
5662 
5663     /+
5664        Pops the rightmost element. Present if `back` is defined.
5665     +/
5666     static if (isBackWellDefined)
5667     void popBack()
5668     {
5669         static if (allKnownSameLength)
5670         {
5671             static foreach (i; 0 .. Ranges.length)
5672                 ranges[i].popBack;
5673         }
5674         else
5675         {
5676             const len = length;
5677             static foreach (i; 0 .. Ranges.length)
5678                 static if (!isInfinite!(Ranges[i]))
5679                     if (ranges[i].length == len)
5680                         ranges[i].popBack();
5681         }
5682     }
5683 
5684     /+
5685        Returns the length of this range. Defined if at least one
5686        constituent range defines `length` and the other ranges all also
5687        define `length` or are infinite, or if at least one constituent
5688        range defines `length` and there is a compile-time guarantee that
5689        all ranges have the same length (in `allKnownSameLength`).
5690     +/
5691     static if (allKnownSameLength
5692         ? anySatisfy!(hasLength, Ranges)
5693         : (anySatisfy!(hasLength, Ranges)
5694             && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
5695     {
5696         @property size_t length()
5697         {
5698            static foreach (i, Range; Ranges)
5699            {
5700                 static if (hasLength!Range)
5701                 {
5702                     static if (!is(typeof(minLen) == size_t))
5703                         size_t minLen = ranges[i].length;
5704                     else static if (!allKnownSameLength)
5705                     {{
5706                         const x = ranges[i].length;
5707                         if (x < minLen) minLen = x;
5708                     }}
5709                 }
5710             }
5711             return minLen;
5712         }
5713 
5714         alias opDollar = length;
5715     }
5716 
5717     /+
5718        Returns a slice of the range. Defined if all constituent ranges
5719        support slicing.
5720     +/
5721     static if (allSatisfy!(hasSlicing, Ranges))
5722     {
5723         // Note: we will know that all elements of the resultant range
5724         // will have the same length but we cannot change `allKnownSameLength`
5725         // because the `hasSlicing` predicate tests that the result returned
5726         // by `opSlice` has the same type as the receiver.
5727         auto opSlice()(size_t from, size_t to)
5728         {
5729             //(ranges[0][from .. to], ranges[1][from .. to], ...)
5730             enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length));
5731             static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs)))
5732                 return mixin(`typeof(this)`~sliceArgs);
5733             else
5734                 // The type is different anyway so we might as well
5735                 // explicitly set allKnownSameLength.
5736                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`
5737                     ~sliceArgs);
5738         }
5739     }
5740 
5741     /+
5742        Returns the `n`th element in the composite range. Defined if all
5743        constituent ranges offer random access.
5744     +/
5745     static if (allSatisfy!(isRandomAccessRange, Ranges))
5746     ElementType opIndex()(size_t n)
5747     {
5748         return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length)));
5749     }
5750 
5751     /+
5752        Sets the `n`th element in the composite range. Defined if all
5753        constituent ranges offer random access and have assignable elements.
5754     +/
5755     static if (allSatisfy!(isRandomAccessRange, Ranges)
5756         && allSatisfy!(hasAssignableElements, Ranges))
5757     void opIndexAssign()(ElementType v, size_t n)
5758     {
5759         static foreach (i; 0 .. Ranges.length)
5760             ranges[i][n] = v[i];
5761     }
5762 
5763     /+
5764        Destructively reads the `n`th element in the composite
5765        range. Defined if all constituent ranges offer random
5766        access and have mobile elements.
5767     +/
5768     static if (allSatisfy!(isRandomAccessRange, Ranges)
5769         && allSatisfy!(hasMobileElements, Ranges))
5770     ElementType moveAt()(size_t n)
5771     {
5772         return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length)));
5773     }
5774 }
5775 
5776 pure @system unittest
5777 {
5778     import std.algorithm.comparison : equal;
5779     import std.algorithm.iteration : filter, map;
5780     import std.algorithm.mutation : swap;
5781     import std.algorithm.sorting : sort;
5782 
5783     import std.exception : assertThrown, assertNotThrown;
5784     import std.typecons : tuple;
5785 
5786     int[] a = [ 1, 2, 3 ];
5787     float[] b = [ 1.0, 2.0, 3.0 ];
5788     foreach (e; zip(a, b))
5789     {
5790         assert(e[0] == e[1]);
5791     }
5792 
5793     swap(a[0], a[1]);
5794     {
5795         auto z = zip(a, b);
5796     }
5797     //swap(z.front(), z.back());
5798     sort!("a[0] < b[0]")(zip(a, b));
5799     assert(a == [1, 2, 3]);
5800     assert(b == [2.0, 1.0, 3.0]);
5801 
5802     auto z = zip(StoppingPolicy.requireSameLength, a, b);
5803     assertNotThrown(z.popBack());
5804     assertNotThrown(z.popBack());
5805     assertNotThrown(z.popBack());
5806     assert(z.empty);
5807     assertThrown(z.popBack());
5808 
5809     a = [ 1, 2, 3 ];
5810     b = [ 1.0, 2.0, 3.0 ];
5811     sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
5812     assert(a == [3, 2, 1]);
5813     assert(b == [3.0, 2.0, 1.0]);
5814 
5815     a = [];
5816     b = [];
5817     assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
5818 
5819     // Test infiniteness propagation.
5820     static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
5821 
5822     // Test stopping policies with both value and reference.
5823     auto a1 = [1, 2];
5824     auto a2 = [1, 2, 3];
5825     auto stuff = tuple(tuple(a1, a2),
5826             tuple(filter!"a"(a1), filter!"a"(a2)));
5827 
5828     alias FOO = Zip!(immutable(int)[], immutable(float)[]);
5829 
5830     foreach (t; stuff.expand)
5831     {
5832         auto arr1 = t[0];
5833         auto arr2 = t[1];
5834         auto zShortest = zip(arr1, arr2);
5835         assert(equal(map!"a[0]"(zShortest), [1, 2]));
5836         assert(equal(map!"a[1]"(zShortest), [1, 2]));
5837 
5838         try {
5839             auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
5840             foreach (elem; zSame) {}
5841             assert(0);
5842         } catch (Throwable) { /* It's supposed to throw.*/ }
5843 
5844         auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
5845         assert(!zLongest.ranges[0].empty);
5846         assert(!zLongest.ranges[1].empty);
5847 
5848         zLongest.popFront();
5849         zLongest.popFront();
5850         assert(!zLongest.empty);
5851         assert(zLongest.ranges[0].empty);
5852         assert(!zLongest.ranges[1].empty);
5853 
5854         zLongest.popFront();
5855         assert(zLongest.empty);
5856     }
5857 
5858     // https://issues.dlang.org/show_bug.cgi?id=8900
5859     assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
5860     assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
5861 
5862     // https://issues.dlang.org/show_bug.cgi?id=18524
5863     // moveBack instead performs moveFront
5864     {
5865         auto r = zip([1,2,3]);
5866         assert(r.moveBack()[0] == 3);
5867         assert(r.moveFront()[0] == 1);
5868     }
5869 
5870     // Doesn't work yet.  Issues w/ emplace.
5871     // static assert(is(Zip!(immutable int[], immutable float[])));
5872 
5873 
5874     // These unittests pass, but make the compiler consume an absurd amount
5875     // of RAM and time.  Therefore, they should only be run if explicitly
5876     // uncommented when making changes to Zip.  Also, running them using
5877     // make -fwin32.mak unittest makes the compiler completely run out of RAM.
5878     // You need to test just this module.
5879     /+
5880      foreach (DummyType1; AllDummyRanges)
5881      {
5882          DummyType1 d1;
5883          foreach (DummyType2; AllDummyRanges)
5884          {
5885              DummyType2 d2;
5886              auto r = zip(d1, d2);
5887              assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
5888              assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
5889 
5890              static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
5891              {
5892                  static assert(isForwardRange!(typeof(r)));
5893              }
5894 
5895              static if (isBidirectionalRange!DummyType1 &&
5896                      isBidirectionalRange!DummyType2) {
5897                  static assert(isBidirectionalRange!(typeof(r)));
5898              }
5899              static if (isRandomAccessRange!DummyType1 &&
5900                      isRandomAccessRange!DummyType2) {
5901                  static assert(isRandomAccessRange!(typeof(r)));
5902              }
5903          }
5904      }
5905     +/
5906 }
5907 
5908 nothrow pure @safe unittest
5909 {
5910     import std.algorithm.sorting : sort;
5911 
5912     auto a = [5,4,3,2,1];
5913     auto b = [3,1,2,5,6];
5914     auto z = zip(a, b);
5915 
5916     sort!"a[0] < b[0]"(z);
5917 
5918     assert(a == [1, 2, 3, 4, 5]);
5919     assert(b == [6, 5, 2, 1, 3]);
5920 }
5921 
5922 nothrow pure @safe unittest
5923 {
5924     import std.algorithm.comparison : equal;
5925     import std.typecons : tuple;
5926 
5927     auto LL = iota(1L, 1000L);
5928     auto z = zip(LL, [4]);
5929 
5930     assert(equal(z, [tuple(1L,4)]));
5931 
5932     auto LL2 = iota(0L, 500L);
5933     auto z2 = zip([7], LL2);
5934     assert(equal(z2, [tuple(7, 0L)]));
5935 }
5936 
5937 // Test for https://issues.dlang.org/show_bug.cgi?id=11196
5938 @safe pure unittest
5939 {
5940     import std.exception : assertThrown;
5941 
5942     static struct S { @disable this(); }
5943     assert(zip((S[5]).init[]).length == 5);
5944     assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
5945     assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
5946 }
5947 
5948 // https://issues.dlang.org/show_bug.cgi?id=12007
5949 @nogc nothrow @safe pure unittest
5950 {
5951     static struct R
5952     {
5953         enum empty = false;
5954         void popFront(){}
5955         int front(){return 1;} @property
5956         R save(){return this;} @property
5957         void opAssign(R) @disable;
5958     }
5959     R r;
5960     auto z = zip(r, r);
5961     assert(z.save == z);
5962 }
5963 
5964 nothrow pure @system unittest
5965 {
5966     import std.typecons : tuple;
5967 
5968     auto r1 = [0,1,2];
5969     auto r2 = [1,2,3];
5970     auto z1 = zip(refRange(&r1), refRange(&r2));
5971     auto z2 = z1.save;
5972     z1.popFront();
5973     assert(z1.front == tuple(1,2));
5974     assert(z2.front == tuple(0,1));
5975 }
5976 
5977 @nogc nothrow pure @safe unittest
5978 {
5979     // Test zip's `back` and `length` with non-equal ranges.
5980     static struct NonSliceableRandomAccess
5981     {
5982         private int[] a;
5983         @property ref front()
5984         {
5985             return a.front;
5986         }
5987         @property ref back()
5988         {
5989             return a.back;
5990         }
5991         ref opIndex(size_t i)
5992         {
5993             return a[i];
5994         }
5995         void popFront()
5996         {
5997             a.popFront();
5998         }
5999         void popBack()
6000         {
6001             a.popBack();
6002         }
6003         auto moveFront()
6004         {
6005             return a.moveFront();
6006         }
6007         auto moveBack()
6008         {
6009             return a.moveBack();
6010         }
6011         auto moveAt(size_t i)
6012         {
6013             return a.moveAt(i);
6014         }
6015         bool empty() const
6016         {
6017             return a.empty;
6018         }
6019         size_t length() const
6020         {
6021             return a.length;
6022         }
6023         typeof(this) save()
6024         {
6025             return this;
6026         }
6027     }
6028     static assert(isRandomAccessRange!NonSliceableRandomAccess);
6029     static assert(!hasSlicing!NonSliceableRandomAccess);
6030     static foreach (iteration; 0 .. 2)
6031     {{
6032         int[5] data = [101, 102, 103, 201, 202];
6033         static if (iteration == 0)
6034         {
6035             auto r1 = NonSliceableRandomAccess(data[0 .. 3]);
6036             auto r2 = NonSliceableRandomAccess(data[3 .. 5]);
6037         }
6038         else
6039         {
6040             auto r1 = data[0 .. 3];
6041             auto r2 = data[3 .. 5];
6042         }
6043         auto z = zip(r1, r2);
6044         static assert(isRandomAccessRange!(typeof(z)));
6045         assert(z.length == 2);
6046         assert(z.back[0] == 102 && z.back[1] == 202);
6047         z.back = typeof(z.back)(-102, -202);// Assign to back.
6048         assert(z.back[0] == -102 && z.back[1] == -202);
6049         z.popBack();
6050         assert(z.length == 1);
6051         assert(z.back[0] == 101 && z.back[1] == 201);
6052         z.front = typeof(z.front)(-101, -201);
6053         assert(z.moveBack() == typeof(z.back)(-101, -201));
6054         z.popBack();
6055         assert(z.empty);
6056     }}
6057 }
6058 
6059 @nogc nothrow pure @safe unittest
6060 {
6061     // Test opSlice on infinite `zip`.
6062     auto z = zip(repeat(1), repeat(2));
6063     assert(hasSlicing!(typeof(z)));
6064     auto slice = z[10 .. 20];
6065     assert(slice.length == 10);
6066     static assert(!is(typeof(z) == typeof(slice)));
6067 }
6068 
6069 /*
6070     Generate lockstep's opApply function as a mixin string.
6071     If withIndex is true prepend a size_t index to the delegate.
6072 */
6073 private struct LockstepMixin(Ranges...)
6074 {
6075     import std.conv : text;
6076     import std.format : format;
6077 
6078     string name;
6079     string implName;
6080     string[] params;
6081     string[] emptyChecks;
6082     string[] dgArgs;
6083     string[] popFronts;
6084     string indexDef;
6085     string indexInc;
6086 
6087 @safe pure:
6088     this(bool withIndex, bool reverse)
6089     {
6090         if (withIndex)
6091         {
6092             params ~= "size_t";
6093             dgArgs ~= "index";
6094             if (reverse)
6095             {
6096                 indexDef = q{
6097                     size_t index = ranges[0].length - 1;
6098                     enforce(
6099                         this.stoppingPolicy == StoppingPolicy.requireSameLength,
6100                         "Indexed lockstep can only be used with foreach_reverse when " ~
6101                         "stoppingPolicy == requireSameLength");
6102 
6103                     foreach (range; ranges[1 .. $])
6104                         enforce(range.length == ranges[0].length);
6105                     };
6106                 indexInc = "--index;";
6107             }
6108             else
6109             {
6110                 indexDef = "size_t index = 0;";
6111                 indexInc = "++index;";
6112             }
6113         }
6114 
6115         foreach (idx, Range; Ranges)
6116         {
6117             params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6118             emptyChecks ~= format("!ranges[%s].empty", idx);
6119             if (reverse)
6120             {
6121                 dgArgs ~= format("ranges[%s].back", idx);
6122                 popFronts ~= format("ranges[%s].popBack();", idx);
6123             }
6124             else
6125             {
6126                 dgArgs ~= format("ranges[%s].front", idx);
6127                 popFronts ~= format("ranges[%s].popFront();", idx);
6128             }
6129         }
6130 
6131         if (reverse)
6132         {
6133             name = "opApplyReverse";
6134             if (withIndex) implName = "opApplyReverseIdxImpl";
6135             else           implName = "opApplyReverseImpl";
6136         }
6137         else
6138         {
6139             name = "opApply";
6140             if (withIndex) implName = "opApplyIdxImpl";
6141             else           implName = "opApplyImpl";
6142         }
6143     }
6144 
6145 const:
6146     string getAlias()
6147     {
6148         return format(q{
6149             alias %s = %s!(int delegate(%-(%s%|, %)));
6150         },
6151             name, implName, params
6152         );
6153     }
6154 
6155     string getImpl()
6156     {
6157         return format(q{
6158             int %s(DG)(scope DG dg) scope
6159             {
6160                 import std.exception : enforce;
6161 
6162                 auto ranges = this.ranges;
6163                 %s
6164 
6165                 while (%-(%s%| && %))
6166                 {
6167                     if (int result = dg(%-(%s%|, %))) return result;
6168                     %-(%s%|
6169                     %)
6170                     %s
6171                 }
6172 
6173                 if (this.stoppingPolicy == StoppingPolicy.requireSameLength)
6174                 {
6175                     foreach (range; ranges)
6176                         enforce(range.empty);
6177                 }
6178                 return 0;
6179             }
6180         },
6181             implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc
6182         );
6183     }
6184 }
6185 
6186 /**
6187    Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
6188    $(LREF zip) it allows reference access to its elements. If only a single
6189    range is passed in, the `Lockstep` aliases itself away.  If the
6190    ranges are of different lengths and `s` == `StoppingPolicy.shortest`
6191    stop after the shortest range is empty.  If the ranges are of different
6192    lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
6193    exception.  `s` may not be `StoppingPolicy.longest`, and passing this
6194    will throw an exception.
6195 
6196    Iterating over `Lockstep` in reverse and with an index is only possible
6197    when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
6198    indexes. If an attempt is made at iterating in reverse when `s` ==
6199    `StoppingPolicy.shortest`, an exception will be thrown.
6200 
6201    By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
6202 
6203    See_Also: $(LREF zip)
6204 
6205        `lockstep` is similar to $(LREF zip), but `zip` bundles its
6206        elements and returns a range.
6207        `lockstep` also supports reference access.
6208        Use `zip` if you want to pass the result to a range function.
6209 */
6210 struct Lockstep(Ranges...)
6211 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
6212 {
6213     private Ranges ranges;
6214     private StoppingPolicy stoppingPolicy;
6215 
6216     ///
6217     this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest)
6218     {
6219         import std.exception : enforce;
6220 
6221         this.ranges = ranges;
6222         enforce(sp != StoppingPolicy.longest,
6223             "Can't use StoppingPolicy.Longest on Lockstep.");
6224         this.stoppingPolicy = sp;
6225     }
6226 
6227     private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false);
6228     mixin(lockstepMixinFF.getImpl);
6229 
6230     private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false);
6231     mixin(lockstepMixinTF.getImpl);
6232 
6233     mixin(lockstepMixinFF.getAlias);
6234     mixin(lockstepMixinTF.getAlias);
6235 
6236     static if (allSatisfy!(isBidirectionalRange, Ranges))
6237     {
6238         private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true);
6239         mixin(lockstepMixinFT.getImpl);
6240         static if (allSatisfy!(hasLength, Ranges))
6241         {
6242             private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true);
6243             mixin(lockstepMixinTT.getImpl);
6244             mixin(lockstepMixinTT.getAlias);
6245         }
6246         else
6247         {
6248             mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
6249             alias opApplyReverse = opApplyReverseIdxFail;
6250         }
6251         mixin(lockstepMixinFT.getAlias);
6252     }
6253     else
6254     {
6255         mixin(lockstepReverseFailMixin!Ranges(withIndex: false));
6256         mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
6257         alias opApplyReverse = opApplyReverseFail;
6258         alias opApplyReverse = opApplyReverseIdxFail;
6259     }
6260 }
6261 
6262 /// Ditto
6263 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
6264 if (allSatisfy!(isInputRange, Ranges))
6265 {
6266     return Lockstep!(Ranges)(ranges);
6267 }
6268 /// Ditto
6269 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
6270 if (allSatisfy!(isInputRange, Ranges))
6271 {
6272     static if (Ranges.length > 1)
6273         return Lockstep!Ranges(ranges, s);
6274     else
6275         return ranges[0];
6276 }
6277 
6278 ///
6279 pure @safe unittest
6280 {
6281     int[6] arr1 = [1,2,3,4,5,100];
6282     int[5] arr2 = [6,7,8,9,10];
6283 
6284     foreach (ref a, b; lockstep(arr1[], arr2[]))
6285     {
6286         a += b;
6287     }
6288 
6289     assert(arr1 == [7,9,11,13,15,100]);
6290 }
6291 
6292 /// Lockstep also supports iterating with an index variable:
6293 pure @safe unittest
6294 {
6295     int[3] arr1 = [1,2,3];
6296     int[3] arr2 = [4,5,6];
6297 
6298     foreach (index, a, b; lockstep(arr1[], arr2[]))
6299     {
6300         assert(arr1[index] == a);
6301         assert(arr2[index] == b);
6302     }
6303 }
6304 
6305 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
6306 pure @safe unittest
6307 {
6308     auto arr1 = [0, 1, 2, 3];
6309     auto arr2 = [4, 5, 6, 7];
6310 
6311     size_t n = arr1.length - 1;
6312     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
6313     {
6314         assert(n == index);
6315         assert(index == a);
6316         assert(arr1[index] == a);
6317         assert(arr2[index] == b);
6318         n--;
6319     }
6320 
6321     auto arr3 = [4, 5];
6322     n = 1;
6323     foreach_reverse (a, b; lockstep(arr1, arr3))
6324     {
6325         assert(a == arr1[$-n] && b == arr3[$-n]);
6326         n++;
6327     }
6328 }
6329 
6330 pure @safe unittest
6331 {
6332     import std.algorithm.iteration : filter;
6333     import std.conv : to;
6334 
6335     // The filters are to make these the lowest common forward denominator ranges,
6336     // i.e. w/o ref return, random access, length, etc.
6337     auto foo = filter!"a"([1,2,3,4,5]);
6338     immutable bar = [6f,7f,8f,9f,10f].idup;
6339     auto l = lockstep(foo, bar);
6340 
6341     // Should work twice.  These are forward ranges with implicit save.
6342     foreach (i; 0 .. 2)
6343     {
6344         uint[] res1;
6345         float[] res2;
6346 
6347         foreach (a, ref b; l)
6348         {
6349             res1 ~= a;
6350             res2 ~= b;
6351         }
6352 
6353         assert(res1 == [1,2,3,4,5]);
6354         assert(res2 == [6,7,8,9,10]);
6355         assert(bar == [6f,7f,8f,9f,10f]);
6356     }
6357 
6358     // Doc example.
6359     auto arr1 = [1,2,3,4,5];
6360     auto arr2 = [6,7,8,9,10];
6361 
6362     foreach (ref a, ref b; lockstep(arr1, arr2))
6363     {
6364         a += b;
6365     }
6366 
6367     assert(arr1 == [7,9,11,13,15]);
6368 
6369     // Make sure StoppingPolicy.requireSameLength doesn't throw.
6370     auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6371 
6372     int k = 1;
6373     foreach (a, b; ls)
6374     {
6375         assert(a - b == k);
6376         ++k;
6377     }
6378 
6379     // Make sure StoppingPolicy.requireSameLength throws.
6380     arr2.popBack();
6381     ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6382 
6383     try {
6384         foreach (a, b; ls) {}
6385         assert(0);
6386     } catch (Exception) {}
6387 
6388     // Just make sure 1-range case instantiates. This hangs the compiler
6389     // when no explicit stopping policy is specified due to
6390     // https://issues.dlang.org/show_bug.cgi?id=4652
6391     auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
6392     foreach (i, a; stuff)
6393     {
6394         assert(stuff[i] == a);
6395     }
6396 
6397     // Test with indexing.
6398     uint[] res1;
6399     float[] res2;
6400     size_t[] indices;
6401     foreach (i, a, b; lockstep(foo, bar))
6402     {
6403         indices ~= i;
6404         res1 ~= a;
6405         res2 ~= b;
6406     }
6407 
6408     assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
6409     assert(res1 == [1,2,3,4,5]);
6410     assert(res2 == [6f,7f,8f,9f,10f]);
6411 
6412     // Make sure we've worked around the relevant compiler bugs and this at least
6413     // compiles w/ >2 ranges.
6414     lockstep(foo, foo, foo);
6415 
6416     // Make sure it works with const.
6417     const(int[])[] foo2 = [[1, 2, 3]];
6418     const(int[])[] bar2 = [[4, 5, 6]];
6419     auto c = chain(foo2, bar2);
6420 
6421     foreach (f, b; lockstep(c, c)) {}
6422 
6423     // Regression 10468
6424     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
6425 }
6426 
6427 pure @safe unittest
6428 {
6429     struct RvalueRange
6430     {
6431         int[] impl;
6432         @property bool empty() { return impl.empty; }
6433         @property int front() { return impl[0]; } // N.B. non-ref
6434         void popFront() { impl.popFront(); }
6435     }
6436     auto data1 = [ 1, 2, 3, 4 ];
6437     auto data2 = [ 5, 6, 7, 8 ];
6438     auto r1 = RvalueRange(data1);
6439     auto r2 = data2;
6440     foreach (a, ref b; lockstep(r1, r2))
6441     {
6442         a++;
6443         b++;
6444     }
6445     assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
6446     assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
6447 
6448     // Since r1 is by-value only, the compiler should reject attempts to
6449     // foreach over it with ref.
6450     static assert(!__traits(compiles, {
6451         foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
6452     }));
6453 }
6454 
6455 private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
6456 {
6457     import std.format : format;
6458     string[] params;
6459     string message;
6460 
6461     if (withIndex)
6462     {
6463         message = "Indexed reverse iteration with lockstep is only supported"
6464         ~"if all ranges are bidirectional and have a length.\n";
6465     }
6466     else
6467     {
6468         message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
6469     }
6470 
6471     if (withIndex)
6472     {
6473         params ~= "size_t";
6474     }
6475 
6476     foreach (idx, Range; Ranges)
6477     {
6478         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6479     }
6480 
6481     return format(
6482     q{
6483         int opApplyReverse%sFail()(scope int delegate(%s) dg)
6484         {
6485             static assert(false, "%s");
6486         }
6487     }, withIndex ? "Idx" : "" , params.join(", "), message);
6488 }
6489 
6490 // For generic programming, make sure Lockstep!(Range) is well defined for a
6491 // single range.
6492 template Lockstep(Range)
6493 {
6494     alias Lockstep = Range;
6495 }
6496 
6497 /**
6498 Creates a mathematical sequence given the initial values and a
6499 recurrence function that computes the next value from the existing
6500 values. The sequence comes in the form of an infinite forward
6501 range. The type `Recurrence` itself is seldom used directly; most
6502 often, recurrences are obtained by calling the function $(D
6503 recurrence).
6504 
6505 When calling `recurrence`, the function that computes the next
6506 value is specified as a template argument, and the initial values in
6507 the recurrence are passed as regular arguments. For example, in a
6508 Fibonacci sequence, there are two initial values (and therefore a
6509 state size of 2) because computing the next Fibonacci value needs the
6510 past two values.
6511 
6512 The signature of this function should be:
6513 ----
6514 auto fun(R)(R state, size_t n)
6515 ----
6516 where `n` will be the index of the current value, and `state` will be an
6517 opaque state vector that can be indexed with array-indexing notation
6518 `state[i]`, where valid values of `i` range from $(D (n - 1)) to
6519 $(D (n - State.length)).
6520 
6521 If the function is passed in string form, the state has name `"a"`
6522 and the zero-based index in the recurrence has name `"n"`. The
6523 given string must return the desired value for `a[n]` given
6524 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
6525 state size is dictated by the number of arguments passed to the call
6526 to `recurrence`. The `Recurrence` struct itself takes care of
6527 managing the recurrence's state and shifting it appropriately.
6528  */
6529 struct Recurrence(alias fun, StateType, size_t stateSize)
6530 {
6531     import std.functional : binaryFun;
6532 
6533     StateType[stateSize] _state;
6534     size_t _n;
6535 
6536     this(StateType[stateSize] initial) { _state = initial; }
6537 
6538     void popFront()
6539     {
6540         static auto trustedCycle(ref typeof(_state) s) @trusted
6541         {
6542             return cycle(s);
6543         }
6544         // The cast here is reasonable because fun may cause integer
6545         // promotion, but needs to return a StateType to make its operation
6546         // closed.  Therefore, we have no other choice.
6547         _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
6548             trustedCycle(_state), _n + stateSize);
6549         ++_n;
6550     }
6551 
6552     @property StateType front()
6553     {
6554         return _state[_n % stateSize];
6555     }
6556 
6557     @property typeof(this) save()
6558     {
6559         return this;
6560     }
6561 
6562     enum bool empty = false;
6563 }
6564 
6565 ///
6566 pure @safe nothrow unittest
6567 {
6568     import std.algorithm.comparison : equal;
6569 
6570     // The Fibonacci numbers, using function in string form:
6571     // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
6572     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6573     assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
6574 
6575     // The factorials, using function in lambda form:
6576     auto fac = recurrence!((a,n) => a[n-1] * n)(1);
6577     assert(take(fac, 10).equal([
6578         1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
6579     ]));
6580 
6581     // The triangular numbers, using function in explicit form:
6582     static size_t genTriangular(R)(R state, size_t n)
6583     {
6584         return state[n-1] + n;
6585     }
6586     auto tri = recurrence!genTriangular(0);
6587     assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
6588 }
6589 
6590 /// Ditto
6591 Recurrence!(fun, CommonType!(State), State.length)
6592 recurrence(alias fun, State...)(State initial)
6593 {
6594     CommonType!(State)[State.length] state;
6595     foreach (i, Unused; State)
6596     {
6597         state[i] = initial[i];
6598     }
6599     return typeof(return)(state);
6600 }
6601 
6602 pure @safe nothrow unittest
6603 {
6604     import std.algorithm.comparison : equal;
6605 
6606     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6607     static assert(isForwardRange!(typeof(fib)));
6608 
6609     int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
6610     assert(equal(take(fib, 10), witness));
6611     foreach (e; take(fib, 10)) {}
6612     auto fact = recurrence!("n * a[n-1]")(1);
6613     assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
6614                             2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
6615     auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
6616     foreach (e; take(piapprox, 20)) {}
6617     // Thanks to yebblies for this test and the associated fix
6618     auto r = recurrence!"a[n-2]"(1, 2);
6619     witness = [1, 2, 1, 2, 1];
6620     assert(equal(take(r, 5), witness));
6621 }
6622 
6623 /**
6624    `Sequence` is similar to `Recurrence` except that iteration is
6625    presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
6626    closed form). This means that the `n`th element in the series is
6627    computable directly from the initial values and `n` itself. This
6628    implies that the interface offered by `Sequence` is a random-access
6629    range, as opposed to the regular `Recurrence`, which only offers
6630    forward iteration.
6631 
6632    The state of the sequence is stored as a `Tuple` so it can be
6633    heterogeneous.
6634 */
6635 struct Sequence(alias fun, State)
6636 {
6637 private:
6638     import std.functional : binaryFun;
6639 
6640     alias compute = binaryFun!(fun, "a", "n");
6641     alias ElementType = typeof(compute(State.init, cast(size_t) 1));
6642     State _state;
6643     size_t _n;
6644 
6645     static struct DollarToken{}
6646 
6647 public:
6648     this(State initial, size_t n = 0)
6649     {
6650         _state = initial;
6651         _n = n;
6652     }
6653 
6654     @property ElementType front()
6655     {
6656         return compute(_state, _n);
6657     }
6658 
6659     void popFront()
6660     {
6661         ++_n;
6662     }
6663 
6664     enum opDollar = DollarToken();
6665 
6666     auto opSlice(size_t lower, size_t upper)
6667     in
6668     {
6669         assert(
6670             upper >= lower,
6671             "Attempting to slice a Sequence with a larger first argument than the second."
6672         );
6673     }
6674     do
6675     {
6676         return typeof(this)(_state, _n + lower).take(upper - lower);
6677     }
6678 
6679     auto opSlice(size_t lower, DollarToken)
6680     {
6681         return typeof(this)(_state, _n + lower);
6682     }
6683 
6684     ElementType opIndex(size_t n)
6685     {
6686         return compute(_state, n + _n);
6687     }
6688 
6689     enum bool empty = false;
6690 
6691     @property Sequence save() { return this; }
6692 }
6693 
6694 /// Ditto
6695 auto sequence(alias fun, State...)(State args)
6696 {
6697     import std.typecons : Tuple, tuple;
6698     alias Return = Sequence!(fun, Tuple!State);
6699     return Return(tuple(args));
6700 }
6701 
6702 /// Odd numbers, using function in string form:
6703 pure @safe nothrow @nogc unittest
6704 {
6705     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6706     assert(odds.front == 1);
6707     odds.popFront();
6708     assert(odds.front == 3);
6709     odds.popFront();
6710     assert(odds.front == 5);
6711 }
6712 
6713 /// Triangular numbers, using function in lambda form:
6714 pure @safe nothrow @nogc unittest
6715 {
6716     auto tri = sequence!((a,n) => n*(n+1)/2)();
6717 
6718     // Note random access
6719     assert(tri[0] == 0);
6720     assert(tri[3] == 6);
6721     assert(tri[1] == 1);
6722     assert(tri[4] == 10);
6723     assert(tri[2] == 3);
6724 }
6725 
6726 /// Fibonacci numbers, using function in explicit form:
6727 @safe nothrow @nogc unittest
6728 {
6729     import std.math.exponential : pow;
6730     import std.math.rounding : round;
6731     import std.math.algebraic : sqrt;
6732     static ulong computeFib(S)(S state, size_t n)
6733     {
6734         // Binet's formula
6735         return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6736                                  state[2]));
6737     }
6738     auto fib = sequence!computeFib(
6739         (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
6740         (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
6741         sqrt(5.0));
6742 
6743     // Note random access with [] operator
6744     assert(fib[1] == 1);
6745     assert(fib[4] == 5);
6746     assert(fib[3] == 3);
6747     assert(fib[2] == 2);
6748     assert(fib[9] == 55);
6749 }
6750 
6751 pure @safe nothrow @nogc unittest
6752 {
6753     import std.typecons : Tuple, tuple;
6754     auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6755     static assert(isForwardRange!(typeof(y)));
6756 
6757     //@@BUG
6758     //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6759     //foreach (e; take(y, 15))
6760     {}                                 //writeln(e);
6761 
6762     auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6763         tuple(1, 2));
6764     for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6765     {
6766         assert(odds.front == odds[0]);
6767         assert(odds[0] == currentOdd);
6768         odds.popFront();
6769     }
6770 }
6771 
6772 pure @safe nothrow @nogc unittest
6773 {
6774     import std.algorithm.comparison : equal;
6775 
6776     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6777     static assert(hasSlicing!(typeof(odds)));
6778 
6779     //Note: don't use drop or take as the target of an equal,
6780     //since they'll both just forward to opSlice, making the tests irrelevant
6781 
6782     // static slicing tests
6783     assert(equal(odds[0 .. 5], only(1,  3,  5,  7,  9)));
6784     assert(equal(odds[3 .. 7], only(7,  9, 11, 13)));
6785 
6786     // relative slicing test, testing slicing is NOT agnostic of state
6787     auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6788     assert(equal(odds_less5[0 ..  3], only(11, 13, 15)));
6789     assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6790 
6791     //Infinite slicing tests
6792     odds = odds[10 .. $];
6793     assert(equal(odds.take(3), only(21, 23, 25)));
6794 }
6795 
6796 // https://issues.dlang.org/show_bug.cgi?id=5036
6797 pure @safe nothrow unittest
6798 {
6799     auto s = sequence!((a, n) => new int)(0);
6800     assert(s.front != s.front);  // no caching
6801 }
6802 
6803 // iota
6804 /**
6805    Creates a range of values that span the given starting and stopping
6806    values.
6807 
6808    Params:
6809    begin = The starting value.
6810    end = The value that serves as the stopping criterion. This value is not
6811         included in the range.
6812    step = The value to add to the current value at each iteration.
6813 
6814    Returns:
6815    A range that goes through the numbers `begin`, $(D begin + step),
6816    $(D begin + 2 * step), `...`, up to and excluding `end`.
6817 
6818    The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6819    0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6820    is returned. If $(D step == 0) then $(D begin == end) is an error.
6821 
6822    For built-in types, the range returned is a random access range. For
6823    user-defined types that support `++`, the range is an input
6824    range.
6825 
6826    An integral iota also supports `in` operator from the right. It takes
6827    the stepping into account, the integral won't be considered
6828    contained if it falls between two consecutive values of the range.
6829    `contains` does the same as in, but from lefthand side.
6830 
6831     Example:
6832     ---
6833     void main()
6834     {
6835         import std.stdio;
6836 
6837         // The following groups all produce the same output of:
6838         // 0 1 2 3 4
6839 
6840         foreach (i; 0 .. 5)
6841             writef("%s ", i);
6842         writeln();
6843 
6844         import std.range : iota;
6845         foreach (i; iota(0, 5))
6846             writef("%s ", i);
6847         writeln();
6848 
6849         writefln("%(%s %|%)", iota(0, 5));
6850 
6851         import std.algorithm.iteration : map;
6852         import std.algorithm.mutation : copy;
6853         import std.format;
6854         iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6855         writeln();
6856     }
6857     ---
6858 */
6859 auto iota(B, E, S)(B begin, E end, S step)
6860 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6861         && isIntegral!S)
6862 {
6863     import std.conv : unsigned;
6864 
6865     alias Value = CommonType!(Unqual!B, Unqual!E);
6866     alias StepType = Unqual!S;
6867 
6868     assert(step != 0 || begin == end);
6869 
6870     static struct Result
6871     {
6872         private Value current, last;
6873         private StepType step; // by convention, 0 if range is empty
6874 
6875         this(Value current, Value pastLast, StepType step)
6876         {
6877             if (current < pastLast && step > 0)
6878             {
6879                 // Iterating upward
6880                 assert(unsigned((pastLast - current) / step) <= size_t.max);
6881                 // Cast below can't fail because current < pastLast
6882                 this.last = cast(Value) (pastLast - 1);
6883                 this.last -= unsigned(this.last - current) % step;
6884             }
6885             else if (current > pastLast && step < 0)
6886             {
6887                 // Iterating downward
6888                 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6889                 // Cast below can't fail because current > pastLast
6890                 this.last = cast(Value) (pastLast + 1);
6891                 this.last += unsigned(current - this.last) % (0 - step);
6892             }
6893             else
6894             {
6895                 // Initialize an empty range
6896                 this.step = 0;
6897                 return;
6898             }
6899             this.step = step;
6900             this.current = current;
6901         }
6902 
6903         @property bool empty() const { return step == 0; }
6904         @property inout(Value) front() inout { assert(!empty); return current; }
6905         void popFront()
6906         {
6907             assert(!empty);
6908             if (current == last) step = 0;
6909             else current += step;
6910         }
6911 
6912         @property inout(Value) back() inout
6913         {
6914             assert(!empty);
6915             return last;
6916         }
6917         void popBack()
6918         {
6919             assert(!empty);
6920             if (current == last) step = 0;
6921             else last -= step;
6922         }
6923 
6924         @property auto save() { return this; }
6925 
6926         inout(Value) opIndex(ulong n) inout
6927         {
6928             assert(n < this.length);
6929 
6930             // Just cast to Value here because doing so gives overflow behavior
6931             // consistent with calling popFront() n times.
6932             return cast(inout Value) (current + step * n);
6933         }
6934         auto opBinaryRight(string op)(Value val) const
6935         if (op == "in")
6936         {
6937             if (empty) return false;
6938             //cast to avoid becoming unsigned
6939             auto supposedIndex = cast(StepType)(val - current) / step;
6940             return supposedIndex < length && supposedIndex * step + current == val;
6941         }
6942         auto contains(Value x){return x in this;}
6943         inout(Result) opSlice() inout { return this; }
6944         inout(Result) opSlice(ulong lower, ulong upper) inout
6945         {
6946             assert(upper >= lower && upper <= this.length);
6947 
6948             return cast(inout Result) Result(
6949                 cast(Value)(current + lower * step),
6950                 cast(Value)(current + upper * step),
6951                 step);
6952         }
6953         @property size_t length() const
6954         {
6955             if (step > 0)
6956                 return 1 + cast(size_t) (unsigned(last - current) / step);
6957             if (step < 0)
6958                 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6959             return 0;
6960         }
6961 
6962         alias opDollar = length;
6963     }
6964 
6965     return Result(begin, end, step);
6966 }
6967 
6968 /// Ditto
6969 auto iota(B, E)(B begin, E end)
6970 if (isFloatingPoint!(CommonType!(B, E)))
6971 {
6972     return iota(begin, end, CommonType!(B, E)(1));
6973 }
6974 
6975 /// Ditto
6976 auto iota(B, E)(B begin, E end)
6977 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6978 {
6979     import std.conv : unsigned;
6980 
6981     alias Value = CommonType!(Unqual!B, Unqual!E);
6982 
6983     static struct Result
6984     {
6985         private Value current, pastLast;
6986 
6987         this(Value current, Value pastLast)
6988         {
6989             if (current < pastLast)
6990             {
6991                 assert(unsigned(pastLast - current) <= size_t.max,
6992                     "`iota` range is too long");
6993 
6994                 this.current = current;
6995                 this.pastLast = pastLast;
6996             }
6997             else
6998             {
6999                 // Initialize an empty range
7000                 this.current = this.pastLast = current;
7001             }
7002         }
7003 
7004         @property bool empty() const { return current == pastLast; }
7005         @property inout(Value) front() inout
7006         {
7007             assert(!empty, "Attempt to access `front` of empty `iota` range");
7008             return current;
7009         }
7010         void popFront()
7011         {
7012             assert(!empty, "Attempt to `popFront` of empty `iota` range");
7013             ++current;
7014         }
7015 
7016         @property inout(Value) back() inout
7017         {
7018             assert(!empty, "Attempt to access `back` of empty `iota` range");
7019             return cast(inout(Value))(pastLast - 1);
7020         }
7021         void popBack()
7022         {
7023             assert(!empty, "Attempt to `popBack` of empty `iota` range");
7024             --pastLast;
7025         }
7026 
7027         @property auto save() { return this; }
7028 
7029         inout(Value) opIndex(size_t n) inout
7030         {
7031             assert(n < this.length,
7032                 "Attempt to read out-of-bounds index of `iota` range");
7033 
7034             // Just cast to Value here because doing so gives overflow behavior
7035             // consistent with calling popFront() n times.
7036             return cast(inout Value) (current + n);
7037         }
7038         auto opBinaryRight(string op)(Value val) const
7039         if (op == "in")
7040         {
7041             return current <= val && val < pastLast;
7042         }
7043         auto contains(Value x){return x in this;}
7044         inout(Result) opSlice() inout { return this; }
7045         inout(Result) opSlice(ulong lower, ulong upper) inout
7046         {
7047             assert(upper >= lower && upper <= this.length,
7048                 "Attempt to get out-of-bounds slice of `iota` range");
7049 
7050             return cast(inout Result) Result(cast(Value)(current + lower),
7051                                             cast(Value)(pastLast - (length - upper)));
7052         }
7053         @property size_t length() const
7054         {
7055             return cast(size_t)(pastLast - current);
7056         }
7057 
7058         alias opDollar = length;
7059     }
7060 
7061     return Result(begin, end);
7062 }
7063 
7064 /// Ditto
7065 auto iota(E)(E end)
7066 if (is(typeof(iota(E(0), end))))
7067 {
7068     E begin = E(0);
7069     return iota(begin, end);
7070 }
7071 
7072 /// Ditto
7073 // Specialization for floating-point types
7074 auto iota(B, E, S)(B begin, E end, S step)
7075 if (isFloatingPoint!(CommonType!(B, E, S)))
7076 in
7077 {
7078     assert(step != 0, "iota: step must not be 0");
7079     assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
7080 }
7081 do
7082 {
7083     alias Value = Unqual!(CommonType!(B, E, S));
7084     static struct Result
7085     {
7086         private Value start, step;
7087         private size_t index, count;
7088 
7089         this(Value start, Value end, Value step)
7090         {
7091             import std.conv : to;
7092 
7093             this.start = start;
7094             this.step = step;
7095             immutable fcount = (end - start) / step;
7096             count = to!size_t(fcount);
7097             auto pastEnd = start + count * step;
7098             if (step > 0)
7099             {
7100                 if (pastEnd < end) ++count;
7101                 assert(start + count * step >= end);
7102             }
7103             else
7104             {
7105                 if (pastEnd > end) ++count;
7106                 assert(start + count * step <= end);
7107             }
7108         }
7109 
7110         @property bool empty() const { return index == count; }
7111         @property Value front() const { assert(!empty); return start + step * index; }
7112         void popFront()
7113         {
7114             assert(!empty);
7115             ++index;
7116         }
7117         @property Value back() const
7118         {
7119             assert(!empty);
7120             return start + step * (count - 1);
7121         }
7122         void popBack()
7123         {
7124             assert(!empty);
7125             --count;
7126         }
7127 
7128         @property auto save() { return this; }
7129 
7130         Value opIndex(size_t n) const
7131         {
7132             assert(n < count);
7133             return start + step * (n + index);
7134         }
7135         inout(Result) opSlice() inout
7136         {
7137             return this;
7138         }
7139         inout(Result) opSlice(size_t lower, size_t upper) inout
7140         {
7141             assert(upper >= lower && upper <= count);
7142 
7143             Result ret = this;
7144             ret.index += lower;
7145             ret.count = upper - lower + ret.index;
7146             return cast(inout Result) ret;
7147         }
7148         @property size_t length() const
7149         {
7150             return count - index;
7151         }
7152 
7153         alias opDollar = length;
7154     }
7155 
7156     return Result(begin, end, step);
7157 }
7158 
7159 ///
7160 pure @safe unittest
7161 {
7162     import std.algorithm.comparison : equal;
7163     import std.math.operations : isClose;
7164 
7165     auto r = iota(0, 10, 1);
7166     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
7167     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
7168     assert(3 in r);
7169     assert(r.contains(3)); //Same as above
7170     assert(!(10 in r));
7171     assert(!(-8 in r));
7172     r = iota(0, 11, 3);
7173     assert(equal(r, [0, 3, 6, 9]));
7174     assert(r[2] == 6);
7175     assert(!(2 in r));
7176     auto rf = iota(0.0, 0.5, 0.1);
7177     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
7178 }
7179 
7180 pure nothrow @nogc @safe unittest
7181 {
7182     import std.traits : Signed;
7183    //float overloads use std.conv.to so can't be @nogc or nothrow
7184     alias ssize_t = Signed!size_t;
7185     assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
7186     assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
7187     assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
7188     assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
7189     assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
7190 }
7191 
7192 debug @system unittest
7193 {//check the contracts
7194     import core.exception : AssertError;
7195     import std.exception : assertThrown;
7196     assertThrown!AssertError(iota(1,2,0));
7197     assertThrown!AssertError(iota(0f,1f,0f));
7198     assertThrown!AssertError(iota(1f,0f,0.1f));
7199     assertThrown!AssertError(iota(0f,1f,-0.1f));
7200 }
7201 
7202 pure @system nothrow unittest
7203 {
7204     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
7205     auto r1 = iota(a.ptr, a.ptr + a.length, 1);
7206     assert(r1.front == a.ptr);
7207     assert(r1.back == a.ptr + a.length - 1);
7208     assert(&a[4] in r1);
7209 }
7210 
7211 pure @safe nothrow @nogc unittest
7212 {
7213     assert(iota(1UL, 0UL).length == 0);
7214     assert(iota(1UL, 0UL, 1).length == 0);
7215     assert(iota(0, 1, 1).length == 1);
7216     assert(iota(1, 0, -1).length == 1);
7217     assert(iota(0, 1, -1).length == 0);
7218     assert(iota(ulong.max, 0).length == 0);
7219 }
7220 
7221 pure @safe unittest
7222 {
7223     import std.algorithm.comparison : equal;
7224     import std.algorithm.searching : count;
7225     import std.math.operations : isClose, nextUp, nextDown;
7226     import std.meta : AliasSeq;
7227 
7228     static assert(is(ElementType!(typeof(iota(0f))) == float));
7229 
7230     static assert(hasLength!(typeof(iota(0, 2))));
7231     auto r = iota(0, 10, 1);
7232     assert(r[$ - 1] == 9);
7233     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7234 
7235     auto rSlice = r[2 .. 8];
7236     assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
7237 
7238     rSlice.popFront();
7239     assert(rSlice[0] == rSlice.front);
7240     assert(rSlice.front == 3);
7241 
7242     rSlice.popBack();
7243     assert(rSlice[rSlice.length - 1] == rSlice.back);
7244     assert(rSlice.back == 6);
7245 
7246     rSlice = r[0 .. 4];
7247     assert(equal(rSlice, [0, 1, 2, 3]));
7248     assert(3 in rSlice);
7249     assert(!(4 in rSlice));
7250 
7251     auto rr = iota(10);
7252     assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7253 
7254     r = iota(0, -10, -1);
7255     assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
7256     rSlice = r[3 .. 9];
7257     assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
7258 
7259     r = iota(0, -6, -3);
7260     assert(equal(r, [0, -3][]));
7261     rSlice = r[1 .. 2];
7262     assert(equal(rSlice, [-3]));
7263 
7264     r = iota(0, -7, -3);
7265     assert(equal(r, [0, -3, -6][]));
7266     assert(0 in r);
7267     assert(-6 in r);
7268     rSlice = r[1 .. 3];
7269     assert(equal(rSlice, [-3, -6]));
7270     assert(!(0 in rSlice));
7271     assert(!(-2 in rSlice));
7272     assert(!(-5 in rSlice));
7273     assert(!(3 in rSlice));
7274     assert(!(-9 in rSlice));
7275 
7276     r = iota(0, 11, 3);
7277     assert(equal(r, [0, 3, 6, 9][]));
7278     assert(r[2] == 6);
7279     rSlice = r[1 .. 3];
7280     assert(equal(rSlice, [3, 6]));
7281 
7282     auto rf = iota(0.0, 0.5, 0.1);
7283     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
7284     assert(rf.length == 5);
7285 
7286     rf.popFront();
7287     assert(rf.length == 4);
7288 
7289     auto rfSlice = rf[1 .. 4];
7290     assert(rfSlice.length == 3);
7291     assert(isClose(rfSlice, [0.2, 0.3, 0.4]));
7292 
7293     rfSlice.popFront();
7294     assert(isClose(rfSlice[0], 0.3));
7295 
7296     rf.popFront();
7297     assert(rf.length == 3);
7298 
7299     rfSlice = rf[1 .. 3];
7300     assert(rfSlice.length == 2);
7301     assert(isClose(rfSlice, [0.3, 0.4]));
7302     assert(isClose(rfSlice[0], 0.3));
7303 
7304     // With something just above 0.5
7305     rf = iota(0.0, nextUp(0.5), 0.1);
7306     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
7307     rf.popBack();
7308     assert(rf[rf.length - 1] == rf.back);
7309     assert(isClose(rf.back, 0.4));
7310     assert(rf.length == 5);
7311 
7312     // going down
7313     rf = iota(0.0, -0.5, -0.1);
7314     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
7315     rfSlice = rf[2 .. 5];
7316     assert(isClose(rfSlice, [-0.2, -0.3, -0.4]));
7317 
7318     rf = iota(0.0, nextDown(-0.5), -0.1);
7319     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
7320 
7321     // iota of longs
7322     auto rl = iota(5_000_000L);
7323     assert(rl.length == 5_000_000L);
7324     assert(0 in rl);
7325     assert(4_000_000L in rl);
7326     assert(!(-4_000_000L in rl));
7327     assert(!(5_000_000L in rl));
7328 
7329     // iota of longs with steps
7330     auto iota_of_longs_with_steps = iota(50L, 101L, 10);
7331     assert(iota_of_longs_with_steps.length == 6);
7332     assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
7333 
7334     // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
7335     // Actually trying to consume it is the only way to find something is wrong
7336     // because the public properties are all correct.
7337     auto iota_zero_unsigned = iota(0, 0u, 3);
7338     assert(count(iota_zero_unsigned) == 0);
7339 
7340     // https://issues.dlang.org/show_bug.cgi?id=7982
7341     // unsigned reverse iota can be buggy if `.length` doesn't
7342     // take them into account
7343     assert(iota(10u, 0u, -1).length == 10);
7344     assert(iota(10u, 0u, -2).length == 5);
7345     assert(iota(uint.max, uint.max-10, -1).length == 10);
7346     assert(iota(uint.max, uint.max-10, -2).length == 5);
7347     assert(iota(uint.max, 0u, -1).length == uint.max);
7348 
7349     assert(20 in iota(20u, 10u, -2));
7350     assert(16 in iota(20u, 10u, -2));
7351     assert(!(15 in iota(20u, 10u, -2)));
7352     assert(!(10 in iota(20u, 10u, -2)));
7353     assert(!(uint.max in iota(20u, 10u, -1)));
7354     assert(!(int.min in iota(20u, 10u, -1)));
7355     assert(!(int.max in iota(20u, 10u, -1)));
7356 
7357 
7358     // https://issues.dlang.org/show_bug.cgi?id=8920
7359     static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
7360         int, uint, long, ulong))
7361     {{
7362         Type val;
7363         foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
7364         assert(val == 10);
7365     }}
7366 }
7367 
7368 pure @safe nothrow unittest
7369 {
7370     import std.algorithm.mutation : copy;
7371     auto idx = new size_t[100];
7372     copy(iota(0, idx.length), idx);
7373 }
7374 
7375 @safe unittest
7376 {
7377     import std.meta : AliasSeq;
7378     static foreach (range; AliasSeq!(iota(2, 27, 4),
7379                              iota(3, 9),
7380                              iota(2.7, 12.3, .1),
7381                              iota(3.2, 9.7)))
7382     {{
7383         const cRange = range;
7384         const e = cRange.empty;
7385         const f = cRange.front;
7386         const b = cRange.back;
7387         const i = cRange[2];
7388         const s1 = cRange[];
7389         const s2 = cRange[0 .. 3];
7390         const l = cRange.length;
7391     }}
7392 }
7393 
7394 @system unittest
7395 {
7396     //The ptr stuff can't be done at compile time, so we unfortunately end
7397     //up with some code duplication here.
7398     auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
7399 
7400     {
7401         const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
7402         const e = cRange.empty;
7403         const f = cRange.front;
7404         const b = cRange.back;
7405         const i = cRange[2];
7406         const s1 = cRange[];
7407         const s2 = cRange[0 .. 3];
7408         const l = cRange.length;
7409     }
7410 
7411     {
7412         const cRange = iota(arr.ptr, arr.ptr + arr.length);
7413         const e = cRange.empty;
7414         const f = cRange.front;
7415         const b = cRange.back;
7416         const i = cRange[2];
7417         const s1 = cRange[];
7418         const s2 = cRange[0 .. 3];
7419         const l = cRange.length;
7420     }
7421 }
7422 
7423 @nogc nothrow pure @safe unittest
7424 {
7425     {
7426         ushort start = 0, end = 10, step = 2;
7427         foreach (i; iota(start, end, step))
7428             static assert(is(typeof(i) == ushort));
7429     }
7430     {
7431         ubyte start = 0, end = 255, step = 128;
7432         uint x;
7433         foreach (i; iota(start, end, step))
7434         {
7435             static assert(is(typeof(i) == ubyte));
7436             ++x;
7437         }
7438         assert(x == 2);
7439     }
7440 }
7441 
7442 /* Generic overload that handles arbitrary types that support arithmetic
7443  * operations.
7444  *
7445  * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
7446  * as they can be incremented with `++` and compared with `<` or `==`.
7447  */
7448 /// ditto
7449 auto iota(B, E)(B begin, E end)
7450 if (!isIntegral!(CommonType!(B, E)) &&
7451     !isFloatingPoint!(CommonType!(B, E)) &&
7452     !isPointer!(CommonType!(B, E)) &&
7453     is(typeof((ref B b) { ++b; })) &&
7454     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
7455 {
7456     static struct Result
7457     {
7458         B current;
7459         E end;
7460 
7461         @property bool empty()
7462         {
7463             static if (is(typeof(B.init < E.init)))
7464                 return !(current < end);
7465             else static if (is(typeof(B.init != E.init)))
7466                 return current == end;
7467             else
7468                 static assert(0);
7469         }
7470         @property auto front() { return current; }
7471         void popFront()
7472         {
7473             assert(!empty);
7474             ++current;
7475         }
7476         @property auto save() { return this; }
7477     }
7478     return Result(begin, end);
7479 }
7480 
7481 @safe unittest
7482 {
7483     import std.algorithm.comparison : equal;
7484 
7485     // Test iota() for a type that only supports ++ and != but does not have
7486     // '<'-ordering.
7487     struct Cyclic(int wrapAround)
7488     {
7489         int current;
7490 
7491         this(int start) { current = start % wrapAround; }
7492 
7493         bool opEquals(Cyclic c) const { return current == c.current; }
7494         bool opEquals(int i) const { return current == i; }
7495         void opUnary(string op)()
7496         if (op == "++")
7497         {
7498             current = (current + 1) % wrapAround;
7499         }
7500     }
7501     alias Cycle5 = Cyclic!5;
7502 
7503     // Easy case
7504     auto i1 = iota(Cycle5(1), Cycle5(4));
7505     assert(i1.equal([1, 2, 3]));
7506 
7507     // Wraparound case
7508     auto i2 = iota(Cycle5(3), Cycle5(2));
7509     assert(i2.equal([3, 4, 0, 1 ]));
7510 }
7511 
7512 // https://issues.dlang.org/show_bug.cgi?id=23453
7513 @safe unittest
7514 {
7515     auto r = iota('a', 'z');
7516     static assert(isForwardRange!(typeof(r)));
7517 }
7518 
7519 /**
7520    Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
7521    (below).
7522 */
7523 enum TransverseOptions
7524 {
7525 /**
7526    When transversed, the elements of a range of ranges are assumed to
7527    have different lengths (e.g. a jagged array).
7528 */
7529     assumeJagged,                      //default
7530     /**
7531        The transversal enforces that the elements of a range of ranges have
7532        all the same length (e.g. an array of arrays, all having the same
7533        length). Checking is done once upon construction of the transversal
7534        range.
7535     */
7536         enforceNotJagged,
7537     /**
7538        The transversal assumes, without verifying, that the elements of a
7539        range of ranges have all the same length. This option is useful if
7540        checking was already done from the outside of the range.
7541     */
7542         assumeNotJagged,
7543 }
7544 
7545 ///
7546 @safe pure unittest
7547 {
7548     import std.algorithm.comparison : equal;
7549     import std.exception : assertThrown;
7550 
7551     auto arr = [[1, 2], [3, 4, 5]];
7552 
7553     auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
7554     assert(r1.equal([1, 3]));
7555 
7556     // throws on construction
7557     assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
7558 
7559     auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
7560     assert(r2.equal([1, 3]));
7561 
7562     // either assuming or checking for equal lengths makes
7563     // the result a random access range
7564     assert(r2[0] == 1);
7565     static assert(!__traits(compiles, r1[0]));
7566 }
7567 
7568 /**
7569    Given a range of ranges, iterate transversally through the first
7570    elements of each of the enclosed ranges.
7571 */
7572 struct FrontTransversal(Ror,
7573         TransverseOptions opt = TransverseOptions.assumeJagged)
7574 {
7575     alias RangeOfRanges = Unqual!(Ror);
7576     alias RangeType     = .ElementType!RangeOfRanges;
7577     alias ElementType   = .ElementType!RangeType;
7578 
7579     private void prime()
7580     {
7581         static if (opt == TransverseOptions.assumeJagged)
7582         {
7583             while (!_input.empty && _input.front.empty)
7584             {
7585                 _input.popFront();
7586             }
7587             static if (isBidirectionalRange!RangeOfRanges)
7588             {
7589                 while (!_input.empty && _input.back.empty)
7590                 {
7591                     _input.popBack();
7592                 }
7593             }
7594         }
7595     }
7596 
7597 /**
7598    Construction from an input.
7599 */
7600     this(RangeOfRanges input)
7601     {
7602         _input = input;
7603         prime();
7604         static if (opt == TransverseOptions.enforceNotJagged)
7605             // (isRandomAccessRange!RangeOfRanges
7606             //     && hasLength!RangeType)
7607         {
7608             import std.exception : enforce;
7609 
7610             if (empty) return;
7611             immutable commonLength = _input.front.length;
7612             foreach (e; _input)
7613             {
7614                 enforce(e.length == commonLength);
7615             }
7616         }
7617     }
7618 
7619 /**
7620    Forward range primitives.
7621 */
7622     static if (isInfinite!RangeOfRanges)
7623     {
7624         enum bool empty = false;
7625     }
7626     else
7627     {
7628         @property bool empty()
7629         {
7630             static if (opt != TransverseOptions.assumeJagged)
7631             {
7632                 if (!_input.empty)
7633                     return _input.front.empty;
7634             }
7635 
7636             return _input.empty;
7637         }
7638     }
7639 
7640     /// Ditto
7641     @property auto ref front()
7642     {
7643         assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
7644         return _input.front.front;
7645     }
7646 
7647     /// Ditto
7648     static if (hasMobileElements!RangeType)
7649     {
7650         ElementType moveFront()
7651         {
7652             return _input.front.moveFront();
7653         }
7654     }
7655 
7656     static if (hasAssignableElements!RangeType)
7657     {
7658         @property void front(ElementType val)
7659         {
7660             import core.lifetime : forward;
7661 
7662             // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7663             _input.front.front = __ctfe ? val : forward!val;
7664         }
7665     }
7666 
7667     /// Ditto
7668     void popFront()
7669     {
7670         assert(!empty, "Attempting to popFront an empty FrontTransversal");
7671         _input.popFront();
7672         prime();
7673     }
7674 
7675 /**
7676    Duplicates this `frontTransversal`. Note that only the encapsulating
7677    range of range will be duplicated. Underlying ranges will not be
7678    duplicated.
7679 */
7680     static if (isForwardRange!RangeOfRanges)
7681     {
7682         @property FrontTransversal save()
7683         {
7684             return FrontTransversal(_input.save);
7685         }
7686     }
7687 
7688     static if (isBidirectionalRange!RangeOfRanges)
7689     {
7690 /**
7691    Bidirectional primitives. They are offered if $(D
7692    isBidirectionalRange!RangeOfRanges).
7693 */
7694         @property auto ref back()
7695         {
7696             assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7697             return _input.back.front;
7698         }
7699         /// Ditto
7700         void popBack()
7701         {
7702             assert(!empty, "Attempting to popBack an empty FrontTransversal");
7703             _input.popBack();
7704             prime();
7705         }
7706 
7707         /// Ditto
7708         static if (hasMobileElements!RangeType)
7709         {
7710             ElementType moveBack()
7711             {
7712                 return _input.back.moveFront();
7713             }
7714         }
7715 
7716         static if (hasAssignableElements!RangeType)
7717         {
7718             @property void back(ElementType val)
7719             {
7720                 import core.lifetime : forward;
7721 
7722                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7723                 _input.back.front = __ctfe ? val : forward!val;
7724             }
7725         }
7726     }
7727 
7728     static if (isRandomAccessRange!RangeOfRanges &&
7729             (opt == TransverseOptions.assumeNotJagged ||
7730                     opt == TransverseOptions.enforceNotJagged))
7731     {
7732 /**
7733    Random-access primitive. It is offered if $(D
7734    isRandomAccessRange!RangeOfRanges && (opt ==
7735    TransverseOptions.assumeNotJagged || opt ==
7736    TransverseOptions.enforceNotJagged)).
7737 */
7738         auto ref opIndex(size_t n)
7739         {
7740             return _input[n].front;
7741         }
7742 
7743         /// Ditto
7744         static if (hasMobileElements!RangeType)
7745         {
7746             ElementType moveAt(size_t n)
7747             {
7748                 return _input[n].moveFront();
7749             }
7750         }
7751         /// Ditto
7752         static if (hasAssignableElements!RangeType)
7753         {
7754             void opIndexAssign(ElementType val, size_t n)
7755             {
7756                 import core.lifetime : forward;
7757 
7758                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7759                 _input[n].front = __ctfe ? val : forward!val;
7760             }
7761         }
7762         mixin ImplementLength!_input;
7763 
7764 /**
7765    Slicing if offered if `RangeOfRanges` supports slicing and all the
7766    conditions for supporting indexing are met.
7767 */
7768         static if (hasSlicing!RangeOfRanges)
7769         {
7770             typeof(this) opSlice(size_t lower, size_t upper)
7771             {
7772                 return typeof(this)(_input[lower .. upper]);
7773             }
7774         }
7775     }
7776 
7777     auto opSlice() { return this; }
7778 
7779 private:
7780     RangeOfRanges _input;
7781 }
7782 
7783 /// Ditto
7784 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7785     TransverseOptions opt = TransverseOptions.assumeJagged,
7786     RangeOfRanges)
7787 (RangeOfRanges rr)
7788 {
7789     return typeof(return)(rr);
7790 }
7791 
7792 ///
7793 pure @safe nothrow unittest
7794 {
7795     import std.algorithm.comparison : equal;
7796     int[][] x = new int[][2];
7797     x[0] = [1, 2];
7798     x[1] = [3, 4];
7799     auto ror = frontTransversal(x);
7800     assert(equal(ror, [ 1, 3 ][]));
7801 }
7802 
7803 @safe unittest
7804 {
7805     import std.algorithm.comparison : equal;
7806     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7807 
7808     static assert(is(FrontTransversal!(immutable int[][])));
7809 
7810     foreach (DummyType; AllDummyRanges)
7811     {
7812         auto dummies =
7813             [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7814 
7815         foreach (i, ref elem; dummies)
7816         {
7817             // Just violate the DummyRange abstraction to get what I want.
7818             elem.arr = elem.arr[i..$ - (3 - i)];
7819         }
7820 
7821         auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7822         static if (isForwardRange!DummyType)
7823         {
7824             static assert(isForwardRange!(typeof(ft)));
7825         }
7826 
7827         assert(equal(ft, [1, 2, 3, 4]));
7828 
7829         // Test slicing.
7830         assert(equal(ft[0 .. 2], [1, 2]));
7831         assert(equal(ft[1 .. 3], [2, 3]));
7832 
7833         assert(ft.front == ft.moveFront());
7834         assert(ft.back == ft.moveBack());
7835         assert(ft.moveAt(1) == ft[1]);
7836 
7837 
7838         // Test infiniteness propagation.
7839         static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7840 
7841         static if (DummyType.r == ReturnBy.Reference)
7842         {
7843             {
7844                 ft.front++;
7845                 scope(exit) ft.front--;
7846                 assert(dummies.front.front == 2);
7847             }
7848 
7849             {
7850                 ft.front = 5;
7851                 scope(exit) ft.front = 1;
7852                 assert(dummies[0].front == 5);
7853             }
7854 
7855             {
7856                 ft.back = 88;
7857                 scope(exit) ft.back = 4;
7858                 assert(dummies.back.front == 88);
7859             }
7860 
7861             {
7862                 ft[1] = 99;
7863                 scope(exit) ft[1] = 2;
7864                 assert(dummies[1].front == 99);
7865             }
7866         }
7867     }
7868 }
7869 
7870 // https://issues.dlang.org/show_bug.cgi?id=16363
7871 pure @safe nothrow unittest
7872 {
7873     import std.algorithm.comparison : equal;
7874 
7875     int[][] darr = [[0, 1], [4, 5]];
7876     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7877 
7878     assert(equal(ft, [0, 4]));
7879     static assert(isRandomAccessRange!(typeof(ft)));
7880 }
7881 
7882 // https://issues.dlang.org/show_bug.cgi?id=16442
7883 pure @safe nothrow unittest
7884 {
7885     int[][] arr = [[], []];
7886 
7887     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7888     assert(ft.empty);
7889 }
7890 
7891 // ditto
7892 pure @safe unittest
7893 {
7894     int[][] arr = [[], []];
7895 
7896     auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7897     assert(ft.empty);
7898 }
7899 
7900 // https://issues.dlang.org/show_bug.cgi?id=24481
7901 @safe unittest
7902 {
7903     bool called;
7904     struct Handle
7905     {
7906         int entry;
7907         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
7908     }
7909 
7910     const(Handle)[][] arr = [[Handle(0), Handle(10)],
7911                              [Handle(1), Handle(11)],
7912                              [Handle(2), Handle(12)],
7913                              [Handle(3), Handle(13)],
7914                              [Handle(4), Handle(14)]];
7915 
7916     {
7917         auto range = arr.frontTransversal();
7918 
7919         called = false;
7920         range.front = Handle(42);
7921         assert(called == true);
7922 
7923         called = false;
7924         range.back = Handle(42);
7925         assert(called == true);
7926     }
7927     {
7928         auto range = arr.frontTransversal!(TransverseOptions.assumeNotJagged)();
7929 
7930         called = false;
7931         range.front = Handle(42);
7932         assert(called == true);
7933 
7934         called = false;
7935         range.back = Handle(42);
7936         assert(called == true);
7937 
7938         called = false;
7939         range[0] = Handle(42);
7940         assert(called == true);
7941     }
7942 }
7943 
7944 /**
7945     Given a range of ranges, iterate transversally through the
7946     `n`th element of each of the enclosed ranges. This function
7947     is similar to `unzip` in other languages.
7948 
7949     Params:
7950         opt = Controls the assumptions the function makes about the lengths
7951         of the ranges
7952         rr = An input range of random access ranges
7953     Returns:
7954         At minimum, an input range. Range primitives such as bidirectionality
7955         and random access are given if the element type of `rr` provides them.
7956 */
7957 struct Transversal(Ror,
7958         TransverseOptions opt = TransverseOptions.assumeJagged)
7959 {
7960     private alias RangeOfRanges = Unqual!Ror;
7961     private alias InnerRange = ElementType!RangeOfRanges;
7962     private alias E = ElementType!InnerRange;
7963 
7964     private void prime()
7965     {
7966         static if (opt == TransverseOptions.assumeJagged)
7967         {
7968             while (!_input.empty && _input.front.length <= _n)
7969             {
7970                 _input.popFront();
7971             }
7972             static if (isBidirectionalRange!RangeOfRanges)
7973             {
7974                 while (!_input.empty && _input.back.length <= _n)
7975                 {
7976                     _input.popBack();
7977                 }
7978             }
7979         }
7980     }
7981 
7982 /**
7983    Construction from an input and an index.
7984 */
7985     this(RangeOfRanges input, size_t n)
7986     {
7987         _input = input;
7988         _n = n;
7989         prime();
7990         static if (opt == TransverseOptions.enforceNotJagged)
7991         {
7992             import std.exception : enforce;
7993 
7994             if (empty) return;
7995             immutable commonLength = _input.front.length;
7996             foreach (e; _input)
7997             {
7998                 enforce(e.length == commonLength);
7999             }
8000         }
8001     }
8002 
8003 /**
8004    Forward range primitives.
8005 */
8006     static if (isInfinite!(RangeOfRanges))
8007     {
8008         enum bool empty = false;
8009     }
8010     else
8011     {
8012         @property bool empty()
8013         {
8014             return _input.empty;
8015         }
8016     }
8017 
8018     /// Ditto
8019     @property auto ref front()
8020     {
8021         assert(!empty, "Attempting to fetch the front of an empty Transversal");
8022         return _input.front[_n];
8023     }
8024 
8025     /// Ditto
8026     static if (hasMobileElements!InnerRange)
8027     {
8028         E moveFront()
8029         {
8030             return _input.front.moveAt(_n);
8031         }
8032     }
8033 
8034     /// Ditto
8035     static if (hasAssignableElements!InnerRange)
8036     {
8037         @property void front(E val)
8038         {
8039             _input.front[_n] = val;
8040         }
8041     }
8042 
8043 
8044     /// Ditto
8045     void popFront()
8046     {
8047         assert(!empty, "Attempting to popFront an empty Transversal");
8048         _input.popFront();
8049         prime();
8050     }
8051 
8052     /// Ditto
8053     static if (isForwardRange!RangeOfRanges)
8054     {
8055         @property typeof(this) save()
8056         {
8057             auto ret = this;
8058             ret._input = _input.save;
8059             return ret;
8060         }
8061     }
8062 
8063     static if (isBidirectionalRange!RangeOfRanges)
8064     {
8065 /**
8066    Bidirectional primitives. They are offered if $(D
8067    isBidirectionalRange!RangeOfRanges).
8068 */
8069         @property auto ref back()
8070         {
8071             assert(!empty, "Attempting to fetch the back of an empty Transversal");
8072             return _input.back[_n];
8073         }
8074 
8075         /// Ditto
8076         void popBack()
8077         {
8078             assert(!empty, "Attempting to popBack an empty Transversal");
8079             _input.popBack();
8080             prime();
8081         }
8082 
8083         /// Ditto
8084         static if (hasMobileElements!InnerRange)
8085         {
8086             E moveBack()
8087             {
8088                 return _input.back.moveAt(_n);
8089             }
8090         }
8091 
8092         /// Ditto
8093         static if (hasAssignableElements!InnerRange)
8094         {
8095             @property void back(E val)
8096             {
8097                 _input.back[_n] = val;
8098             }
8099         }
8100 
8101     }
8102 
8103     static if (isRandomAccessRange!RangeOfRanges &&
8104             (opt == TransverseOptions.assumeNotJagged ||
8105                     opt == TransverseOptions.enforceNotJagged))
8106     {
8107 /**
8108    Random-access primitive. It is offered if $(D
8109    isRandomAccessRange!RangeOfRanges && (opt ==
8110    TransverseOptions.assumeNotJagged || opt ==
8111    TransverseOptions.enforceNotJagged)).
8112 */
8113         auto ref opIndex(size_t n)
8114         {
8115             return _input[n][_n];
8116         }
8117 
8118         /// Ditto
8119         static if (hasMobileElements!InnerRange)
8120         {
8121             E moveAt(size_t n)
8122             {
8123                 return _input[n].moveAt(_n);
8124             }
8125         }
8126 
8127         /// Ditto
8128         static if (hasAssignableElements!InnerRange)
8129         {
8130             void opIndexAssign(E val, size_t n)
8131             {
8132                 _input[n][_n] = val;
8133             }
8134         }
8135 
8136         mixin ImplementLength!_input;
8137 
8138 /**
8139    Slicing if offered if `RangeOfRanges` supports slicing and all the
8140    conditions for supporting indexing are met.
8141 */
8142         static if (hasSlicing!RangeOfRanges)
8143         {
8144             typeof(this) opSlice(size_t lower, size_t upper)
8145             {
8146                 return typeof(this)(_input[lower .. upper], _n);
8147             }
8148         }
8149     }
8150 
8151     auto opSlice() { return this; }
8152 
8153 private:
8154     RangeOfRanges _input;
8155     size_t _n;
8156 }
8157 
8158 /// Ditto
8159 Transversal!(RangeOfRanges, opt) transversal
8160 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8161 (RangeOfRanges rr, size_t n)
8162 {
8163     return typeof(return)(rr, n);
8164 }
8165 
8166 ///
8167 @safe unittest
8168 {
8169     import std.algorithm.comparison : equal;
8170     int[][] x = new int[][2];
8171     x[0] = [1, 2];
8172     x[1] = [3, 4];
8173     auto ror = transversal(x, 1);
8174     assert(equal(ror, [ 2, 4 ]));
8175 }
8176 
8177 /// The following code does a full unzip
8178 @safe unittest
8179 {
8180     import std.algorithm.comparison : equal;
8181     import std.algorithm.iteration : map;
8182     int[][] y = [[1, 2, 3], [4, 5, 6]];
8183     auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
8184     assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
8185 }
8186 
8187 @safe unittest
8188 {
8189     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
8190 
8191     int[][] x = new int[][2];
8192     x[0] = [ 1, 2 ];
8193     x[1] = [3, 4];
8194     auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
8195     auto witness = [ 2, 4 ];
8196     uint i;
8197     foreach (e; ror) assert(e == witness[i++]);
8198     assert(i == 2);
8199     assert(ror.length == 2);
8200 
8201     static assert(is(Transversal!(immutable int[][])));
8202 
8203     // Make sure ref, assign is being propagated.
8204     {
8205         ror.front++;
8206         scope(exit) ror.front--;
8207         assert(x[0][1] == 3);
8208     }
8209     {
8210         ror.front = 5;
8211         scope(exit) ror.front = 2;
8212         assert(x[0][1] == 5);
8213         assert(ror.moveFront() == 5);
8214     }
8215     {
8216         ror.back = 999;
8217         scope(exit) ror.back = 4;
8218         assert(x[1][1] == 999);
8219         assert(ror.moveBack() == 999);
8220     }
8221     {
8222         ror[0] = 999;
8223         scope(exit) ror[0] = 2;
8224         assert(x[0][1] == 999);
8225         assert(ror.moveAt(0) == 999);
8226     }
8227 
8228     // Test w/o ref return.
8229     alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
8230     auto drs = [D.init, D.init];
8231     foreach (num; 0 .. 10)
8232     {
8233         auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
8234         assert(t[0] == t[1]);
8235         assert(t[1] == num + 1);
8236     }
8237 
8238     static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
8239 
8240     // Test slicing.
8241     auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
8242     auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
8243     assert(mat1[0] == 6);
8244     assert(mat1[1] == 10);
8245 }
8246 
8247 struct Transposed(RangeOfRanges,
8248     TransverseOptions opt = TransverseOptions.assumeJagged)
8249 if (isForwardRange!RangeOfRanges &&
8250     isInputRange!(ElementType!RangeOfRanges) &&
8251     hasAssignableElements!RangeOfRanges)
8252 {
8253     this(RangeOfRanges input)
8254     {
8255         this._input = input;
8256         static if (opt == TransverseOptions.enforceNotJagged)
8257         {
8258             import std.exception : enforce;
8259 
8260             if (empty) return;
8261             immutable commonLength = _input.front.length;
8262             foreach (e; _input)
8263             {
8264                 enforce(e.length == commonLength);
8265             }
8266         }
8267     }
8268 
8269     @property auto front()
8270     {
8271         import std.algorithm.iteration : filter, map;
8272         return _input.save
8273                      .filter!(a => !a.empty)
8274                      .map!(a => a.front);
8275     }
8276 
8277     void popFront()
8278     {
8279         // Advance the position of each subrange.
8280         auto r = _input.save;
8281         while (!r.empty)
8282         {
8283             auto e = r.front;
8284             if (!e.empty)
8285             {
8286                 e.popFront();
8287                 r.front = e;
8288             }
8289 
8290             r.popFront();
8291         }
8292     }
8293 
8294     static if (isRandomAccessRange!(ElementType!RangeOfRanges))
8295     {
8296         auto ref opIndex(size_t n)
8297         {
8298             return transversal!opt(_input, n);
8299         }
8300     }
8301 
8302     @property bool empty()
8303     {
8304         if (_input.empty) return true;
8305         foreach (e; _input.save)
8306         {
8307             if (!e.empty) return false;
8308         }
8309         return true;
8310     }
8311 
8312     auto opSlice() { return this; }
8313 
8314 private:
8315     RangeOfRanges _input;
8316 }
8317 
8318 @safe unittest
8319 {
8320     // Boundary case: transpose of empty range should be empty
8321     int[][] ror = [];
8322     assert(transposed(ror).empty);
8323 }
8324 
8325 // https://issues.dlang.org/show_bug.cgi?id=9507
8326 @safe unittest
8327 {
8328     import std.algorithm.comparison : equal;
8329 
8330     auto r = [[1,2], [3], [4,5], [], [6]];
8331     assert(r.transposed.equal!equal([
8332         [1, 3, 4, 6],
8333         [2, 5]
8334     ]));
8335 }
8336 
8337 // https://issues.dlang.org/show_bug.cgi?id=17742
8338 @safe unittest
8339 {
8340     import std.algorithm.iteration : map;
8341     import std.algorithm.comparison : equal;
8342     auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
8343     assert(ror[3][2] == 6);
8344     auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
8345     assert(result[2][3] == 6);
8346 
8347     auto x = [[1,2,3],[4,5,6]];
8348     auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
8349     assert(y.front.equal([1,4]));
8350     assert(y[0].equal([1,4]));
8351     assert(y[0][0] == 1);
8352     assert(y[1].equal([2,5]));
8353     assert(y[1][1] == 5);
8354 
8355     auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
8356     assert(yy.front.equal([1,4]));
8357     assert(yy[0].equal([1,4]));
8358     assert(yy[0][0] == 1);
8359     assert(yy[1].equal([2,5]));
8360     assert(yy[1][1] == 5);
8361 
8362     auto z = x.transposed; // assumeJagged
8363     assert(z.front.equal([1,4]));
8364     assert(z[0].equal([1,4]));
8365     assert(!is(typeof(z[0][0])));
8366 }
8367 
8368 @safe unittest
8369 {
8370     import std.exception : assertThrown;
8371 
8372     auto r = [[1,2], [3], [4,5], [], [6]];
8373     assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
8374 }
8375 
8376 /**
8377 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
8378 contains the $(I i)'th elements of the original subranges.
8379 
8380 Params:
8381     opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
8382     rr = Range of ranges
8383  */
8384 Transposed!(RangeOfRanges, opt) transposed
8385 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8386 (RangeOfRanges rr)
8387 if (isForwardRange!RangeOfRanges &&
8388     isInputRange!(ElementType!RangeOfRanges) &&
8389     hasAssignableElements!RangeOfRanges)
8390 {
8391     return Transposed!(RangeOfRanges, opt)(rr);
8392 }
8393 
8394 ///
8395 @safe unittest
8396 {
8397     import std.algorithm.comparison : equal;
8398     int[][] ror = [
8399         [1, 2, 3],
8400         [4, 5, 6]
8401     ];
8402     auto xp = transposed(ror);
8403     assert(equal!"a.equal(b)"(xp, [
8404         [1, 4],
8405         [2, 5],
8406         [3, 6]
8407     ]));
8408 }
8409 
8410 ///
8411 @safe unittest
8412 {
8413     int[][] x = new int[][2];
8414     x[0] = [1, 2];
8415     x[1] = [3, 4];
8416     auto tr = transposed(x);
8417     int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
8418     uint i;
8419 
8420     foreach (e; tr)
8421     {
8422         assert(array(e) == witness[i++]);
8423     }
8424 }
8425 
8426 // https://issues.dlang.org/show_bug.cgi?id=8764
8427 @safe unittest
8428 {
8429     import std.algorithm.comparison : equal;
8430     ulong[] t0 = [ 123 ];
8431 
8432     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
8433     assert(!is(typeof(transposed(t0[].chunks(1)))));
8434     assert(is(typeof(transposed(t0[].chunks(1).array()))));
8435 
8436     auto t1 = transposed(t0[].chunks(1).array());
8437     assert(equal!"a.equal(b)"(t1, [[123]]));
8438 }
8439 
8440 /**
8441 This struct takes two ranges, `source` and `indices`, and creates a view
8442 of `source` as if its elements were reordered according to `indices`.
8443 `indices` may include only a subset of the elements of `source` and
8444 may also repeat elements.
8445 
8446 `Source` must be a random access range.  The returned range will be
8447 bidirectional or random-access if `Indices` is bidirectional or
8448 random-access, respectively.
8449 */
8450 struct Indexed(Source, Indices)
8451 if (isRandomAccessRange!Source && isInputRange!Indices &&
8452     is(typeof(Source.init[ElementType!(Indices).init])))
8453 {
8454     this(Source source, Indices indices)
8455     {
8456         this._source = source;
8457         this._indices = indices;
8458     }
8459 
8460     /// Range primitives
8461     @property auto ref front()
8462     {
8463         assert(!empty, "Attempting to fetch the front of an empty Indexed");
8464         return _source[_indices.front];
8465     }
8466 
8467     /// Ditto
8468     void popFront()
8469     {
8470         assert(!empty, "Attempting to popFront an empty Indexed");
8471         _indices.popFront();
8472     }
8473 
8474     static if (isInfinite!Indices)
8475     {
8476         enum bool empty = false;
8477     }
8478     else
8479     {
8480         /// Ditto
8481         @property bool empty()
8482         {
8483             return _indices.empty;
8484         }
8485     }
8486 
8487     static if (isForwardRange!Indices)
8488     {
8489         /// Ditto
8490         @property typeof(this) save()
8491         {
8492             // Don't need to save _source because it's never consumed.
8493             return typeof(this)(_source, _indices.save);
8494         }
8495     }
8496 
8497     /// Ditto
8498     static if (hasAssignableElements!Source)
8499     {
8500         @property auto ref front(ElementType!Source newVal)
8501         {
8502             assert(!empty);
8503             return _source[_indices.front] = newVal;
8504         }
8505     }
8506 
8507 
8508     static if (hasMobileElements!Source)
8509     {
8510         /// Ditto
8511         auto moveFront()
8512         {
8513             assert(!empty);
8514             return _source.moveAt(_indices.front);
8515         }
8516     }
8517 
8518     static if (isBidirectionalRange!Indices)
8519     {
8520         /// Ditto
8521         @property auto ref back()
8522         {
8523             assert(!empty, "Attempting to fetch the back of an empty Indexed");
8524             return _source[_indices.back];
8525         }
8526 
8527         /// Ditto
8528         void popBack()
8529         {
8530            assert(!empty, "Attempting to popBack an empty Indexed");
8531            _indices.popBack();
8532         }
8533 
8534         /// Ditto
8535         static if (hasAssignableElements!Source)
8536         {
8537             @property auto ref back(ElementType!Source newVal)
8538             {
8539                 assert(!empty);
8540                 return _source[_indices.back] = newVal;
8541             }
8542         }
8543 
8544 
8545         static if (hasMobileElements!Source)
8546         {
8547             /// Ditto
8548             auto moveBack()
8549             {
8550                 assert(!empty);
8551                 return _source.moveAt(_indices.back);
8552             }
8553         }
8554     }
8555 
8556     mixin ImplementLength!_indices;
8557 
8558     static if (isRandomAccessRange!Indices)
8559     {
8560         /// Ditto
8561         auto ref opIndex(size_t index)
8562         {
8563             return _source[_indices[index]];
8564         }
8565 
8566         static if (hasSlicing!Indices)
8567         {
8568             /// Ditto
8569             typeof(this) opSlice(size_t a, size_t b)
8570             {
8571                 return typeof(this)(_source, _indices[a .. b]);
8572             }
8573         }
8574 
8575 
8576         static if (hasAssignableElements!Source)
8577         {
8578             /// Ditto
8579             auto opIndexAssign(ElementType!Source newVal, size_t index)
8580             {
8581                 return _source[_indices[index]] = newVal;
8582             }
8583         }
8584 
8585 
8586         static if (hasMobileElements!Source)
8587         {
8588             /// Ditto
8589             auto moveAt(size_t index)
8590             {
8591                 return _source.moveAt(_indices[index]);
8592             }
8593         }
8594     }
8595 
8596     // All this stuff is useful if someone wants to index an Indexed
8597     // without adding a layer of indirection.
8598 
8599     /**
8600     Returns the source range.
8601     */
8602     @property Source source()
8603     {
8604         return _source;
8605     }
8606 
8607     /**
8608     Returns the indices range.
8609     */
8610      @property Indices indices()
8611     {
8612         return _indices;
8613     }
8614 
8615     static if (isRandomAccessRange!Indices)
8616     {
8617         /**
8618         Returns the physical index into the source range corresponding to a
8619         given logical index.  This is useful, for example, when indexing
8620         an `Indexed` without adding another layer of indirection.
8621         */
8622         size_t physicalIndex(size_t logicalIndex)
8623         {
8624             return _indices[logicalIndex];
8625         }
8626 
8627         ///
8628         @safe unittest
8629         {
8630             auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8631             assert(ind.physicalIndex(0) == 1);
8632         }
8633     }
8634 
8635 private:
8636     Source _source;
8637     Indices _indices;
8638 
8639 }
8640 
8641 /// Ditto
8642 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
8643 {
8644     return typeof(return)(source, indices);
8645 }
8646 
8647 ///
8648 @safe unittest
8649 {
8650     import std.algorithm.comparison : equal;
8651     auto source = [1, 2, 3, 4, 5];
8652     auto indices = [4, 3, 1, 2, 0, 4];
8653     auto ind = indexed(source, indices);
8654     assert(equal(ind, [5, 4, 2, 3, 1, 5]));
8655     assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
8656 }
8657 
8658 @safe unittest
8659 {
8660     {
8661         auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8662         assert(ind.physicalIndex(0) == 1);
8663     }
8664 
8665     auto source = [1, 2, 3, 4, 5];
8666     auto indices = [4, 3, 1, 2, 0, 4];
8667     auto ind = indexed(source, indices);
8668 
8669     // When elements of indices are duplicated and Source has lvalue elements,
8670     // these are aliased in ind.
8671     ind[0]++;
8672     assert(ind[0] == 6);
8673     assert(ind[5] == 6);
8674 }
8675 
8676 @safe unittest
8677 {
8678     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
8679         propagatesRangeType, RangeType;
8680 
8681     foreach (DummyType; AllDummyRanges)
8682     {
8683         auto d = DummyType.init;
8684         auto r = indexed([1, 2, 3, 4, 5], d);
8685         static assert(propagatesRangeType!(DummyType, typeof(r)));
8686         static assert(propagatesLength!(DummyType, typeof(r)));
8687     }
8688 }
8689 
8690 /**
8691 This range iterates over fixed-sized chunks of size `chunkSize` of a
8692 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8693 `chunkSize` must be greater than zero.
8694 
8695 If `!isInfinite!Source` and `source.walkLength` is not evenly
8696 divisible by `chunkSize`, the back element of this range will contain
8697 fewer than `chunkSize` elements.
8698 
8699 If `Source` is a forward range, the resulting range will be forward ranges as
8700 well. Otherwise, the resulting chunks will be input ranges consuming the same
8701 input: iterating over `front` will shrink the chunk such that subsequent
8702 invocations of `front` will no longer return the full chunk, and calling
8703 `popFront` on the outer range will invalidate any lingering references to
8704 previous values of `front`.
8705 
8706 Params:
8707     source = Range from which the chunks will be selected
8708     chunkSize = Chunk size
8709 
8710 See_Also: $(LREF slide)
8711 
8712 Returns: Range of chunks.
8713 */
8714 struct Chunks(Source)
8715 if (isInputRange!Source)
8716 {
8717     static if (isForwardRange!Source)
8718     {
8719         /// Standard constructor
8720         this(Source source, size_t chunkSize)
8721         {
8722             assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8723             _source = source;
8724             _chunkSize = chunkSize;
8725         }
8726 
8727         /// Input range primitives. Always present.
8728         @property auto front()
8729         {
8730             assert(!empty, "Attempting to fetch the front of an empty Chunks");
8731             return _source.save.take(_chunkSize);
8732         }
8733 
8734         /// Ditto
8735         void popFront()
8736         {
8737             assert(!empty, "Attempting to popFront and empty Chunks");
8738             _source.popFrontN(_chunkSize);
8739         }
8740 
8741         static if (!isInfinite!Source)
8742             /// Ditto
8743             @property bool empty()
8744             {
8745                 return _source.empty;
8746             }
8747         else
8748             // undocumented
8749             enum empty = false;
8750 
8751         /// Forward range primitives. Only present if `Source` is a forward range.
8752         @property typeof(this) save()
8753         {
8754             return typeof(this)(_source.save, _chunkSize);
8755         }
8756 
8757         static if (hasLength!Source)
8758         {
8759             /// Length. Only if `hasLength!Source` is `true`
8760             @property size_t length()
8761             {
8762                 // Note: _source.length + _chunkSize may actually overflow.
8763                 // We cast to ulong to mitigate the problem on x86 machines.
8764                 // For x64 machines, we just suppose we'll never overflow.
8765                 // The "safe" code would require either an extra branch, or a
8766                 //   modulo operation, which is too expensive for such a rare case
8767                 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8768             }
8769             //Note: No point in defining opDollar here without slicing.
8770             //opDollar is defined below in the hasSlicing!Source section
8771         }
8772 
8773         static if (hasSlicing!Source)
8774         {
8775             //Used for various purposes
8776             private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8777 
8778             /**
8779             Indexing and slicing operations. Provided only if
8780             `hasSlicing!Source` is `true`.
8781              */
8782             auto opIndex(size_t index)
8783             {
8784                 immutable start = index * _chunkSize;
8785                 immutable end   = start + _chunkSize;
8786 
8787                 static if (isInfinite!Source)
8788                     return _source[start .. end];
8789                 else
8790                 {
8791                     import std.algorithm.comparison : min;
8792                     immutable len = _source.length;
8793                     assert(start < len, "chunks index out of bounds");
8794                     return _source[start .. min(end, len)];
8795                 }
8796             }
8797 
8798             /// Ditto
8799             static if (hasLength!Source)
8800                 typeof(this) opSlice(size_t lower, size_t upper)
8801                 {
8802                     import std.algorithm.comparison : min;
8803                     assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8804                     immutable len = _source.length;
8805                     return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8806                 }
8807             else static if (hasSliceToEnd)
8808                 //For slicing an infinite chunk, we need to slice the source to the end.
8809                 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8810                 {
8811                     assert(lower <= upper, "chunks slicing index out of bounds");
8812                     return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8813                 }
8814 
8815             static if (isInfinite!Source)
8816             {
8817                 static if (hasSliceToEnd)
8818                 {
8819                     private static struct DollarToken{}
8820                     DollarToken opDollar()
8821                     {
8822                         return DollarToken();
8823                     }
8824                     //Slice to dollar
8825                     typeof(this) opSlice(size_t lower, DollarToken)
8826                     {
8827                         return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8828                     }
8829                 }
8830             }
8831             else
8832             {
8833                 //Dollar token carries a static type, with no extra information.
8834                 //It can lazily transform into _source.length on algorithmic
8835                 //operations such as : chunks[$/2, $-1];
8836                 private static struct DollarToken
8837                 {
8838                     Chunks!Source* mom;
8839                     @property size_t momLength()
8840                     {
8841                         return mom.length;
8842                     }
8843                     alias momLength this;
8844                 }
8845                 DollarToken opDollar()
8846                 {
8847                     return DollarToken(&this);
8848                 }
8849 
8850                 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8851                 //1. Evaluate chunks.length
8852                 //2. Multiply by _chunksSize
8853                 //3. To finally just compare it (with min) to the original length of source (!)
8854                 //These overloads avoid that.
8855                 typeof(this) opSlice(DollarToken, DollarToken)
8856                 {
8857                     static if (hasSliceToEnd)
8858                         return chunks(_source[$ .. $], _chunkSize);
8859                     else
8860                     {
8861                         immutable len = _source.length;
8862                         return chunks(_source[len .. len], _chunkSize);
8863                     }
8864                 }
8865                 typeof(this) opSlice(size_t lower, DollarToken)
8866                 {
8867                     import std.algorithm.comparison : min;
8868                     assert(lower <= length, "chunks slicing index out of bounds");
8869                     static if (hasSliceToEnd)
8870                         return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8871                     else
8872                     {
8873                         immutable len = _source.length;
8874                         return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8875                     }
8876                 }
8877                 typeof(this) opSlice(DollarToken, size_t upper)
8878                 {
8879                     assert(upper == length, "chunks slicing index out of bounds");
8880                     return this[$ .. $];
8881                 }
8882             }
8883         }
8884 
8885         //Bidirectional range primitives
8886         static if (hasSlicing!Source && hasLength!Source)
8887         {
8888             /**
8889             Bidirectional range primitives. Provided only if both
8890             `hasSlicing!Source` and `hasLength!Source` are `true`.
8891              */
8892             @property auto back()
8893             {
8894                 assert(!empty, "back called on empty chunks");
8895                 immutable len = _source.length;
8896                 immutable start = (len - 1) / _chunkSize * _chunkSize;
8897                 return _source[start .. len];
8898             }
8899 
8900             /// Ditto
8901             void popBack()
8902             {
8903                 assert(!empty, "popBack() called on empty chunks");
8904                 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8905                 _source = _source[0 .. end];
8906             }
8907         }
8908 
8909     private:
8910         Source _source;
8911         size_t _chunkSize;
8912     }
8913     else // is input range only
8914     {
8915         import std.typecons : RefCounted;
8916 
8917         static struct Chunk
8918         {
8919             private RefCounted!Impl impl;
8920 
8921             @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8922             @property auto front() { return impl.r.front; }
8923             void popFront()
8924             {
8925                 assert(impl.curSizeLeft > 0 && !impl.r.empty);
8926                 impl.curSizeLeft--;
8927                 impl.r.popFront();
8928             }
8929         }
8930 
8931         static struct Impl
8932         {
8933             private Source r;
8934             private size_t chunkSize;
8935             private size_t curSizeLeft;
8936         }
8937 
8938         private RefCounted!Impl impl;
8939 
8940         private this(Source r, size_t chunkSize)
8941         {
8942             impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8943         }
8944 
8945         @property bool empty() { return impl.chunkSize == 0; }
8946         @property Chunk front() return { return Chunk(impl); }
8947 
8948         void popFront()
8949         {
8950             impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8951             if (!impl.r.empty)
8952                 impl.curSizeLeft = impl.chunkSize;
8953             else
8954                 impl.chunkSize = 0;
8955         }
8956 
8957         static assert(isInputRange!(typeof(this)));
8958     }
8959 }
8960 
8961 /// Ditto
8962 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8963 if (isInputRange!Source)
8964 {
8965     return typeof(return)(source, chunkSize);
8966 }
8967 
8968 ///
8969 @safe unittest
8970 {
8971     import std.algorithm.comparison : equal;
8972     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8973     auto chunks = chunks(source, 4);
8974     assert(chunks[0] == [1, 2, 3, 4]);
8975     assert(chunks[1] == [5, 6, 7, 8]);
8976     assert(chunks[2] == [9, 10]);
8977     assert(chunks.back == chunks[2]);
8978     assert(chunks.front == chunks[0]);
8979     assert(chunks.length == 3);
8980     assert(equal(retro(array(chunks)), array(retro(chunks))));
8981 }
8982 
8983 /// Non-forward input ranges are supported, but with limited semantics.
8984 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8985 {
8986     import std.algorithm.comparison : equal;
8987 
8988     int i;
8989 
8990     // The generator doesn't save state, so it cannot be a forward range.
8991     auto inputRange = generate!(() => ++i).take(10);
8992 
8993     // We can still process it in chunks, but it will be single-pass only.
8994     auto chunked = inputRange.chunks(2);
8995 
8996     assert(chunked.front.equal([1, 2]));
8997     assert(chunked.front.empty); // Iterating the chunk has consumed it
8998     chunked.popFront;
8999     assert(chunked.front.equal([3, 4]));
9000 }
9001 
9002 @system /*@safe*/ unittest
9003 {
9004     import std.algorithm.comparison : equal;
9005     import std.internal.test.dummyrange : ReferenceInputRange;
9006 
9007     auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
9008     auto r = new ReferenceInputRange!int(data).chunks(3);
9009     assert(r.equal!equal([
9010         [ 1, 2, 3 ],
9011         [ 4, 5, 6 ],
9012         [ 7, 8, 9 ],
9013         [ 10 ]
9014     ]));
9015 
9016     auto data2 = [ 1, 2, 3, 4, 5, 6 ];
9017     auto r2 = new ReferenceInputRange!int(data2).chunks(3);
9018     assert(r2.equal!equal([
9019         [ 1, 2, 3 ],
9020         [ 4, 5, 6 ]
9021     ]));
9022 
9023     auto data3 = [ 1, 2, 3, 4, 5 ];
9024     auto r3 = new ReferenceInputRange!int(data3).chunks(2);
9025     assert(r3.front.equal([1, 2]));
9026     r3.popFront();
9027     assert(!r3.empty);
9028     r3.popFront();
9029     assert(r3.front.equal([5]));
9030 }
9031 
9032 @safe unittest
9033 {
9034     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9035     auto chunks = chunks(source, 4);
9036     auto chunks2 = chunks.save;
9037     chunks.popFront();
9038     assert(chunks[0] == [5, 6, 7, 8]);
9039     assert(chunks[1] == [9, 10]);
9040     chunks2.popBack();
9041     assert(chunks2[1] == [5, 6, 7, 8]);
9042     assert(chunks2.length == 2);
9043 
9044     static assert(isRandomAccessRange!(typeof(chunks)));
9045 }
9046 
9047 @safe unittest
9048 {
9049     import std.algorithm.comparison : equal;
9050 
9051     //Extra toying with slicing and indexing.
9052     auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
9053     auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
9054 
9055     assert(chunks1.length == 5);
9056     assert(chunks2.length == 5);
9057     assert(chunks1[4] == [4]);
9058     assert(chunks2[4] == [4, 4]);
9059     assert(chunks1.back == [4]);
9060     assert(chunks2.back == [4, 4]);
9061 
9062     assert(chunks1[0 .. 1].equal([[0, 0]]));
9063     assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
9064     assert(chunks1[4 .. 5].equal([[4]]));
9065     assert(chunks2[4 .. 5].equal([[4, 4]]));
9066 
9067     assert(chunks1[0 .. 0].equal((int[][]).init));
9068     assert(chunks1[5 .. 5].equal((int[][]).init));
9069     assert(chunks2[5 .. 5].equal((int[][]).init));
9070 
9071     //Fun with opDollar
9072     assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
9073     assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
9074     assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
9075     assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
9076     assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
9077     assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
9078 
9079     assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
9080 }
9081 
9082 @safe unittest
9083 {
9084     import std.algorithm.comparison : equal;
9085     import std.algorithm.iteration : filter;
9086 
9087     //ForwardRange
9088     auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
9089     assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
9090 
9091     //InfiniteRange w/o RA
9092     auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
9093     assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
9094 
9095     //InfiniteRange w/ RA and slicing
9096     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9097     auto oddsByPairs = odds.chunks(2);
9098     assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
9099 
9100     //Requires phobos#991 for Sequence to have slice to end
9101     static assert(hasSlicing!(typeof(odds)));
9102     assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
9103     assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
9104 }
9105 
9106 
9107 
9108 /**
9109 This range splits a `source` range into `chunkCount` chunks of
9110 approximately equal length. `Source` must be a forward range with
9111 known length.
9112 
9113 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
9114 The returned range will contain zero or more $(D source.length /
9115 chunkCount + 1) elements followed by $(D source.length / chunkCount)
9116 elements. If $(D source.length < chunkCount), some chunks will be empty.
9117 
9118 `chunkCount` must not be zero, unless `source` is also empty.
9119 */
9120 struct EvenChunks(Source)
9121 if (isForwardRange!Source && hasLength!Source)
9122 {
9123     /// Standard constructor
9124     this(Source source, size_t chunkCount)
9125     {
9126         assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
9127         _source = source;
9128         _chunkCount = chunkCount;
9129     }
9130 
9131     /// Forward range primitives. Always present.
9132     @property auto front()
9133     {
9134         assert(!empty, "Attempting to fetch the front of an empty evenChunks");
9135         return _source.save.take(_chunkPos(1));
9136     }
9137 
9138     /// Ditto
9139     void popFront()
9140     {
9141         assert(!empty, "Attempting to popFront an empty evenChunks");
9142         _source.popFrontN(_chunkPos(1));
9143         _chunkCount--;
9144     }
9145 
9146     /// Ditto
9147     @property bool empty()
9148     {
9149         return _chunkCount == 0;
9150     }
9151 
9152     /// Ditto
9153     @property typeof(this) save()
9154     {
9155         return typeof(this)(_source.save, _chunkCount);
9156     }
9157 
9158     /// Length
9159     @property size_t length() const
9160     {
9161         return _chunkCount;
9162     }
9163     //Note: No point in defining opDollar here without slicing.
9164     //opDollar is defined below in the hasSlicing!Source section
9165 
9166     static if (hasSlicing!Source)
9167     {
9168         /**
9169         Indexing, slicing and bidirectional operations and range primitives.
9170         Provided only if `hasSlicing!Source` is `true`.
9171          */
9172         auto opIndex(size_t index)
9173         {
9174             assert(index < _chunkCount, "evenChunks index out of bounds");
9175             return _source[_chunkPos(index) .. _chunkPos(index+1)];
9176         }
9177 
9178         /// Ditto
9179         typeof(this) opSlice(size_t lower, size_t upper)
9180         {
9181             assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
9182             return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
9183         }
9184 
9185         /// Ditto
9186         @property auto back()
9187         {
9188             assert(!empty, "back called on empty evenChunks");
9189             return _source[_chunkPos(_chunkCount - 1) .. _source.length];
9190         }
9191 
9192         /// Ditto
9193         void popBack()
9194         {
9195             assert(!empty, "popBack() called on empty evenChunks");
9196             _source = _source[0 .. _chunkPos(_chunkCount - 1)];
9197             _chunkCount--;
9198         }
9199     }
9200 
9201 private:
9202     Source _source;
9203     size_t _chunkCount;
9204 
9205     size_t _chunkPos(size_t i)
9206     {
9207         /*
9208             _chunkCount = 5, _source.length = 13:
9209 
9210                chunk0
9211                  |   chunk3
9212                  |     |
9213                  v     v
9214                 +-+-+-+-+-+   ^
9215                 |0|3|.| | |   |
9216                 +-+-+-+-+-+   | div
9217                 |1|4|.| | |   |
9218                 +-+-+-+-+-+   v
9219                 |2|5|.|
9220                 +-+-+-+
9221 
9222                 <----->
9223                   mod
9224 
9225                 <--------->
9226                 _chunkCount
9227 
9228             One column is one chunk.
9229             popFront and popBack pop the left-most
9230             and right-most column, respectively.
9231         */
9232 
9233         auto div = _source.length / _chunkCount;
9234         auto mod = _source.length % _chunkCount;
9235         auto pos = i <= mod
9236             ? i   * (div+1)
9237             : mod * (div+1) + (i-mod) * div
9238         ;
9239         //auto len = i < mod
9240         //    ? div+1
9241         //    : div
9242         //;
9243         return pos;
9244     }
9245 }
9246 
9247 /// Ditto
9248 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
9249 if (isForwardRange!Source && hasLength!Source)
9250 {
9251     return typeof(return)(source, chunkCount);
9252 }
9253 
9254 ///
9255 @safe unittest
9256 {
9257     import std.algorithm.comparison : equal;
9258     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9259     auto chunks = evenChunks(source, 3);
9260     assert(chunks[0] == [1, 2, 3, 4]);
9261     assert(chunks[1] == [5, 6, 7]);
9262     assert(chunks[2] == [8, 9, 10]);
9263 }
9264 
9265 @safe unittest
9266 {
9267     import std.algorithm.comparison : equal;
9268 
9269     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9270     auto chunks = evenChunks(source, 3);
9271     assert(chunks.back == chunks[2]);
9272     assert(chunks.front == chunks[0]);
9273     assert(chunks.length == 3);
9274     assert(equal(retro(array(chunks)), array(retro(chunks))));
9275 
9276     auto chunks2 = chunks.save;
9277     chunks.popFront();
9278     assert(chunks[0] == [5, 6, 7]);
9279     assert(chunks[1] == [8, 9, 10]);
9280     chunks2.popBack();
9281     assert(chunks2[1] == [5, 6, 7]);
9282     assert(chunks2.length == 2);
9283 
9284     static assert(isRandomAccessRange!(typeof(chunks)));
9285 }
9286 
9287 @safe unittest
9288 {
9289     import std.algorithm.comparison : equal;
9290 
9291     int[] source = [];
9292     auto chunks = source.evenChunks(0);
9293     assert(chunks.length == 0);
9294     chunks = source.evenChunks(3);
9295     assert(equal(chunks, [[], [], []]));
9296     chunks = [1, 2, 3].evenChunks(5);
9297     assert(equal(chunks, [[1], [2], [3], [], []]));
9298 }
9299 
9300 /**
9301 A fixed-sized sliding window iteration
9302 of size `windowSize` over a `source` range by a custom `stepSize`.
9303 
9304 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
9305 and the `windowSize` must be greater than zero.
9306 
9307 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
9308 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
9309 
9310 Params:
9311     f = Whether the last element has fewer elements than `windowSize`
9312         it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
9313     source = Range from which the slide will be selected
9314     windowSize = Sliding window size
9315     stepSize = Steps between the windows (by default 1)
9316 
9317 Returns: Range of all sliding windows with propagated bi-directionality,
9318          forwarding, random access, and slicing.
9319 
9320 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
9321       is only available when $(REF hasSlicing, std,range,primitives)
9322       and $(REF hasLength, std,range,primitives) are true.
9323 
9324 See_Also: $(LREF chunks)
9325 */
9326 auto slide(Flag!"withPartial" f = Yes.withPartial,
9327             Source)(Source source, size_t windowSize, size_t stepSize = 1)
9328 if (isForwardRange!Source)
9329 {
9330     return Slides!(f, Source)(source, windowSize, stepSize);
9331 }
9332 
9333 /// Iterate over ranges with windows
9334 @safe pure nothrow unittest
9335 {
9336     import std.algorithm.comparison : equal;
9337 
9338     assert([0, 1, 2, 3].slide(2).equal!equal(
9339         [[0, 1], [1, 2], [2, 3]]
9340     ));
9341 
9342     assert(5.iota.slide(3).equal!equal(
9343         [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
9344     ));
9345 }
9346 
9347 /// set a custom stepsize (default 1)
9348 @safe pure nothrow unittest
9349 {
9350     import std.algorithm.comparison : equal;
9351 
9352     assert(6.iota.slide(1, 2).equal!equal(
9353         [[0], [2], [4]]
9354     ));
9355 
9356     assert(6.iota.slide(2, 4).equal!equal(
9357         [[0, 1], [4, 5]]
9358     ));
9359 
9360     assert(iota(7).slide(2, 2).equal!equal(
9361         [[0, 1], [2, 3], [4, 5], [6]]
9362     ));
9363 
9364     assert(iota(12).slide(2, 4).equal!equal(
9365         [[0, 1], [4, 5], [8, 9]]
9366     ));
9367 }
9368 
9369 /// Allow the last slide to have fewer elements than windowSize
9370 @safe pure nothrow unittest
9371 {
9372     import std.algorithm.comparison : equal;
9373 
9374     assert(3.iota.slide!(No.withPartial)(4).empty);
9375     assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
9376         [[0, 1, 2]]
9377     ));
9378 }
9379 
9380 /// Count all the possible substrings of length 2
9381 @safe pure nothrow unittest
9382 {
9383     import std.algorithm.iteration : each;
9384 
9385     int[dstring] d;
9386     "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
9387     assert(d == ["AG"d: 2, "GA"d: 2]);
9388 }
9389 
9390 /// withPartial only has an effect if last element in the range doesn't have the full size
9391 @safe pure nothrow unittest
9392 {
9393     import std.algorithm.comparison : equal;
9394 
9395     assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
9396     assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
9397     assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9398 
9399     assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9400     assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9401     assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9402 }
9403 
9404 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
9405 if (isForwardRange!Source)
9406 {
9407 private:
9408     Source source;
9409     size_t windowSize;
9410     size_t stepSize;
9411 
9412     static if (hasLength!Source)
9413     {
9414         enum needsEndTracker = false;
9415     }
9416     else
9417     {
9418         // If there's no information about the length, track needs to be kept manually
9419         Source nextSource;
9420         enum needsEndTracker = true;
9421     }
9422 
9423     bool _empty;
9424 
9425     static if (hasSlicing!Source)
9426         enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
9427 
9428     static if (withPartial)
9429         bool hasShownPartialBefore;
9430 
9431 public:
9432     /// Standard constructor
9433     this(Source source, size_t windowSize, size_t stepSize)
9434     {
9435         assert(windowSize > 0, "windowSize must be greater than zero");
9436         assert(stepSize > 0, "stepSize must be greater than zero");
9437         this.source = source;
9438         this.windowSize = windowSize;
9439         this.stepSize = stepSize;
9440 
9441         static if (needsEndTracker)
9442         {
9443             // `nextSource` is used to "look one step into the future" and check for the end
9444             // this means `nextSource` is advanced by `stepSize` on every `popFront`
9445             nextSource = source.save;
9446             auto poppedElems = nextSource.popFrontN(windowSize);
9447         }
9448 
9449         if (source.empty)
9450         {
9451             _empty = true;
9452             return;
9453         }
9454 
9455         static if (withPartial)
9456         {
9457             static if (needsEndTracker)
9458             {
9459                 if (nextSource.empty)
9460                     hasShownPartialBefore = true;
9461             }
9462             else
9463             {
9464                 if (source.length <= windowSize)
9465                     hasShownPartialBefore = true;
9466             }
9467         }
9468         else
9469         {
9470             // empty source range is needed, s.t. length, slicing etc. works properly
9471             static if (needsEndTracker)
9472             {
9473                 if (poppedElems < windowSize)
9474                      _empty = true;
9475             }
9476             else
9477             {
9478                 if (source.length < windowSize)
9479                      _empty = true;
9480             }
9481         }
9482     }
9483 
9484     /// Forward range primitives. Always present.
9485     @property auto front()
9486     {
9487         assert(!empty, "Attempting to access front on an empty slide.");
9488         static if (hasSlicing!Source && hasLength!Source)
9489         {
9490             static if (withPartial)
9491             {
9492                 import std.algorithm.comparison : min;
9493                 return source[0 .. min(windowSize, source.length)];
9494             }
9495             else
9496             {
9497                 assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
9498                 return source[0 .. windowSize];
9499             }
9500         }
9501         else
9502         {
9503             static if (withPartial)
9504                 return source.save.take(windowSize);
9505             else
9506                 return source.save.takeExactly(windowSize);
9507         }
9508     }
9509 
9510     /// Ditto
9511     void popFront()
9512     {
9513         assert(!empty, "Attempting to call popFront() on an empty slide.");
9514         source.popFrontN(stepSize);
9515 
9516         if (source.empty)
9517         {
9518             _empty = true;
9519             return;
9520         }
9521 
9522         static if (withPartial)
9523         {
9524             if (hasShownPartialBefore)
9525                 _empty = true;
9526         }
9527 
9528         static if (needsEndTracker)
9529         {
9530             // Check the upcoming slide
9531             auto poppedElements = nextSource.popFrontN(stepSize);
9532             static if (withPartial)
9533             {
9534                 if (poppedElements < stepSize || nextSource.empty)
9535                     hasShownPartialBefore = true;
9536             }
9537             else
9538             {
9539                 if (poppedElements < stepSize)
9540                     _empty = true;
9541             }
9542         }
9543         else
9544         {
9545             static if (withPartial)
9546             {
9547                 if (source.length <= windowSize)
9548                     hasShownPartialBefore = true;
9549             }
9550             else
9551             {
9552                 if (source.length < windowSize)
9553                     _empty = true;
9554             }
9555         }
9556     }
9557 
9558     static if (!isInfinite!Source)
9559     {
9560         /// Ditto
9561         @property bool empty() const
9562         {
9563             return _empty;
9564         }
9565     }
9566     else
9567     {
9568         // undocumented
9569         enum empty = false;
9570     }
9571 
9572     /// Ditto
9573     @property typeof(this) save()
9574     {
9575         return typeof(this)(source.save, windowSize, stepSize);
9576     }
9577 
9578     static if (hasLength!Source)
9579     {
9580         // gaps between the last element and the end of the range
9581         private size_t gap()
9582         {
9583             /*
9584             * Note:
9585             * - In the following `end` is the exclusive end as used in opSlice
9586             * - For the trivial case with `stepSize = 1`  `end` is at `len`:
9587             *
9588             *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]]    (end = 4)
9589             *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]      (end = 4)
9590             *
9591             * - For the non-trivial cases, we need to calculate the gap
9592             *   between `len` and `end` - this is the number of missing elements
9593             *   from the input range:
9594             *
9595             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
9596             *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
9597             *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
9598             *
9599             *   As it can be seen `gap` can be at most `stepSize - 1`
9600             *   More generally the elements of the sliding window with
9601             *   `w = windowSize` and `s = stepSize` are:
9602             *
9603             *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
9604             *
9605             *  We can thus calculate the gap between the `end` and `len` as:
9606             *
9607             *     gap = len - (n * s + w) = len - w - (n * s)
9608             *
9609             *  As we aren't interested in exact value of `n`, but the best
9610             *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
9611             *
9612             *     gap = len - w - (s - s ... - s) = (len - w) % s
9613             *
9614             *  So for example:
9615             *
9616             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
9617             *      gap: (7 - 2) % 3 = 5 % 3 = 2
9618             *      end: 7 - 2 = 5
9619             *
9620             *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
9621             *      gap: (7 - 4) % 2 = 3 % 2 = 1
9622             *      end: 7 - 1 = 6
9623             */
9624             return (source.length - windowSize)  % stepSize;
9625         }
9626 
9627         private size_t numberOfFullFrames()
9628         {
9629             /**
9630             5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9631             7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (3)
9632             7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (2)
9633             6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5]         (2)
9634             7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (2)
9635 
9636             As the last window is only added iff its complete,
9637             we don't count the last window except if it's full due to integer rounding.
9638             */
9639             return 1 + (source.length - windowSize) / stepSize;
9640         }
9641 
9642         // Whether the last slide frame size is less than windowSize
9643         private bool hasPartialElements()
9644         {
9645             static if (withPartial)
9646                 return gap != 0 && source.length > numberOfFullFrames * stepSize;
9647             else
9648                 return 0;
9649         }
9650 
9651         /// Length. Only if `hasLength!Source` is `true`
9652         @property size_t length()
9653         {
9654             if (source.length < windowSize)
9655             {
9656                 static if (withPartial)
9657                     return source.length > 0;
9658                 else
9659                     return 0;
9660             }
9661             else
9662             {
9663                 /***
9664                   We bump the pointer by stepSize for every element.
9665                   If withPartial, we don't count the last element if its size
9666                   isn't windowSize
9667 
9668                   At most:
9669                       [p, p + stepSize, ..., p + stepSize * n]
9670 
9671                 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9672                 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (4)
9673                 7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (3)
9674                 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6]      (3)
9675                 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (3)
9676                 */
9677                 return numberOfFullFrames + hasPartialElements;
9678             }
9679         }
9680     }
9681 
9682     static if (hasSlicing!Source)
9683     {
9684         /**
9685         Indexing and slicing operations. Provided only if
9686         `hasSlicing!Source` is `true`.
9687          */
9688         auto opIndex(size_t index)
9689         {
9690             immutable start = index * stepSize;
9691 
9692             static if (isInfinite!Source)
9693             {
9694                 immutable end = start + windowSize;
9695             }
9696             else
9697             {
9698                 import std.algorithm.comparison : min;
9699 
9700                 immutable len = source.length;
9701                 assert(start < len, "slide index out of bounds");
9702                 immutable end = min(start + windowSize, len);
9703             }
9704 
9705             return source[start .. end];
9706         }
9707 
9708         static if (!isInfinite!Source)
9709         {
9710             /// ditto
9711             typeof(this) opSlice(size_t lower, size_t upper)
9712             {
9713                 import std.algorithm.comparison : min;
9714 
9715                 assert(upper <= length, "slide slicing index out of bounds");
9716                 assert(lower <= upper, "slide slicing index out of bounds");
9717 
9718                 lower *= stepSize;
9719                 upper *= stepSize;
9720 
9721                 immutable len = source.length;
9722 
9723                 static if (withPartial)
9724                 {
9725                     import std.algorithm.comparison : max;
9726 
9727                     if (lower == upper)
9728                         return this[$ .. $];
9729 
9730                     /*
9731                     A) If `stepSize` >= `windowSize` => `rightPos = upper`
9732 
9733                        [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9734                          rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9735                          6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9736 
9737                     B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9738 
9739                        [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9740                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9741                          1.iota.slide(2) = [[0]]
9742 
9743                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9744                          1.iota.slide(2) = [[0, 1]]
9745 
9746                        More complex:
9747 
9748                        20.iota.slide(7, 6)[0 .. 2]
9749                          rightPos: (upper=2) * (stepSize=6) = 12.iota
9750                          12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9751 
9752                        Now we add up for the difference between `windowSize` and `stepSize`:
9753 
9754                          rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9755                          13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9756                     */
9757                     immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9758                 }
9759                 else
9760                 {
9761                     /*
9762                     After we have normalized `lower` and `upper` by `stepSize`,
9763                     we only need to look at the case of `stepSize=1`.
9764                     As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9765                     Notice that starting from `upper`,
9766                     we only need to move for `windowSize - 1` to the right:
9767 
9768                       - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9769                         rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9770 
9771                       - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9772                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9773 
9774                       - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9775                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9776                     */
9777                     immutable rightPos = min(upper + windowSize - 1, len);
9778                 }
9779 
9780                 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9781             }
9782         }
9783         else static if (hasSliceToEnd)
9784         {
9785             // For slicing an infinite chunk, we need to slice the source to the infinite end.
9786             auto opSlice(size_t lower, size_t upper)
9787             {
9788                 assert(lower <= upper, "slide slicing index out of bounds");
9789                 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9790                                     .takeExactly(upper - lower);
9791             }
9792         }
9793 
9794         static if (isInfinite!Source)
9795         {
9796             static if (hasSliceToEnd)
9797             {
9798                 private static struct DollarToken{}
9799                 DollarToken opDollar()
9800                 {
9801                     return DollarToken();
9802                 }
9803                 //Slice to dollar
9804                 typeof(this) opSlice(size_t lower, DollarToken)
9805                 {
9806                     return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9807                 }
9808             }
9809         }
9810         else
9811         {
9812             // Dollar token carries a static type, with no extra information.
9813             // It can lazily transform into source.length on algorithmic
9814             // operations such as : slide[$/2, $-1];
9815             private static struct DollarToken
9816             {
9817                 private size_t _length;
9818                 alias _length this;
9819             }
9820 
9821             DollarToken opDollar()
9822             {
9823                 return DollarToken(this.length);
9824             }
9825 
9826             // Optimized slice overloads optimized for using dollar.
9827             typeof(this) opSlice(DollarToken, DollarToken)
9828             {
9829                 static if (hasSliceToEnd)
9830                 {
9831                     return typeof(this)(source[$ .. $], windowSize, stepSize);
9832                 }
9833                 else
9834                 {
9835                     immutable len = source.length;
9836                     return typeof(this)(source[len .. len], windowSize, stepSize);
9837                 }
9838             }
9839 
9840             // Optimized slice overloads optimized for using dollar.
9841             typeof(this) opSlice(size_t lower, DollarToken)
9842             {
9843                 import std.algorithm.comparison : min;
9844                 assert(lower <= length, "slide slicing index out of bounds");
9845                 lower *= stepSize;
9846                 static if (hasSliceToEnd)
9847                 {
9848                     return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9849                 }
9850                 else
9851                 {
9852                     immutable len = source.length;
9853                     return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9854                 }
9855             }
9856 
9857             // Optimized slice overloads optimized for using dollar.
9858             typeof(this) opSlice(DollarToken, size_t upper)
9859             {
9860                 assert(upper == length, "slide slicing index out of bounds");
9861                 return this[$ .. $];
9862             }
9863         }
9864 
9865         // Bidirectional range primitives
9866         static if (!isInfinite!Source)
9867         {
9868             /**
9869             Bidirectional range primitives. Provided only if both
9870             `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9871              */
9872             @property auto back()
9873             {
9874                 import std.algorithm.comparison : max;
9875 
9876                 assert(!empty, "Attempting to access front on an empty slide");
9877 
9878                 immutable len = source.length;
9879 
9880                 static if (withPartial)
9881                 {
9882                     if (source.length <= windowSize)
9883                         return source[0 .. source.length];
9884 
9885                     if (hasPartialElements)
9886                         return source[numberOfFullFrames * stepSize .. len];
9887                 }
9888 
9889                 // check for underflow
9890                 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9891                 return source[start .. len - gap];
9892             }
9893 
9894             /// Ditto
9895             void popBack()
9896             {
9897                 assert(!empty, "Attempting to call popBack() on an empty slide");
9898 
9899                 // Move by stepSize
9900                 immutable end = source.length > stepSize ? source.length - stepSize : 0;
9901 
9902                 static if (withPartial)
9903                 {
9904                     if (hasShownPartialBefore || source.empty)
9905                     {
9906                         _empty = true;
9907                         return;
9908                     }
9909 
9910                     // pop by stepSize, except for the partial frame at the end
9911                     if (hasPartialElements)
9912                         source = source[0 .. source.length - gap];
9913                     else
9914                         source = source[0 .. end];
9915                 }
9916                 else
9917                 {
9918                     source = source[0 .. end];
9919                 }
9920 
9921                 if (source.length < windowSize)
9922                     _empty = true;
9923             }
9924         }
9925     }
9926 }
9927 
9928 // test @nogc
9929 @safe pure nothrow @nogc unittest
9930 {
9931     import std.algorithm.comparison : equal;
9932 
9933     static immutable res1 = [[0], [1], [2], [3]];
9934     assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9935 
9936     static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9937     assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9938 }
9939 
9940 // test different window sizes
9941 @safe pure nothrow unittest
9942 {
9943     import std.array : array;
9944     import std.algorithm.comparison : equal;
9945 
9946     assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9947     assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9948     assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9949     assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9950     assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9951     assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9952 
9953     assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9954     assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9955     assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9956     assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9957     assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9958     assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9959     assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9960 }
9961 
9962 // test combinations
9963 @safe pure nothrow unittest
9964 {
9965     import std.algorithm.comparison : equal;
9966     import std.typecons : tuple;
9967 
9968     alias t = tuple;
9969     auto list = [
9970         t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9971         t(t(1, 2), [[0], [2], [4]]),
9972         t(t(1, 3), [[0], [3]]),
9973         t(t(1, 4), [[0], [4]]),
9974         t(t(1, 5), [[0], [5]]),
9975         t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9976         t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9977         t(t(2, 3), [[0, 1], [3, 4]]),
9978         t(t(2, 4), [[0, 1], [4, 5]]),
9979         t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9980         t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9981         t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9982         t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9983         t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9984     ];
9985 
9986     static foreach (Partial; [Yes.withPartial, No.withPartial])
9987         foreach (e; list)
9988             assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9989 
9990     auto listSpecial = [
9991         t(t(2, 5), [[0, 1], [5]]),
9992         t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9993         t(t(3, 4), [[0, 1, 2], [4, 5]]),
9994         t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9995         t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9996         t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9997     ];
9998     foreach (e; listSpecial)
9999     {
10000         assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
10001         assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
10002     }
10003 }
10004 
10005 // test emptiness and copyability
10006 @safe pure nothrow unittest
10007 {
10008     import std.algorithm.comparison : equal;
10009     import std.algorithm.iteration : map;
10010 
10011     // check with empty input
10012     int[] d;
10013     assert(d.slide!(Yes.withPartial)(2).empty);
10014     assert(d.slide!(Yes.withPartial)(2, 2).empty);
10015 
10016     // is copyable?
10017     auto e = iota(5).slide!(Yes.withPartial)(2);
10018     e.popFront;
10019     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
10020     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
10021     assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
10022 }
10023 
10024 // test with strings
10025 @safe pure nothrow unittest
10026 {
10027     import std.algorithm.iteration : each;
10028 
10029     int[dstring] f;
10030     "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
10031     assert(f == ["AGA"d: 2, "GAG"d: 1]);
10032 
10033     int[dstring] g;
10034     "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
10035     assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
10036     g = null;
10037     "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
10038     assert(g == ["ABC"d:1, "DEF"d:1]);
10039 }
10040 
10041 // test with utf8 strings
10042 @safe unittest
10043 {
10044     import std.stdio;
10045     import std.algorithm.comparison : equal;
10046 
10047     assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."]));
10048     assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"]));
10049 
10050     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
10051     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
10052     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]);
10053     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]);
10054 }
10055 
10056 // test length
10057 @safe pure nothrow unittest
10058 {
10059     // Slides with fewer elements are empty or 1 for Yes.withPartial
10060     static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
10061     {{
10062         assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
10063         assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
10064         assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
10065     }}
10066 
10067     static immutable list = [
10068     //  iota   slide    expected
10069         [4,    2, 1,     3, 3],
10070         [5,    3, 1,     3, 3],
10071         [7,    2, 2,     4, 3],
10072         [12,   2, 4,     3, 3],
10073         [6,    1, 2,     3, 3],
10074         [6,    2, 4,     2, 2],
10075         [3,    2, 4,     1, 1],
10076         [5,    2, 1,     4, 4],
10077         [7,    2, 2,     4, 3],
10078         [7,    2, 3,     3, 2],
10079         [7,    3, 2,     3, 3],
10080         [7,    3, 3,     3, 2],
10081     ];
10082     foreach (e; list)
10083     {
10084         assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
10085         assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
10086     }
10087 }
10088 
10089 // test index and slicing
10090 @safe pure nothrow unittest
10091 {
10092     import std.algorithm.comparison : equal;
10093     import std.array : array;
10094 
10095     static foreach (Partial; [Yes.withPartial, No.withPartial])
10096     {
10097         foreach (s; [5, 7, 10, 15, 20])
10098         foreach (windowSize; 1 .. 10)
10099         foreach (stepSize; 1 .. 10)
10100         {
10101             auto r = s.iota.slide!Partial(windowSize, stepSize);
10102             auto arr = r.array;
10103             assert(r.length == arr.length);
10104 
10105             // test indexing
10106             foreach (i; 0 .. arr.length)
10107                 assert(r[i] == arr[i]);
10108 
10109             // test slicing
10110             foreach (i; 0 .. arr.length)
10111             {
10112                 foreach (j; i .. arr.length)
10113                     assert(r[i .. j].equal(arr[i .. j]));
10114 
10115                 assert(r[i .. $].equal(arr[i .. $]));
10116             }
10117 
10118             // test opDollar slicing
10119             assert(r[$/2 .. $].equal(arr[$/2 .. $]));
10120             assert(r[$ .. $].empty);
10121             if (arr.empty)
10122             {
10123                 assert(r[$ .. 0].empty);
10124                 assert(r[$/2 .. $].empty);
10125 
10126             }
10127         }
10128     }
10129 }
10130 
10131 // test with infinite ranges
10132 @safe pure nothrow unittest
10133 {
10134     import std.algorithm.comparison : equal;
10135 
10136     static foreach (Partial; [Yes.withPartial, No.withPartial])
10137     {{
10138         // InfiniteRange without RandomAccess
10139         auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
10140         assert(fibs.slide!Partial(2).take(2).equal!equal([[1,  1], [1,  2]]));
10141         assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
10142 
10143         // InfiniteRange with RandomAccess and slicing
10144         auto odds = sequence!("a[0] + n * a[1]")(1, 2);
10145         auto oddsByPairs = odds.slide!Partial(2);
10146         assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
10147         assert(oddsByPairs[1].equal([3, 5]));
10148         assert(oddsByPairs[4].equal([9, 11]));
10149 
10150         static assert(hasSlicing!(typeof(odds)));
10151         assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
10152         assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
10153 
10154         auto oddsWithGaps = odds.slide!Partial(2, 4);
10155         assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
10156         assert(oddsWithGaps[2].equal([17, 19]));
10157         assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
10158         assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
10159     }}
10160 }
10161 
10162 // test reverse
10163 @safe pure nothrow unittest
10164 {
10165     import std.algorithm.comparison : equal;
10166 
10167     static foreach (Partial; [Yes.withPartial, No.withPartial])
10168     {{
10169         foreach (windowSize; 1 .. 15)
10170         foreach (stepSize; 1 .. 15)
10171         {
10172             auto r = 20.iota.slide!Partial(windowSize, stepSize);
10173             auto rArr = r.array.retro;
10174             auto rRetro = r.retro;
10175 
10176             assert(rRetro.length == rArr.length);
10177             assert(rRetro.equal(rArr));
10178             assert(rRetro.array.retro.equal(r));
10179         }
10180     }}
10181 }
10182 
10183 // test with dummy ranges
10184 @safe pure nothrow unittest
10185 {
10186     import std.algorithm.comparison : equal;
10187     import std.internal.test.dummyrange : AllDummyRanges;
10188     import std.meta : Filter;
10189 
10190     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10191     {{
10192         Range r;
10193 
10194         static foreach (Partial; [Yes.withPartial, No.withPartial])
10195         {
10196             assert(r.slide!Partial(1).equal!equal(
10197                 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
10198             ));
10199             assert(r.slide!Partial(2).equal!equal(
10200                 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
10201             ));
10202             assert(r.slide!Partial(3).equal!equal(
10203                 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
10204                 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
10205             ));
10206             assert(r.slide!Partial(6).equal!equal(
10207                 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
10208                 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
10209             ));
10210         }
10211 
10212         // special cases
10213         assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
10214         assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
10215         assert(r.slide!(No.withPartial)(15).empty);
10216         assert(r.slide!(No.withPartial)(15).walkLength == 0);
10217     }}
10218 }
10219 
10220 // test with dummy ranges
10221 @safe pure nothrow unittest
10222 {
10223     import std.algorithm.comparison : equal;
10224     import std.internal.test.dummyrange : AllDummyRanges;
10225     import std.meta : Filter;
10226     import std.typecons : tuple;
10227 
10228     alias t = tuple;
10229     static immutable list = [
10230     // iota   slide    expected
10231         t(6,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
10232         t(6,  t(4, 6), [[1, 2, 3, 4]]),
10233         t(6,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
10234         t(7,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
10235         t(7,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
10236         t(8,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
10237         t(8,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]),
10238         t(8,  t(3, 4), [[1, 2, 3], [5, 6, 7]]),
10239         t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
10240     ];
10241 
10242     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10243     static foreach (Partial; [Yes.withPartial, No.withPartial])
10244     foreach (e; list)
10245         assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
10246 
10247     static immutable listSpecial = [
10248     // iota   slide    expected
10249         t(6,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
10250         t(7,  t(4, 5), [[1, 2, 3, 4], [6, 7]]),
10251         t(7,  t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
10252         t(7,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
10253         t(8,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
10254         t(8,  t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
10255         t(8,  t(3, 6), [[1, 2, 3], [7, 8]]),
10256         t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
10257         t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
10258     ];
10259     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10260     static foreach (Partial; [Yes.withPartial, No.withPartial])
10261     foreach (e; listSpecial)
10262     {
10263         Range r;
10264         assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
10265         assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
10266     }
10267 }
10268 
10269 // test reverse with dummy ranges
10270 @safe pure nothrow unittest
10271 {
10272     import std.algorithm.comparison : equal;
10273     import std.internal.test.dummyrange : AllDummyRanges;
10274     import std.meta : Filter, templateAnd;
10275     import std.typecons : tuple;
10276     alias t = tuple;
10277 
10278     static immutable list = [
10279     //   slide   expected
10280         t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
10281         t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
10282         t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
10283                  [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
10284         t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
10285         t(2, 4, [[9, 10], [5, 6], [1, 2]]),
10286     ];
10287 
10288     static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
10289     {{
10290         Range r;
10291         static foreach (Partial; [Yes.withPartial, No.withPartial])
10292         {
10293             foreach (e; list)
10294                 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
10295 
10296             // front = back
10297             foreach (windowSize; 1 .. 10)
10298             foreach (stepSize; 1 .. 10)
10299             {
10300                 auto slider = r.slide!Partial(windowSize, stepSize);
10301                 auto sliderRetro = slider.retro.array;
10302                 assert(slider.length == sliderRetro.length);
10303                 assert(sliderRetro.retro.equal!equal(slider));
10304             }
10305         }
10306 
10307         // special cases
10308         assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
10309         assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
10310     }}
10311 }
10312 
10313 // test different sliceable ranges
10314 @safe pure nothrow unittest
10315 {
10316     import std.algorithm.comparison : equal;
10317     import std.internal.test.dummyrange : AllDummyRanges;
10318     import std.meta : AliasSeq;
10319 
10320     struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
10321                                  Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
10322     {
10323         Range arr = 10.iota.array; // similar to DummyRange
10324         @property auto save() { return typeof(this)(arr); }
10325         @property auto front() { return arr[0]; }
10326         void popFront() { arr.popFront(); }
10327         auto opSlice(size_t i, size_t j)
10328         {
10329             // subslices can't be infinite
10330             return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
10331         }
10332 
10333         static if (withInfiniteness)
10334         {
10335             enum empty = false;
10336         }
10337         else
10338         {
10339             @property bool empty() { return arr.empty; }
10340             @property auto length() { return arr.length; }
10341         }
10342 
10343         static if (withOpDollar)
10344         {
10345             static if (withInfiniteness)
10346             {
10347                 struct Dollar {}
10348                 Dollar opDollar() const { return Dollar.init; }
10349 
10350                 // Slice to dollar
10351                 typeof(this) opSlice(size_t lower, Dollar)
10352                 {
10353                     return typeof(this)(arr[lower .. $]);
10354                 }
10355 
10356             }
10357             else
10358             {
10359                 alias opDollar = length;
10360             }
10361         }
10362     }
10363 
10364     import std.meta : Filter,  templateNot;
10365     alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
10366 
10367     static foreach (Partial; [Yes.withPartial, No.withPartial])
10368     {{
10369         static foreach (Range; SliceableDummyRanges)
10370         {{
10371             Range r;
10372             r.reinit;
10373             r.arr[] -= 1; // use a 0-based array (for clarity)
10374 
10375             assert(r.slide!Partial(2)[0].equal([0, 1]));
10376             assert(r.slide!Partial(2)[1].equal([1, 2]));
10377 
10378             // saveable
10379             auto s = r.slide!Partial(2);
10380             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10381             s.save.popFront;
10382             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10383 
10384             assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
10385         }}
10386 
10387         static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
10388         {{
10389             Range r;
10390             r.reinit;
10391             r.arr[] -= 1; // use a 0-based array (for clarity)
10392 
10393             assert(r.slide!(No.withPartial)(6).equal!equal(
10394                 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
10395                 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
10396             ));
10397             assert(r.slide!(No.withPartial)(16).empty);
10398 
10399             assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
10400             assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
10401             assert(r.slide!Partial(2)[$ .. $].empty);
10402 
10403             assert(r.slide!Partial(3).retro.equal!equal(
10404                 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
10405             ));
10406         }}
10407 
10408         alias T = int[];
10409 
10410         // separate checks for infinity
10411         auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
10412         assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
10413         assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
10414 
10415         auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
10416         assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
10417         assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
10418         assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
10419     }}
10420 }
10421 
10422 // https://issues.dlang.org/show_bug.cgi?id=19082
10423 @safe unittest
10424 {
10425     import std.algorithm.comparison : equal;
10426     import std.algorithm.iteration : map;
10427     assert([1].map!(x => x).slide(2).equal!equal([[1]]));
10428 }
10429 
10430 // https://issues.dlang.org/show_bug.cgi?id=19642
10431 @safe unittest
10432 {
10433     import std.algorithm.comparison : equal;
10434     import std.algorithm.iteration : splitter;
10435 
10436     assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]]));
10437 }
10438 
10439 // https://issues.dlang.org/show_bug.cgi?id=23976
10440 @safe unittest
10441 {
10442     import std.algorithm.comparison : equal;
10443     import std.algorithm.iteration : splitter;
10444 
10445     assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]]));
10446 }
10447 
10448 private struct OnlyResult(Values...)
10449 if (Values.length > 1)
10450 {
10451     import std.meta : ApplyRight;
10452     import std.traits : isAssignable;
10453 
10454     private enum arity = Values.length;
10455 
10456     private alias UnqualValues = staticMap!(Unqual, Values);
10457 
10458     private enum canAssignElements = allSatisfy!(
10459         ApplyRight!(isAssignable, CommonType!Values),
10460         Values
10461     );
10462 
10463     private this(return scope ref Values values)
10464     {
10465         ref @trusted unqual(T)(ref T x){return cast() x;}
10466 
10467         // TODO: this calls any possible copy constructors without qualifiers.
10468         // Find a way to initialize values using qualified copy constructors.
10469         static foreach (i; 0 .. Values.length)
10470         {
10471             this.values[i] = unqual(values[i]);
10472         }
10473         this.backIndex = arity;
10474     }
10475 
10476     bool empty() @property
10477     {
10478         return frontIndex >= backIndex;
10479     }
10480 
10481     CommonType!Values front() @property
10482     {
10483         assert(!empty, "Attempting to fetch the front of an empty Only range");
10484         return this[0];
10485     }
10486 
10487     static if (canAssignElements)
10488     {
10489         void front(CommonType!Values value) @property
10490         {
10491             assert(!empty, "Attempting to assign the front of an empty Only range");
10492             this[0] = value;
10493         }
10494     }
10495 
10496     void popFront()
10497     {
10498         assert(!empty, "Attempting to popFront an empty Only range");
10499         ++frontIndex;
10500     }
10501 
10502     CommonType!Values back() @property
10503     {
10504         assert(!empty, "Attempting to fetch the back of an empty Only range");
10505         return this[$ - 1];
10506     }
10507 
10508     static if (canAssignElements)
10509     {
10510         void back(CommonType!Values value) @property
10511         {
10512             assert(!empty, "Attempting to assign the back of an empty Only range");
10513             this[$ - 1] = value;
10514         }
10515     }
10516 
10517     void popBack()
10518     {
10519         assert(!empty, "Attempting to popBack an empty Only range");
10520         --backIndex;
10521     }
10522 
10523     OnlyResult save() @property
10524     {
10525         return this;
10526     }
10527 
10528     size_t length() const @property
10529     {
10530         return backIndex - frontIndex;
10531     }
10532 
10533     alias opDollar = length;
10534 
10535     @trusted CommonType!Values opIndex(size_t idx)
10536     {
10537         // when i + idx points to elements popped
10538         // with popBack
10539         assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
10540         final switch (frontIndex + idx)
10541             static foreach (i, T; Values)
10542             case i:
10543                 return cast(T) values[i];
10544     }
10545 
10546     static if (canAssignElements)
10547     {
10548         void opIndexAssign(CommonType!Values value, size_t idx)
10549         {
10550             assert(idx < length, "Attempting to assign to an out of bounds index of an Only range");
10551             final switch (frontIndex + idx)
10552                 static foreach (i; 0 .. Values.length)
10553                 case i:
10554                     values[i] = value;
10555         }
10556     }
10557 
10558     OnlyResult opSlice()
10559     {
10560         return this;
10561     }
10562 
10563     OnlyResult opSlice(size_t from, size_t to)
10564     {
10565         OnlyResult result = this;
10566         result.frontIndex += from;
10567         result.backIndex = this.frontIndex + to;
10568         assert(
10569             from <= to,
10570             "Attempting to slice an Only range with a larger first argument than the second."
10571         );
10572         assert(
10573             to <= length,
10574             "Attempting to slice using an out of bounds index on an Only range"
10575         );
10576         return result;
10577     }
10578 
10579     private size_t frontIndex = 0;
10580     private size_t backIndex = 0;
10581 
10582     // https://issues.dlang.org/show_bug.cgi?id=10643
10583     version (none)
10584     {
10585         import std.traits : hasElaborateAssign;
10586         static if (hasElaborateAssign!T)
10587             private UnqualValues values;
10588         else
10589             private UnqualValues values = void;
10590     }
10591     else
10592         // These may alias to shared or immutable data. Do not let the user
10593         // to access these directly, and do not allow mutation without checking
10594         // the qualifier.
10595         private UnqualValues values;
10596 }
10597 
10598 // Specialize for single-element results
10599 private struct OnlyResult(T)
10600 {
10601     import std.traits : isAssignable;
10602 
10603     @property T front()
10604     {
10605         assert(!empty, "Attempting to fetch the front of an empty Only range");
10606         return fetchFront();
10607     }
10608     static if (isAssignable!T)
10609     {
10610         @property void front(T value)
10611         {
10612             assert(!empty, "Attempting to assign the front of an empty Only range");
10613             assignFront(value);
10614         }
10615     }
10616     @property T back()
10617     {
10618         assert(!empty, "Attempting to fetch the back of an empty Only range");
10619         return fetchFront();
10620     }
10621     static if (isAssignable!T)
10622     {
10623         @property void back(T value)
10624         {
10625             assert(!empty, "Attempting to assign the front of an empty Only range");
10626             assignFront(value);
10627         }
10628     }
10629     @property bool empty() const { return _empty; }
10630     @property size_t length() const { return !_empty; }
10631     @property auto save() { return this; }
10632     void popFront()
10633     {
10634         assert(!_empty, "Attempting to popFront an empty Only range");
10635         _empty = true;
10636     }
10637     void popBack()
10638     {
10639         assert(!_empty, "Attempting to popBack an empty Only range");
10640         _empty = true;
10641     }
10642     alias opDollar = length;
10643 
10644     // FIXME Workaround for https://issues.dlang.org/show_bug.cgi?id=24415
10645     import std.traits : hasElaborateCopyConstructor;
10646     static if (hasElaborateCopyConstructor!T)
10647     {
10648         private static struct WorkaroundBugzilla24415 {}
10649         public this()(WorkaroundBugzilla24415) {}
10650     }
10651 
10652     private this()(return scope auto ref T value)
10653     {
10654         ref @trusted unqual(ref T x){return cast() x;}
10655         // TODO: this calls the possible copy constructor without qualifiers.
10656         // Find a way to initialize value using a qualified copy constructor.
10657         this._value = unqual(value);
10658         this._empty = false;
10659     }
10660 
10661     T opIndex(size_t i)
10662     {
10663         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
10664         return fetchFront();
10665     }
10666 
10667     static if (isAssignable!T)
10668     {
10669         void opIndexAssign(T value, size_t i)
10670         {
10671             assert(!_empty && i == 0, "Attempting to assign an out of bounds index of an Only range");
10672             assignFront(value);
10673         }
10674     }
10675 
10676     OnlyResult opSlice()
10677     {
10678         return this;
10679     }
10680 
10681     OnlyResult opSlice(size_t from, size_t to)
10682     {
10683         assert(
10684             from <= to,
10685             "Attempting to slice an Only range with a larger first argument than the second."
10686         );
10687         assert(
10688             to <= length,
10689             "Attempting to slice using an out of bounds index on an Only range"
10690         );
10691         OnlyResult copy = this;
10692         copy._empty = _empty || from == to;
10693         return copy;
10694     }
10695 
10696     // This may alias to shared or immutable data. Do not let the user
10697     // to access this directly, and do not allow mutation without checking
10698     // the qualifier.
10699     private Unqual!T _value;
10700     private bool _empty = true;
10701     private @trusted T fetchFront()
10702     {
10703         return *cast(T*)&_value;
10704     }
10705     static if (isAssignable!T)
10706     {
10707         private @trusted void assignFront(T newValue)
10708         {
10709             *cast(T*) &_value = newValue;
10710         }
10711     }
10712 }
10713 
10714 /**
10715 Assemble `values` into a range that carries all its
10716 elements in-situ.
10717 
10718 Useful when a single value or multiple disconnected values
10719 must be passed to an algorithm expecting a range, without
10720 having to perform dynamic memory allocation.
10721 
10722 As copying the range means copying all elements, it can be
10723 safely returned from functions. For the same reason, copying
10724 the returned range may be expensive for a large number of arguments.
10725 
10726 Params:
10727     values = the values to assemble together
10728 
10729 Returns:
10730     A `RandomAccessRange` of the assembled values.
10731 
10732     The returned range can be sliced. Its elements can be assigned to if every
10733     type in `Values` supports assignment from the range's element type.
10734 
10735 See_Also: $(LREF chain) to chain ranges
10736  */
10737 auto only(Values...)(return scope Values values)
10738 if (!is(CommonType!Values == void))
10739 {
10740     return OnlyResult!Values(values);
10741 }
10742 
10743 /// ditto
10744 auto only()()
10745 {
10746     // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383
10747     struct EmptyElementType {}
10748     EmptyElementType[] result;
10749     return result;
10750 }
10751 
10752 ///
10753 @safe unittest
10754 {
10755     import std.algorithm.comparison : equal;
10756     import std.algorithm.iteration : filter, joiner, map;
10757     import std.algorithm.searching : findSplitBefore;
10758     import std.uni : isUpper;
10759 
10760     assert(equal(only('♡'), "♡"));
10761     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
10762 
10763     assert(only("one", "two", "three").joiner(" ").equal("one two three"));
10764 
10765     string title = "The D Programming Language";
10766     assert(title
10767         .filter!isUpper // take the upper case letters
10768         .map!only       // make each letter its own range
10769         .joiner(".")    // join the ranges together lazily
10770         .equal("T.D.P.L"));
10771 }
10772 
10773 // https://issues.dlang.org/show_bug.cgi?id=20314
10774 @safe unittest
10775 {
10776     import std.algorithm.iteration : joiner;
10777 
10778     const string s = "foo", t = "bar";
10779 
10780     assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
10781 }
10782 
10783 // Tests the zero-element result
10784 @safe unittest
10785 {
10786     import std.algorithm.comparison : equal;
10787 
10788     auto emptyRange = only();
10789 
10790     alias EmptyRange = typeof(emptyRange);
10791     static assert(isInputRange!EmptyRange);
10792     static assert(isForwardRange!EmptyRange);
10793     static assert(isBidirectionalRange!EmptyRange);
10794     static assert(isRandomAccessRange!EmptyRange);
10795     static assert(hasLength!EmptyRange);
10796     static assert(hasSlicing!EmptyRange);
10797 
10798     assert(emptyRange.empty);
10799     assert(emptyRange.length == 0);
10800     assert(emptyRange.equal(emptyRange[]));
10801     assert(emptyRange.equal(emptyRange.save));
10802     assert(emptyRange[0 .. 0].equal(emptyRange));
10803 }
10804 
10805 // Tests the single-element result
10806 @safe unittest
10807 {
10808     import std.algorithm.comparison : equal;
10809     import std.typecons : tuple;
10810     foreach (x; tuple(1, '1', 1.0, "1", [1]))
10811     {
10812         auto a = only(x);
10813         typeof(x)[] e = [];
10814         assert(a.front == x);
10815         assert(a.back == x);
10816         assert(!a.empty);
10817         assert(a.length == 1);
10818         assert(equal(a, a[]));
10819         assert(equal(a, a[0 .. 1]));
10820         assert(equal(a[0 .. 0], e));
10821         assert(equal(a[1 .. 1], e));
10822         assert(a[0] == x);
10823 
10824         auto b = a.save;
10825         assert(equal(a, b));
10826         a.popFront();
10827         assert(a.empty && a.length == 0 && a[].empty);
10828         b.popBack();
10829         assert(b.empty && b.length == 0 && b[].empty);
10830 
10831         alias A = typeof(a);
10832         static assert(isInputRange!A);
10833         static assert(isForwardRange!A);
10834         static assert(isBidirectionalRange!A);
10835         static assert(isRandomAccessRange!A);
10836         static assert(hasLength!A);
10837         static assert(hasSlicing!A);
10838     }
10839 
10840     auto imm = only!(immutable int)(1);
10841     immutable int[] imme = [];
10842     assert(imm.front == 1);
10843     assert(imm.back == 1);
10844     assert(!imm.empty);
10845     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10846     assert(imm.length == 1);
10847     assert(equal(imm, imm[]));
10848     assert(equal(imm, imm[0 .. 1]));
10849     assert(equal(imm[0 .. 0], imme));
10850     assert(equal(imm[1 .. 1], imme));
10851     assert(imm[0] == 1);
10852 }
10853 
10854 // Tests multiple-element results
10855 @safe unittest
10856 {
10857     import std.algorithm.comparison : equal;
10858     import std.algorithm.iteration : joiner;
10859     import std.meta : AliasSeq;
10860     static assert(!__traits(compiles, only(1, "1")));
10861 
10862     auto nums = only!(byte, uint, long)(1, 2, 3);
10863     static assert(is(ElementType!(typeof(nums)) == long));
10864     assert(nums.length == 3);
10865 
10866     foreach (i; 0 .. 3)
10867         assert(nums[i] == i + 1);
10868 
10869     auto saved = nums.save;
10870 
10871     foreach (i; 1 .. 4)
10872     {
10873         assert(nums.front == nums[0]);
10874         assert(nums.front == i);
10875         nums.popFront();
10876         assert(nums.length == 3 - i);
10877     }
10878 
10879     assert(nums.empty);
10880 
10881     assert(saved.equal(only(1, 2, 3)));
10882     assert(saved.equal(saved[]));
10883     assert(saved[0 .. 1].equal(only(1)));
10884     assert(saved[0 .. 2].equal(only(1, 2)));
10885     assert(saved[0 .. 3].equal(saved));
10886     assert(saved[1 .. 3].equal(only(2, 3)));
10887     assert(saved[2 .. 3].equal(only(3)));
10888     assert(saved[0 .. 0].empty);
10889     assert(saved[3 .. 3].empty);
10890 
10891     alias data = AliasSeq!("one", "two", "three", "four");
10892     static joined =
10893         ["one two", "one two three", "one two three four"];
10894     string[] joinedRange = joined;
10895 
10896     static foreach (argCount; 2 .. 5)
10897     {{
10898         auto values = only(data[0 .. argCount]);
10899         alias Values = typeof(values);
10900         static assert(is(ElementType!Values == string));
10901         static assert(isInputRange!Values);
10902         static assert(isForwardRange!Values);
10903         static assert(isBidirectionalRange!Values);
10904         static assert(isRandomAccessRange!Values);
10905         static assert(hasSlicing!Values);
10906         static assert(hasLength!Values);
10907 
10908         assert(values.length == argCount);
10909         assert(values[0 .. $].equal(values[0 .. values.length]));
10910         assert(values.joiner(" ").equal(joinedRange.front));
10911         joinedRange.popFront();
10912     }}
10913 
10914     assert(saved.retro.equal(only(3, 2, 1)));
10915     assert(saved.length == 3);
10916 
10917     assert(saved.back == 3);
10918     saved.popBack();
10919     assert(saved.length == 2);
10920     assert(saved.back == 2);
10921 
10922     assert(saved.front == 1);
10923     saved.popFront();
10924     assert(saved.length == 1);
10925     assert(saved.front == 2);
10926 
10927     saved.popBack();
10928     assert(saved.empty);
10929 
10930     auto imm = only!(immutable int, immutable int)(42, 24);
10931     alias Imm = typeof(imm);
10932     static assert(is(ElementType!Imm == immutable(int)));
10933     assert(!imm.empty);
10934     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10935     assert(imm.front == 42);
10936     imm.popFront();
10937     assert(imm.front == 24);
10938     imm.popFront();
10939     assert(imm.empty);
10940 
10941     static struct Test { int* a; }
10942     immutable(Test) test;
10943     cast(void) only(test, test); // Works with mutable indirection
10944 }
10945 
10946 // https://issues.dlang.org/show_bug.cgi?id=21129
10947 @safe unittest
10948 {
10949     auto range = () @safe {
10950         const(char)[5] staticStr = "Hello";
10951 
10952         // `only` must store a char[5] - not a char[]!
10953         return only(staticStr, " World");
10954     } ();
10955 
10956     assert(range.join == "Hello World");
10957 }
10958 
10959 // https://issues.dlang.org/show_bug.cgi?id=21129
10960 @safe unittest
10961 {
10962     struct AliasedString
10963     {
10964         const(char)[5] staticStr = "Hello";
10965 
10966         @property const(char)[] slice() const
10967         {
10968             return staticStr[];
10969         }
10970         alias slice this;
10971     }
10972 
10973     auto range = () @safe {
10974         auto hello = AliasedString();
10975 
10976         // a copy of AliasedString is stored in the range.
10977         return only(hello, " World");
10978     } ();
10979 
10980     assert(range.join == "Hello World");
10981 }
10982 
10983 // https://issues.dlang.org/show_bug.cgi?id=21022
10984 @safe pure nothrow unittest
10985 {
10986     struct S
10987     {
10988         int* mem;
10989     }
10990 
10991     immutable S x;
10992     immutable(S)[] arr;
10993     auto r1 = arr.chain(x.only, only(x, x));
10994 }
10995 
10996 // https://issues.dlang.org/show_bug.cgi?id=24382
10997 @safe unittest
10998 {
10999     auto r1 = only(123);
11000     r1.front = 456;
11001     r1.back = 456;
11002     r1[0] = 456;
11003 
11004     auto r2 = only(123, 456);
11005     r2.front = 789;
11006     r2.back = 789;
11007     r2[0] = 789;
11008 
11009     auto r3 = only(1.23, 456);
11010     // Can't assign double to int
11011     static assert(!__traits(compiles, r3.front = 7.89));
11012     static assert(!__traits(compiles, r3.back = 7.89));
11013     // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
11014     static assert(!__traits(compiles, () { r3[0] = 7.89; }));
11015     // Can't assign type other than element type (even if compatible)
11016     static assert(!__traits(compiles, r3.front = 789));
11017     static assert(!__traits(compiles, r3.back = 789));
11018     // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
11019     static assert(!__traits(compiles, () { r3[0] = 789; }));
11020 }
11021 
11022 /**
11023 Iterate over `range` with an attached index variable.
11024 
11025 Each element is a $(REF Tuple, std,typecons) containing the index
11026 and the element, in that order, where the index member is named `index`
11027 and the element member is named `value`.
11028 
11029 The index starts at `start` and is incremented by one on every iteration.
11030 
11031 Overflow:
11032     If `range` has length, then it is an error to pass a value for `start`
11033     so that `start + range.length` is bigger than `Enumerator.max`, thus
11034     it is ensured that overflow cannot happen.
11035 
11036     If `range` does not have length, and `popFront` is called when
11037     `front.index == Enumerator.max`, the index will overflow and
11038     continue from `Enumerator.min`.
11039 
11040 Params:
11041     range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
11042     start = the number to start the index counter from
11043 
11044 Returns:
11045     At minimum, an input range. All other range primitives are given in the
11046     resulting range if `range` has them. The exceptions are the bidirectional
11047     primitives, which are propagated only if `range` has length.
11048 
11049 Example:
11050 Useful for using `foreach` with an index loop variable:
11051 ----
11052     import std.stdio : stdin, stdout;
11053     import std.range : enumerate;
11054 
11055     foreach (lineNum, line; stdin.byLine().enumerate(1))
11056         stdout.writefln("line #%s: %s", lineNum, line);
11057 ----
11058 */
11059 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
11060 if (isIntegral!Enumerator && isInputRange!Range)
11061 in
11062 {
11063     static if (hasLength!Range)
11064     {
11065         // TODO: core.checkedint supports mixed signedness yet?
11066         import core.checkedint : adds, addu;
11067         import std.conv : ConvException, to;
11068         import std.traits : isSigned, Largest, Signed;
11069 
11070         alias LengthType = typeof(range.length);
11071         bool overflow;
11072         static if (isSigned!Enumerator && isSigned!LengthType)
11073             auto result = adds(start, range.length, overflow);
11074         else static if (isSigned!Enumerator)
11075         {
11076             alias signed_t = Largest!(Enumerator, Signed!LengthType);
11077             signed_t signedLength;
11078             //This is to trick the compiler because if length is enum
11079             //the compiler complains about unreachable code.
11080             auto getLength()
11081             {
11082                 return range.length;
11083             }
11084             //Can length fit in the signed type
11085             assert(getLength() < signed_t.max,
11086                 "a signed length type is required but the range's length() is too great");
11087             signedLength = range.length;
11088             auto result = adds(start, signedLength, overflow);
11089         }
11090         else
11091         {
11092             static if (isSigned!LengthType)
11093                 assert(range.length >= 0);
11094             auto result = addu(start, range.length, overflow);
11095         }
11096 
11097         assert(!overflow && result <= Enumerator.max);
11098     }
11099 }
11100 do
11101 {
11102     // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
11103     static struct Result
11104     {
11105         import std.typecons : Tuple;
11106 
11107         private:
11108         alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
11109         Range range;
11110         Unqual!Enumerator index;
11111 
11112         public:
11113         ElemType front() @property
11114         {
11115             assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
11116             return typeof(return)(index, range.front);
11117         }
11118 
11119         static if (isInfinite!Range)
11120             enum bool empty = false;
11121         else
11122         {
11123             bool empty() @property
11124             {
11125                 return range.empty;
11126             }
11127         }
11128 
11129         void popFront()
11130         {
11131             assert(!range.empty, "Attempting to popFront an empty enumerate");
11132             range.popFront();
11133             ++index; // When !hasLength!Range, overflow is expected
11134         }
11135 
11136         static if (isForwardRange!Range)
11137         {
11138             Result save() @property
11139             {
11140                 return typeof(return)(range.save, index);
11141             }
11142         }
11143 
11144         static if (hasLength!Range)
11145         {
11146             mixin ImplementLength!range;
11147 
11148             static if (isBidirectionalRange!Range)
11149             {
11150                 ElemType back() @property
11151                 {
11152                     assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
11153                     return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
11154                 }
11155 
11156                 void popBack()
11157                 {
11158                     assert(!range.empty, "Attempting to popBack an empty enumerate");
11159                     range.popBack();
11160                 }
11161             }
11162         }
11163 
11164         static if (isRandomAccessRange!Range)
11165         {
11166              ElemType opIndex(size_t i)
11167              {
11168                 return typeof(return)(cast(Enumerator)(index + i), range[i]);
11169              }
11170         }
11171 
11172         static if (hasSlicing!Range)
11173         {
11174             static if (hasLength!Range)
11175             {
11176                 Result opSlice(size_t i, size_t j)
11177                 {
11178                     return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
11179                 }
11180             }
11181             else
11182             {
11183                 static struct DollarToken {}
11184                 enum opDollar = DollarToken.init;
11185 
11186                 Result opSlice(size_t i, DollarToken)
11187                 {
11188                     return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
11189                 }
11190 
11191                 auto opSlice(size_t i, size_t j)
11192                 {
11193                     return this[i .. $].takeExactly(j - 1);
11194                 }
11195             }
11196         }
11197     }
11198 
11199     return Result(range, start);
11200 }
11201 
11202 /// Can start enumeration from a negative position:
11203 pure @safe nothrow unittest
11204 {
11205     import std.array : assocArray;
11206     import std.range : enumerate;
11207 
11208     bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
11209     assert(aa[-1]);
11210     assert(aa[0]);
11211     assert(aa[1]);
11212 }
11213 
11214 // Make sure passing qualified types works
11215 pure @safe nothrow unittest
11216 {
11217     char[4] v;
11218     immutable start = 2;
11219     v[2 .. $].enumerate(start);
11220 }
11221 
11222 pure @safe nothrow unittest
11223 {
11224     import std.internal.test.dummyrange : AllDummyRanges;
11225     import std.meta : AliasSeq;
11226     import std.typecons : tuple;
11227 
11228     static struct HasSlicing
11229     {
11230         typeof(this) front() @property { return typeof(this).init; }
11231         bool empty() @property { return true; }
11232         void popFront() {}
11233 
11234         typeof(this) opSlice(size_t, size_t)
11235         {
11236             return typeof(this)();
11237         }
11238     }
11239 
11240     static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
11241     {{
11242         alias R = typeof(enumerate(DummyType.init));
11243         static assert(isInputRange!R);
11244         static assert(isForwardRange!R == isForwardRange!DummyType);
11245         static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
11246         static assert(!hasAssignableElements!R);
11247 
11248         static if (hasLength!DummyType)
11249         {
11250             static assert(hasLength!R);
11251             static assert(isBidirectionalRange!R ==
11252                 isBidirectionalRange!DummyType);
11253         }
11254 
11255         static assert(hasSlicing!R == hasSlicing!DummyType);
11256     }}
11257 
11258     static immutable values = ["zero", "one", "two", "three"];
11259     auto enumerated = values[].enumerate();
11260     assert(!enumerated.empty);
11261     assert(enumerated.front == tuple(0, "zero"));
11262     assert(enumerated.back == tuple(3, "three"));
11263 
11264     typeof(enumerated) saved = enumerated.save;
11265     saved.popFront();
11266     assert(enumerated.front == tuple(0, "zero"));
11267     assert(saved.front == tuple(1, "one"));
11268     assert(saved.length == enumerated.length - 1);
11269     saved.popBack();
11270     assert(enumerated.back == tuple(3, "three"));
11271     assert(saved.back == tuple(2, "two"));
11272     saved.popFront();
11273     assert(saved.front == tuple(2, "two"));
11274     assert(saved.back == tuple(2, "two"));
11275     saved.popFront();
11276     assert(saved.empty);
11277 
11278     size_t control = 0;
11279     foreach (i, v; enumerated)
11280     {
11281         static assert(is(typeof(i) == size_t));
11282         static assert(is(typeof(v) == typeof(values[0])));
11283         assert(i == control);
11284         assert(v == values[i]);
11285         assert(tuple(i, v) == enumerated[i]);
11286         ++control;
11287     }
11288 
11289     assert(enumerated[0 .. $].front == tuple(0, "zero"));
11290     assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
11291 
11292     foreach (i; 0 .. 10)
11293     {
11294         auto shifted = values[0 .. 2].enumerate(i);
11295         assert(shifted.front == tuple(i, "zero"));
11296         assert(shifted[0] == shifted.front);
11297 
11298         auto next = tuple(i + 1, "one");
11299         assert(shifted[1] == next);
11300         shifted.popFront();
11301         assert(shifted.front == next);
11302         shifted.popFront();
11303         assert(shifted.empty);
11304     }
11305 
11306     static foreach (T; AliasSeq!(ubyte, byte, uint, int))
11307     {{
11308         auto inf = 42.repeat().enumerate(T.max);
11309         alias Inf = typeof(inf);
11310         static assert(isInfinite!Inf);
11311         static assert(hasSlicing!Inf);
11312 
11313         // test overflow
11314         assert(inf.front == tuple(T.max, 42));
11315         inf.popFront();
11316         assert(inf.front == tuple(T.min, 42));
11317 
11318         // test slicing
11319         inf = inf[42 .. $];
11320         assert(inf.front == tuple(T.min + 42, 42));
11321         auto window = inf[0 .. 2];
11322         assert(window.length == 1);
11323         assert(window.front == inf.front);
11324         window.popFront();
11325         assert(window.empty);
11326     }}
11327 }
11328 
11329 pure @safe unittest
11330 {
11331     import std.algorithm.comparison : equal;
11332     import std.meta : AliasSeq;
11333     static immutable int[] values = [0, 1, 2, 3, 4];
11334     static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
11335     {{
11336         auto enumerated = values.enumerate!T();
11337         static assert(is(typeof(enumerated.front.index) == T));
11338         assert(enumerated.equal(values[].zip(values)));
11339 
11340         foreach (T i; 0 .. 5)
11341         {
11342             auto subset = values[cast(size_t) i .. $];
11343             auto offsetEnumerated = subset.enumerate(i);
11344             static assert(is(typeof(enumerated.front.index) == T));
11345             assert(offsetEnumerated.equal(subset.zip(subset)));
11346         }
11347     }}
11348 }
11349 @nogc @safe unittest
11350 {
11351    const val = iota(1, 100).enumerate(1);
11352 }
11353 @nogc @safe unittest
11354 {
11355     import core.exception : AssertError;
11356     import std.exception : assertThrown;
11357     struct RangePayload {
11358         enum length = size_t.max;
11359         void popFront() {}
11360         int front() { return 0; }
11361         bool empty() { return true; }
11362     }
11363     RangePayload thePayload;
11364     //Assertion won't happen when contracts are disabled for -release.
11365     debug assertThrown!AssertError(enumerate(thePayload, -10));
11366 }
11367 // https://issues.dlang.org/show_bug.cgi?id=10939
11368 version (none)
11369 {
11370     // Re-enable (or remove) if 10939 is resolved.
11371     /+pure+/ @safe unittest // Impure because of std.conv.to
11372     {
11373         import core.exception : RangeError;
11374         import std.exception : assertNotThrown, assertThrown;
11375         import std.meta : AliasSeq;
11376 
11377         static immutable values = [42];
11378 
11379         static struct SignedLengthRange
11380         {
11381             immutable(int)[] _values = values;
11382 
11383             int front() @property { assert(false); }
11384             bool empty() @property { assert(false); }
11385             void popFront() { assert(false); }
11386 
11387             int length() @property
11388             {
11389                 return cast(int)_values.length;
11390             }
11391         }
11392 
11393         SignedLengthRange svalues;
11394         static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
11395         {
11396             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
11397             assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
11398             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
11399 
11400             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
11401             assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
11402             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
11403         }
11404 
11405         static foreach (Enumerator; AliasSeq!(byte, short, int))
11406         {
11407             assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
11408         }
11409 
11410         assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
11411     }
11412 }
11413 
11414 /**
11415   Returns true if `fn` accepts variables of type T1 and T2 in any order.
11416   The following code should compile:
11417   ---
11418   (ref T1 a, ref T2 b)
11419   {
11420     fn(a, b);
11421     fn(b, a);
11422   }
11423   ---
11424 */
11425 template isTwoWayCompatible(alias fn, T1, T2)
11426 {
11427     enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
11428         {
11429             cast(void) fn(a, b);
11430             cast(void) fn(b, a);
11431         }
11432     ));
11433 }
11434 
11435 ///
11436 @safe unittest
11437 {
11438     void func1(int a, int b);
11439     void func2(int a, float b);
11440 
11441     static assert(isTwoWayCompatible!(func1, int, int));
11442     static assert(isTwoWayCompatible!(func1, short, int));
11443     static assert(!isTwoWayCompatible!(func2, int, float));
11444 
11445     void func3(ref int a, ref int b);
11446     static assert( isTwoWayCompatible!(func3, int, int));
11447     static assert(!isTwoWayCompatible!(func3, short, int));
11448 }
11449 
11450 
11451 /**
11452    Policy used with the searching primitives `lowerBound`, $(D
11453    upperBound), and `equalRange` of $(LREF SortedRange) below.
11454  */
11455 enum SearchPolicy
11456 {
11457     /**
11458        Searches in a linear fashion.
11459     */
11460     linear,
11461 
11462     /**
11463        Searches with a step that is grows linearly (1, 2, 3,...)
11464        leading to a quadratic search schedule (indexes tried are 0, 1,
11465        3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
11466        the remaining interval is searched using binary search. The
11467        search is completed in $(BIGOH sqrt(n)) time. Use it when you
11468        are reasonably confident that the value is around the beginning
11469        of the range.
11470     */
11471     trot,
11472 
11473     /**
11474        Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
11475        galloping search algorithm), i.e. searches
11476        with a step that doubles every time, (1, 2, 4, 8, ...)  leading
11477        to an exponential search schedule (indexes tried are 0, 1, 3,
11478        7, 15, 31, 63,...) Once the search overshoots its target, the
11479        remaining interval is searched using binary search. A value is
11480        found in $(BIGOH log(n)) time.
11481     */
11482     gallop,
11483 
11484     /**
11485        Searches using a classic interval halving policy. The search
11486        starts in the middle of the range, and each search step cuts
11487        the range in half. This policy finds a value in $(BIGOH log(n))
11488        time but is less cache friendly than `gallop` for large
11489        ranges. The `binarySearch` policy is used as the last step
11490        of `trot`, `gallop`, `trotBackwards`, and $(D
11491        gallopBackwards) strategies.
11492     */
11493     binarySearch,
11494 
11495     /**
11496        Similar to `trot` but starts backwards. Use it when
11497        confident that the value is around the end of the range.
11498     */
11499     trotBackwards,
11500 
11501     /**
11502        Similar to `gallop` but starts backwards. Use it when
11503        confident that the value is around the end of the range.
11504     */
11505     gallopBackwards
11506 }
11507 
11508 ///
11509 @safe unittest
11510 {
11511     import std.algorithm.comparison : equal;
11512 
11513     auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
11514     auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
11515     assert(p1.equal([4, 5, 6, 7, 8, 9]));
11516 
11517     auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
11518     assert(p2.equal([0, 1, 2, 3]));
11519 }
11520 
11521 /**
11522    Options for $(LREF SortedRange) ranges (below).
11523 */
11524 enum SortedRangeOptions
11525 {
11526    /**
11527       Assume, that the range is sorted without checking.
11528    */
11529    assumeSorted,
11530 
11531    /**
11532       All elements of the range are checked to be sorted.
11533       The check is performed in O(n) time.
11534    */
11535    checkStrictly,
11536 
11537    /**
11538       Some elements of the range are checked to be sorted.
11539       For ranges with random order, this will almost surely
11540       detect, that it is not sorted. For almost sorted ranges
11541       it's more likely to fail. The checked elements are choosen
11542       in a deterministic manner, which makes this check reproducable.
11543       The check is performed in O(log(n)) time.
11544    */
11545    checkRoughly,
11546 }
11547 
11548 ///
11549 @safe pure unittest
11550 {
11551     // create a SortedRange, that's checked strictly
11552     SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
11553 }
11554 
11555 /**
11556    Represents a sorted range. In addition to the regular range
11557    primitives, supports additional operations that take advantage of the
11558    ordering, such as merge and binary search. To obtain a $(D
11559    SortedRange) from an unsorted range `r`, use
11560    $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
11561    corresponding `SortedRange`. To construct a `SortedRange` from a range
11562    `r` that is known to be already sorted, use $(LREF assumeSorted).
11563 
11564    Params:
11565        pred: The predicate used to define the sortedness
11566        opt: Controls how strongly the range is checked for sortedness.
11567             Will only be used for `RandomAccessRanges`.
11568             Will not be used in CTFE.
11569 */
11570 struct SortedRange(Range, alias pred = "a < b",
11571     SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11572 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
11573 {
11574     import std.functional : binaryFun;
11575 
11576     private alias predFun = binaryFun!pred;
11577     private bool geq(L, R)(L lhs, R rhs)
11578     {
11579         return !predFun(lhs, rhs);
11580     }
11581     private bool gt(L, R)(L lhs, R rhs)
11582     {
11583         return predFun(rhs, lhs);
11584     }
11585     private Range _input;
11586 
11587     // Undocummented because a clearer way to invoke is by calling
11588     // assumeSorted.
11589     this(Range input)
11590     {
11591         static if (opt == SortedRangeOptions.checkRoughly)
11592         {
11593             roughlyVerifySorted(input);
11594         }
11595         static if (opt == SortedRangeOptions.checkStrictly)
11596         {
11597             strictlyVerifySorted(input);
11598         }
11599         this._input = input;
11600     }
11601 
11602     // Assertion only.
11603     static if (opt == SortedRangeOptions.checkRoughly)
11604     private void roughlyVerifySorted(Range r)
11605     {
11606         if (!__ctfe)
11607         {
11608             static if (isRandomAccessRange!Range && hasLength!Range)
11609             {
11610                 import core.bitop : bsr;
11611                 import std.algorithm.sorting : isSorted;
11612                 import std.exception : enforce;
11613 
11614                 // Check the sortedness of the input
11615                 if (r.length < 2) return;
11616 
11617                 immutable size_t msb = bsr(r.length) + 1;
11618                 assert(msb > 0 && msb <= r.length);
11619                 immutable step = r.length / msb;
11620                 auto st = stride(r, step);
11621 
11622                 enforce(isSorted!pred(st), "Range is not sorted");
11623             }
11624         }
11625     }
11626 
11627     // Assertion only.
11628     static if (opt == SortedRangeOptions.checkStrictly)
11629     private void strictlyVerifySorted(Range r)
11630     {
11631         if (!__ctfe)
11632         {
11633             static if (isRandomAccessRange!Range && hasLength!Range)
11634             {
11635                 import std.algorithm.sorting : isSorted;
11636                 import std.exception : enforce;
11637 
11638                 enforce(isSorted!pred(r), "Range is not sorted");
11639             }
11640         }
11641     }
11642 
11643     /// Range primitives.
11644     @property bool empty()             //const
11645     {
11646         return this._input.empty;
11647     }
11648 
11649     /// Ditto
11650     static if (isForwardRange!Range)
11651     @property auto save()
11652     {
11653         // Avoid the constructor
11654         typeof(this) result = this;
11655         result._input = _input.save;
11656         return result;
11657     }
11658 
11659     /// Ditto
11660     @property auto ref front()
11661     {
11662         return _input.front;
11663     }
11664 
11665     /// Ditto
11666     void popFront()
11667     {
11668         _input.popFront();
11669     }
11670 
11671     /// Ditto
11672     static if (isBidirectionalRange!Range)
11673     {
11674         @property auto ref back()
11675         {
11676             return _input.back;
11677         }
11678 
11679         /// Ditto
11680         void popBack()
11681         {
11682             _input.popBack();
11683         }
11684     }
11685 
11686     /// Ditto
11687     static if (isRandomAccessRange!Range)
11688         auto ref opIndex(size_t i)
11689         {
11690             return _input[i];
11691         }
11692 
11693     /// Ditto
11694     static if (hasSlicing!Range)
11695         auto opSlice(size_t a, size_t b) return scope
11696         {
11697             assert(
11698                 a <= b,
11699                 "Attempting to slice a SortedRange with a larger first argument than the second."
11700             );
11701             typeof(this) result = this;
11702             result._input = _input[a .. b];// skip checking
11703             return result;
11704         }
11705 
11706     mixin ImplementLength!_input;
11707 
11708 /**
11709     Releases the controlled range and returns it.
11710 
11711     This does the opposite of $(LREF assumeSorted): instead of turning a range
11712     into a `SortedRange`, it extracts the original range back out of the `SortedRange`
11713     using $(REF, move, std,algorithm,mutation).
11714 */
11715     auto release() return scope
11716     {
11717         import std.algorithm.mutation : move;
11718         return move(_input);
11719     }
11720 
11721     ///
11722     static if (is(Range : int[]))
11723     @safe unittest
11724     {
11725         import std.algorithm.sorting : sort;
11726         int[3] data = [ 1, 2, 3 ];
11727         auto a = assumeSorted(data[]);
11728         assert(a == sort!"a < b"(data[]));
11729         int[] p = a.release();
11730         assert(p == [ 1, 2, 3 ]);
11731     }
11732 
11733     // Assuming a predicate "test" that returns 0 for a left portion
11734     // of the range and then 1 for the rest, returns the index at
11735     // which the first 1 appears. Used internally by the search routines.
11736     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11737     if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
11738     {
11739         size_t first = 0, count = _input.length;
11740         while (count > 0)
11741         {
11742             immutable step = count / 2, it = first + step;
11743             if (!test(_input[it], v))
11744             {
11745                 first = it + 1;
11746                 count -= step + 1;
11747             }
11748             else
11749             {
11750                 count = step;
11751             }
11752         }
11753         return first;
11754     }
11755 
11756     // Specialization for trot and gallop
11757     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11758     if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
11759         && isRandomAccessRange!Range)
11760     {
11761         if (empty || test(front, v)) return 0;
11762         immutable count = length;
11763         if (count == 1) return 1;
11764         size_t below = 0, above = 1, step = 2;
11765         while (!test(_input[above], v))
11766         {
11767             // Still too small, update below and increase gait
11768             below = above;
11769             immutable next = above + step;
11770             if (next >= count)
11771             {
11772                 // Overshot - the next step took us beyond the end. So
11773                 // now adjust next and simply exit the loop to do the
11774                 // binary search thingie.
11775                 above = count;
11776                 break;
11777             }
11778             // Still in business, increase step and continue
11779             above = next;
11780             static if (sp == SearchPolicy.trot)
11781                 ++step;
11782             else
11783                 step <<= 1;
11784         }
11785         return below + this[below .. above].getTransitionIndex!(
11786             SearchPolicy.binarySearch, test, V)(v);
11787     }
11788 
11789     // Specialization for trotBackwards and gallopBackwards
11790     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11791     if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
11792         && isRandomAccessRange!Range)
11793     {
11794         immutable count = length;
11795         if (empty || !test(back, v)) return count;
11796         if (count == 1) return 0;
11797         size_t below = count - 2, above = count - 1, step = 2;
11798         while (test(_input[below], v))
11799         {
11800             // Still too large, update above and increase gait
11801             above = below;
11802             if (below < step)
11803             {
11804                 // Overshot - the next step took us beyond the end. So
11805                 // now adjust next and simply fall through to do the
11806                 // binary search thingie.
11807                 below = 0;
11808                 break;
11809             }
11810             // Still in business, increase step and continue
11811             below -= step;
11812             static if (sp == SearchPolicy.trot)
11813                 ++step;
11814             else
11815                 step <<= 1;
11816         }
11817         return below + this[below .. above].getTransitionIndex!(
11818             SearchPolicy.binarySearch, test, V)(v);
11819     }
11820 
11821 // lowerBound
11822 /**
11823    This function uses a search with policy `sp` to find the
11824    largest left subrange on which $(D pred(x, value)) is `true` for
11825    all `x` (e.g., if `pred` is "less than", returns the portion of
11826    the range with elements strictly smaller than `value`). The search
11827    schedule and its complexity are documented in
11828    $(LREF SearchPolicy).
11829 */
11830     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11831     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11832          && hasSlicing!Range)
11833     {
11834         return this[0 .. getTransitionIndex!(sp, geq)(value)];
11835     }
11836 
11837     ///
11838     static if (is(Range : int[]))
11839     @safe unittest
11840     {
11841         import std.algorithm.comparison : equal;
11842         auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
11843         auto p = a.lowerBound(4);
11844         assert(equal(p, [ 0, 1, 2, 3 ]));
11845     }
11846 
11847 // upperBound
11848 /**
11849 This function searches with policy `sp` to find the largest right
11850 subrange on which $(D pred(value, x)) is `true` for all `x`
11851 (e.g., if `pred` is "less than", returns the portion of the range
11852 with elements strictly greater than `value`). The search schedule
11853 and its complexity are documented in $(LREF SearchPolicy).
11854 
11855 For ranges that do not offer random access, `SearchPolicy.linear`
11856 is the only policy allowed (and it must be specified explicitly lest it exposes
11857 user code to unexpected inefficiencies). For random-access searches, all
11858 policies are allowed, and `SearchPolicy.binarySearch` is the default.
11859 */
11860     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11861     if (isTwoWayCompatible!(predFun, ElementType!Range, V))
11862     {
11863         static assert(hasSlicing!Range || sp == SearchPolicy.linear,
11864             "Specify SearchPolicy.linear explicitly for "
11865             ~ typeof(this).stringof);
11866         static if (sp == SearchPolicy.linear)
11867         {
11868             for (; !_input.empty && !predFun(value, _input.front);
11869                  _input.popFront())
11870             {
11871             }
11872             return this;
11873         }
11874         else
11875         {
11876             return this[getTransitionIndex!(sp, gt)(value) .. length];
11877         }
11878     }
11879 
11880     ///
11881     static if (is(Range : int[]))
11882     @safe unittest
11883     {
11884         import std.algorithm.comparison : equal;
11885         auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
11886         auto p = a.upperBound(3);
11887         assert(equal(p, [4, 4, 5, 6]));
11888     }
11889 
11890 
11891 // equalRange
11892 /**
11893    Returns the subrange containing all elements `e` for which both $(D
11894    pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11895    if `pred` is "less than", returns the portion of the range with
11896    elements equal to `value`). Uses a classic binary search with
11897    interval halving until it finds a value that satisfies the condition,
11898    then uses `SearchPolicy.gallopBackwards` to find the left boundary
11899    and `SearchPolicy.gallop` to find the right boundary. These
11900    policies are justified by the fact that the two boundaries are likely
11901    to be near the first found value (i.e., equal ranges are relatively
11902    small). Completes the entire search in $(BIGOH log(n)) time.
11903 */
11904     auto equalRange(V)(V value)
11905     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11906         && isRandomAccessRange!Range)
11907     {
11908         size_t first = 0, count = _input.length;
11909         while (count > 0)
11910         {
11911             immutable step = count / 2;
11912             auto it = first + step;
11913             if (predFun(_input[it], value))
11914             {
11915                 // Less than value, bump left bound up
11916                 first = it + 1;
11917                 count -= step + 1;
11918             }
11919             else if (predFun(value, _input[it]))
11920             {
11921                 // Greater than value, chop count
11922                 count = step;
11923             }
11924             else
11925             {
11926                 // Equal to value, do binary searches in the
11927                 // leftover portions
11928                 // Gallop towards the left end as it's likely nearby
11929                 immutable left = first
11930                     + this[first .. it]
11931                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11932                 first += count;
11933                 // Gallop towards the right end as it's likely nearby
11934                 immutable right = first
11935                     - this[it + 1 .. first]
11936                     .upperBound!(SearchPolicy.gallop)(value).length;
11937                 return this[left .. right];
11938             }
11939         }
11940         return this.init;
11941     }
11942 
11943     ///
11944     static if (is(Range : int[]))
11945     @safe unittest
11946     {
11947         import std.algorithm.comparison : equal;
11948         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11949         auto r = a.assumeSorted.equalRange(3);
11950         assert(equal(r, [ 3, 3, 3 ]));
11951     }
11952 
11953 // trisect
11954 /**
11955 Returns a tuple `r` such that `r[0]` is the same as the result
11956 of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11957 equalRange(value)), and `r[2]` is the same as the result of $(D
11958 upperBound(value)). The call is faster than computing all three
11959 separately. Uses a search schedule similar to $(D
11960 equalRange). Completes the entire search in $(BIGOH log(n)) time.
11961 */
11962     auto trisect(V)(V value)
11963     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11964         && isRandomAccessRange!Range && hasLength!Range)
11965     {
11966         import std.typecons : tuple;
11967         size_t first = 0, count = _input.length;
11968         while (count > 0)
11969         {
11970             immutable step = count / 2;
11971             auto it = first + step;
11972             if (predFun(_input[it], value))
11973             {
11974                 // Less than value, bump left bound up
11975                 first = it + 1;
11976                 count -= step + 1;
11977             }
11978             else if (predFun(value, _input[it]))
11979             {
11980                 // Greater than value, chop count
11981                 count = step;
11982             }
11983             else
11984             {
11985                 // Equal to value, do binary searches in the
11986                 // leftover portions
11987                 // Gallop towards the left end as it's likely nearby
11988                 immutable left = first
11989                     + this[first .. it]
11990                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11991                 first += count;
11992                 // Gallop towards the right end as it's likely nearby
11993                 immutable right = first
11994                     - this[it + 1 .. first]
11995                     .upperBound!(SearchPolicy.gallop)(value).length;
11996                 return tuple(this[0 .. left], this[left .. right],
11997                         this[right .. length]);
11998             }
11999         }
12000         // No equal element was found
12001         return tuple(this[0 .. first], this.init, this[first .. length]);
12002     }
12003 
12004     ///
12005     static if (is(Range : int[]))
12006     @safe unittest
12007     {
12008         import std.algorithm.comparison : equal;
12009         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12010         auto r = assumeSorted(a).trisect(3);
12011         assert(equal(r[0], [ 1, 2 ]));
12012         assert(equal(r[1], [ 3, 3, 3 ]));
12013         assert(equal(r[2], [ 4, 4, 5, 6 ]));
12014     }
12015 
12016 // contains
12017 /**
12018 Returns `true` if and only if `value` can be found in $(D
12019 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
12020 evaluations of `pred`.
12021  */
12022 
12023     bool contains(V)(V value)
12024     if (isRandomAccessRange!Range)
12025     {
12026         if (empty) return false;
12027         immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
12028         if (i >= length) return false;
12029         return !predFun(value, _input[i]);
12030     }
12031 
12032 /**
12033 Like `contains`, but the value is specified before the range.
12034 */
12035     bool opBinaryRight(string op, V)(V value)
12036     if (op == "in" && isRandomAccessRange!Range)
12037     {
12038         return contains(value);
12039     }
12040 
12041 // groupBy
12042 /**
12043 Returns a range of subranges of elements that are equivalent according to the
12044 sorting relation.
12045  */
12046     auto groupBy()()
12047     {
12048         import std.algorithm.iteration : chunkBy;
12049         return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
12050     }
12051 }
12052 
12053 /// ditto
12054 template SortedRange(Range, alias pred = "a < b",
12055                      SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
12056 if (isInstanceOf!(SortedRange, Range))
12057 {
12058     // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
12059     alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
12060 }
12061 
12062 ///
12063 @safe unittest
12064 {
12065     import std.algorithm.sorting : sort;
12066     auto a = [ 1, 2, 3, 42, 52, 64 ];
12067     auto r = assumeSorted(a);
12068     assert(r.contains(3));
12069     assert(!(32 in r));
12070     auto r1 = sort!"a > b"(a);
12071     assert(3 in r1);
12072     assert(!r1.contains(32));
12073     assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
12074 }
12075 
12076 /**
12077 `SortedRange` could accept ranges weaker than random-access, but it
12078 is unable to provide interesting functionality for them. Therefore,
12079 `SortedRange` is currently restricted to random-access ranges.
12080 
12081 No copy of the original range is ever made. If the underlying range is
12082 changed concurrently with its corresponding `SortedRange` in ways
12083 that break its sorted-ness, `SortedRange` will work erratically.
12084 */
12085 @safe unittest
12086 {
12087     import std.algorithm.mutation : swap;
12088     auto a = [ 1, 2, 3, 42, 52, 64 ];
12089     auto r = assumeSorted(a);
12090     assert(r.contains(42));
12091     swap(a[3], a[5]);         // illegal to break sortedness of original range
12092     assert(!r.contains(42));  // passes although it shouldn't
12093 }
12094 
12095 /**
12096 `SortedRange` can be searched with predicates that do not take
12097 two elements of the underlying range as arguments.
12098 
12099 This is useful, if a range of structs is sorted by a member and you
12100 want to search in that range by only providing a value for that member.
12101 
12102 */
12103 @safe unittest
12104 {
12105     import std.algorithm.comparison : equal;
12106     static struct S { int i; }
12107     static bool byI(A, B)(A a, B b)
12108     {
12109         static if (is(A == S))
12110             return a.i < b;
12111         else
12112             return a < b.i;
12113     }
12114     auto r = assumeSorted!byI([S(1), S(2), S(3)]);
12115     auto lessThanTwo = r.lowerBound(2);
12116     assert(equal(lessThanTwo, [S(1)]));
12117 }
12118 
12119 @safe unittest
12120 {
12121     import std.exception : assertThrown, assertNotThrown;
12122 
12123     assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
12124     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
12125 
12126     // these two checks are implementation depended
12127     assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
12128     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
12129 }
12130 
12131 @safe unittest
12132 {
12133     import std.algorithm.comparison : equal;
12134 
12135     auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
12136     auto r = assumeSorted(a).trisect(30);
12137     assert(equal(r[0], [ 10, 20 ]));
12138     assert(equal(r[1], [ 30, 30, 30 ]));
12139     assert(equal(r[2], [ 40, 40, 50, 60 ]));
12140 
12141     r = assumeSorted(a).trisect(35);
12142     assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
12143     assert(r[1].empty);
12144     assert(equal(r[2], [ 40, 40, 50, 60 ]));
12145 }
12146 
12147 @safe unittest
12148 {
12149     import std.algorithm.comparison : equal;
12150     auto a = [ "A", "AG", "B", "E", "F" ];
12151     auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
12152     assert(equal(r[0], [ "A", "AG" ]));
12153     assert(equal(r[1], [ "B" ]));
12154     assert(equal(r[2], [ "E", "F" ]));
12155     r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
12156     assert(r[0].empty);
12157     assert(equal(r[1], [ "A" ]));
12158     assert(equal(r[2], [ "AG", "B", "E", "F" ]));
12159 }
12160 
12161 @safe unittest
12162 {
12163     import std.algorithm.comparison : equal;
12164     static void test(SearchPolicy pol)()
12165     {
12166         auto a = [ 1, 2, 3, 42, 52, 64 ];
12167         auto r = assumeSorted(a);
12168         assert(equal(r.lowerBound(42), [1, 2, 3]));
12169 
12170         assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
12171         assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
12172         assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
12173         assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
12174         assert(equal(r.lowerBound!(pol)(3), [1, 2]));
12175         assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
12176         assert(equal(r.lowerBound!(pol)(420), a));
12177         assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
12178 
12179         assert(equal(r.upperBound!(pol)(42), [52, 64]));
12180         assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
12181         assert(equal(r.upperBound!(pol)(43), [52, 64]));
12182         assert(equal(r.upperBound!(pol)(51), [52, 64]));
12183         assert(equal(r.upperBound!(pol)(53), [64]));
12184         assert(equal(r.upperBound!(pol)(55), [64]));
12185         assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
12186         assert(equal(r.upperBound!(pol)(0), a));
12187     }
12188 
12189     test!(SearchPolicy.trot)();
12190     test!(SearchPolicy.gallop)();
12191     test!(SearchPolicy.trotBackwards)();
12192     test!(SearchPolicy.gallopBackwards)();
12193     test!(SearchPolicy.binarySearch)();
12194 }
12195 
12196 @safe unittest
12197 {
12198     // Check for small arrays
12199     int[] a;
12200     auto r = assumeSorted(a);
12201     a = [ 1 ];
12202     r = assumeSorted(a);
12203     a = [ 1, 2 ];
12204     r = assumeSorted(a);
12205     a = [ 1, 2, 3 ];
12206     r = assumeSorted(a);
12207 }
12208 
12209 @safe unittest
12210 {
12211     import std.algorithm.mutation : swap;
12212     auto a = [ 1, 2, 3, 42, 52, 64 ];
12213     auto r = assumeSorted(a);
12214     assert(r.contains(42));
12215     swap(a[3], a[5]);                  // illegal to break sortedness of original range
12216     assert(!r.contains(42));            // passes although it shouldn't
12217 }
12218 
12219 @betterC @nogc nothrow @safe unittest
12220 {
12221     static immutable(int)[] arr = [ 1, 2, 3 ];
12222     auto s = assumeSorted(arr);
12223 }
12224 
12225 @system unittest
12226 {
12227     import std.algorithm.comparison : equal;
12228     int[] arr = [100, 101, 102, 200, 201, 300];
12229     auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
12230     assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
12231 }
12232 
12233 // Test on an input range
12234 @system unittest
12235 {
12236     import std.conv : text;
12237     import std.file : exists, remove, tempDir;
12238     import std.path : buildPath;
12239     import std.stdio : File;
12240     import std.uuid : randomUUID;
12241     auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
12242                           "." ~ randomUUID().toString());
12243     auto f = File(name, "w");
12244     scope(exit) if (exists(name)) remove(name);
12245     // write a sorted range of lines to the file
12246     f.write("abc\ndef\nghi\njkl");
12247     f.close();
12248     f.open(name, "r");
12249     auto r = assumeSorted(f.byLine());
12250     auto r1 = r.upperBound!(SearchPolicy.linear)("def");
12251     assert(r1.front == "ghi", r1.front);
12252     f.close();
12253 }
12254 
12255 // https://issues.dlang.org/show_bug.cgi?id=19337
12256 @safe unittest
12257 {
12258     import std.algorithm.sorting : sort;
12259     auto a = [ 1, 2, 3, 42, 52, 64 ];
12260     a.sort.sort!"a > b";
12261 }
12262 
12263 /**
12264 Assumes `r` is sorted by predicate `pred` and returns the
12265 corresponding $(D SortedRange!(pred, R)) having `r` as support.
12266 To check for sorted-ness at
12267 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
12268  */
12269 auto assumeSorted(alias pred = "a < b", R)(R r)
12270 if (isInputRange!(Unqual!R))
12271 {
12272     // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
12273     static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
12274     {
12275         static if (isInputRange!R && __traits(isSame, pred, RPred))
12276             // If the predicate is the same and we don't need to cast away
12277             // constness for the result to be an input range.
12278             return r;
12279         else
12280             return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
12281     }
12282     else
12283     {
12284         return SortedRange!(Unqual!R, pred)(r);
12285     }
12286 }
12287 
12288 ///
12289 @safe unittest
12290 {
12291     import std.algorithm.comparison : equal;
12292 
12293     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
12294     auto p = assumeSorted(a);
12295 
12296     assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
12297     assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
12298     assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
12299     assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
12300 }
12301 
12302 @safe unittest
12303 {
12304     import std.algorithm.comparison : equal;
12305     static assert(isRandomAccessRange!(SortedRange!(int[])));
12306     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12307     auto p = assumeSorted(a).upperBound(3);
12308     assert(equal(p, [4, 4, 5, 6 ]));
12309     p = assumeSorted(a).upperBound(4.2);
12310     assert(equal(p, [ 5, 6 ]));
12311 
12312     // https://issues.dlang.org/show_bug.cgi?id=18933
12313     // don't create senselessly nested SortedRange types.
12314     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
12315     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
12316 }
12317 
12318 @safe unittest
12319 {
12320     import std.algorithm.comparison : equal;
12321     import std.conv : text;
12322 
12323     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12324     auto p = assumeSorted(a).equalRange(3);
12325     assert(equal(p, [ 3, 3, 3 ]), text(p));
12326     p = assumeSorted(a).equalRange(4);
12327     assert(equal(p, [ 4, 4 ]), text(p));
12328     p = assumeSorted(a).equalRange(2);
12329     assert(equal(p, [ 2 ]));
12330     p = assumeSorted(a).equalRange(0);
12331     assert(p.empty);
12332     p = assumeSorted(a).equalRange(7);
12333     assert(p.empty);
12334     p = assumeSorted(a).equalRange(3.0);
12335     assert(equal(p, [ 3, 3, 3]));
12336 }
12337 
12338 @safe unittest
12339 {
12340     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12341     if (a.length)
12342     {
12343         auto b = a[a.length / 2];
12344         //auto r = sort(a);
12345         //assert(r.contains(b));
12346     }
12347 }
12348 
12349 @safe unittest
12350 {
12351     auto a = [ 5, 7, 34, 345, 677 ];
12352     auto r = assumeSorted(a);
12353     a = null;
12354     r = assumeSorted(a);
12355     a = [ 1 ];
12356     r = assumeSorted(a);
12357 }
12358 
12359 // https://issues.dlang.org/show_bug.cgi?id=15003
12360 @nogc @safe unittest
12361 {
12362     static immutable a = [1, 2, 3, 4];
12363     auto r = a.assumeSorted;
12364 }
12365 
12366 /++
12367     Wrapper which effectively makes it possible to pass a range by reference.
12368     Both the original range and the RefRange will always have the exact same
12369     elements. Any operation done on one will affect the other. So, for instance,
12370     if it's passed to a function which would implicitly copy the original range
12371     if it were passed to it, the original range is $(I not) copied but is
12372     consumed as if it were a reference type.
12373 
12374     Note:
12375         `save` works as normal and operates on a new range, so if
12376         `save` is ever called on the `RefRange`, then no operations on the
12377         saved range will affect the original.
12378 
12379     Params:
12380         range = the range to construct the `RefRange` from
12381 
12382     Returns:
12383         A `RefRange`. If the given range is a class type
12384         (and thus is already a reference type), then the original
12385         range is returned rather than a `RefRange`.
12386   +/
12387 struct RefRange(R)
12388 if (isInputRange!R)
12389 {
12390 public:
12391 
12392     /++ +/
12393     this(R* range) @safe pure nothrow
12394     {
12395         _range = range;
12396     }
12397 
12398 
12399     /++
12400         This does not assign the pointer of `rhs` to this `RefRange`.
12401         Rather it assigns the range pointed to by `rhs` to the range pointed
12402         to by this `RefRange`. This is because $(I any) operation on a
12403         `RefRange` is the same is if it occurred to the original range. The
12404         one exception is when a `RefRange` is assigned `null` either
12405         directly or because `rhs` is `null`. In that case, `RefRange`
12406         no longer refers to the original range but is `null`.
12407       +/
12408     auto opAssign(RefRange rhs)
12409     {
12410         if (_range && rhs._range)
12411             *_range = *rhs._range;
12412         else
12413             _range = rhs._range;
12414 
12415         return this;
12416     }
12417 
12418     /++ +/
12419     void opAssign(typeof(null) rhs)
12420     {
12421         _range = null;
12422     }
12423 
12424 
12425     /++
12426         A pointer to the wrapped range.
12427       +/
12428     @property inout(R*) ptr() @safe inout pure nothrow
12429     {
12430         return _range;
12431     }
12432 
12433 
12434     version (StdDdoc)
12435     {
12436         /++ +/
12437         @property auto front() {assert(0);}
12438         /++ Ditto +/
12439         @property auto front() const {assert(0);}
12440         /++ Ditto +/
12441         @property auto front(ElementType!R value) {assert(0);}
12442     }
12443     else
12444     {
12445         @property auto front()
12446         {
12447             return (*_range).front;
12448         }
12449 
12450         static if (is(typeof(((const R* r) => (*r).front)(null)))) @property auto front() const
12451         {
12452             return (*_range).front;
12453         }
12454 
12455         static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
12456         {
12457             return (*_range).front = value;
12458         }
12459     }
12460 
12461 
12462     version (StdDdoc)
12463     {
12464         @property bool empty(); ///
12465         @property bool empty() const; ///Ditto
12466     }
12467     else static if (isInfinite!R)
12468         enum empty = false;
12469     else
12470     {
12471         @property bool empty()
12472         {
12473             return (*_range).empty;
12474         }
12475 
12476         static if (is(typeof(((const R* r) => (*r).empty)(null)))) @property bool empty() const
12477         {
12478             return (*_range).empty;
12479         }
12480     }
12481 
12482 
12483     /++ +/
12484     void popFront()
12485     {
12486         return (*_range).popFront();
12487     }
12488 
12489 
12490     version (StdDdoc)
12491     {
12492         /++
12493             Only defined if `isForwardRange!R` is `true`.
12494           +/
12495         @property auto save() {assert(0);}
12496         /++ Ditto +/
12497         @property auto save() const {assert(0);}
12498         /++ Ditto +/
12499         auto opSlice() {assert(0);}
12500         /++ Ditto +/
12501         auto opSlice() const {assert(0);}
12502     }
12503     else static if (isForwardRange!R)
12504     {
12505         import std.traits : isSafe;
12506         private alias S = typeof((() => (*_range).save)());
12507 
12508         static if (is(typeof(((const R* r) => (*r).save)(null))))
12509             private alias CS = typeof(((const R* r) => (*r).save)(null));
12510 
12511 
12512         static if (isSafe!((R* r) => (*r).save))
12513         {
12514             @property RefRange!S save() @trusted
12515             {
12516                 mixin(_genSave());
12517             }
12518 
12519             static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() @trusted const
12520             {
12521                 mixin(_genSave());
12522             }
12523         }
12524         else
12525         {
12526             @property RefRange!S save()
12527             {
12528                 mixin(_genSave());
12529             }
12530 
12531             static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() const
12532             {
12533                 mixin(_genSave());
12534             }
12535         }
12536 
12537         auto opSlice()()
12538         {
12539             return save;
12540         }
12541 
12542         auto opSlice()() const
12543         {
12544             return save;
12545         }
12546 
12547         private static string _genSave() @safe pure nothrow
12548         {
12549             return `import core.lifetime : emplace;` ~
12550                    `alias S = typeof((() => (*_range).save)());` ~
12551                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
12552                    `auto mem = new void[S.sizeof];` ~
12553                    `emplace!S(mem, cast(S)(*_range).save);` ~
12554                    `return RefRange!S(cast(S*) mem.ptr);`;
12555         }
12556 
12557         static assert(isForwardRange!RefRange);
12558     }
12559 
12560 
12561     version (StdDdoc)
12562     {
12563         /++
12564             Only defined if `isBidirectionalRange!R` is `true`.
12565           +/
12566         @property auto back() {assert(0);}
12567         /++ Ditto +/
12568         @property auto back() const {assert(0);}
12569         /++ Ditto +/
12570         @property auto back(ElementType!R value) {assert(0);}
12571     }
12572     else static if (isBidirectionalRange!R)
12573     {
12574         @property auto back()
12575         {
12576             return (*_range).back;
12577         }
12578 
12579         static if (is(typeof(((const R* r) => (*r).back)(null)))) @property auto back() const
12580         {
12581             return (*_range).back;
12582         }
12583 
12584         static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
12585         {
12586             return (*_range).back = value;
12587         }
12588     }
12589 
12590 
12591     /++ Ditto +/
12592     static if (isBidirectionalRange!R) void popBack()
12593     {
12594         return (*_range).popBack();
12595     }
12596 
12597 
12598     version (StdDdoc)
12599     {
12600         /++
12601             Only defined if `isRandomAccessRange!R` is `true`.
12602           +/
12603         auto ref opIndex(IndexType)(IndexType index) {assert(0);}
12604 
12605         /++ Ditto +/
12606         auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
12607     }
12608     else static if (isRandomAccessRange!R)
12609     {
12610         auto ref opIndex(IndexType)(IndexType index)
12611         if (is(typeof((*_range)[index])))
12612         {
12613             return (*_range)[index];
12614         }
12615 
12616         auto ref opIndex(IndexType)(IndexType index) const
12617         if (is(typeof((*cast(const R*)_range)[index])))
12618         {
12619             return (*_range)[index];
12620         }
12621     }
12622 
12623 
12624     /++
12625         Only defined if `hasMobileElements!R` and `isForwardRange!R` are
12626         `true`.
12627       +/
12628     static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
12629     {
12630         return (*_range).moveFront();
12631     }
12632 
12633 
12634     /++
12635         Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
12636         are `true`.
12637       +/
12638     static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
12639     {
12640         return (*_range).moveBack();
12641     }
12642 
12643 
12644     /++
12645         Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
12646         are `true`.
12647       +/
12648     static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
12649     {
12650         return (*_range).moveAt(index);
12651     }
12652 
12653 
12654     version (StdDdoc)
12655     {
12656         /// Only defined if `hasLength!R` is `true`.
12657         @property size_t length();
12658         /// ditto
12659         @property size_t length() const;
12660         /// Ditto
12661         alias opDollar = length;
12662     }
12663     else static if (hasLength!R)
12664     {
12665         @property auto length()
12666         {
12667             return (*_range).length;
12668         }
12669         static if (is(typeof(((const R* r) => (*r).length)(null)))) @property auto length() const
12670         {
12671             return (*_range).length;
12672         }
12673         alias opDollar = length;
12674     }
12675 
12676 
12677     version (StdDdoc)
12678     {
12679         /++
12680             Only defined if `hasSlicing!R` is `true`.
12681           +/
12682         auto opSlice(IndexType1, IndexType2)
12683                     (IndexType1 begin, IndexType2 end) {assert(0);}
12684 
12685         /++ Ditto +/
12686         auto opSlice(IndexType1, IndexType2)
12687                     (IndexType1 begin, IndexType2 end) const {assert(0);}
12688     }
12689     else static if (hasSlicing!R)
12690     {
12691         private alias T = typeof((*_range)[1 .. 2]);
12692         static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
12693         {
12694             private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
12695         }
12696 
12697         RefRange!T opSlice(IndexType1, IndexType2)
12698                     (IndexType1 begin, IndexType2 end)
12699         if (is(typeof((*_range)[begin .. end])))
12700         {
12701             mixin(_genOpSlice());
12702         }
12703 
12704         RefRange!CT opSlice(IndexType1, IndexType2)
12705                     (IndexType1 begin, IndexType2 end) const
12706         if (is(typeof((*cast(const R*)_range)[begin .. end])))
12707         {
12708             mixin(_genOpSlice());
12709         }
12710 
12711         private static string _genOpSlice() @safe pure nothrow
12712         {
12713             return `import core.lifetime : emplace;` ~
12714                    `alias S = typeof((*_range)[begin .. end]);` ~
12715                    `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
12716                    `auto mem = new void[S.sizeof];` ~
12717                    `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
12718                    `return RefRange!S(cast(S*) mem.ptr);`;
12719         }
12720     }
12721 
12722 
12723 private:
12724 
12725     R* _range;
12726 }
12727 
12728 /// Basic Example
12729 @system unittest
12730 {
12731     import std.algorithm.searching : find;
12732     ubyte[] buffer = [1, 9, 45, 12, 22];
12733     auto found1 = find(buffer, 45);
12734     assert(found1 == [45, 12, 22]);
12735     assert(buffer == [1, 9, 45, 12, 22]);
12736 
12737     auto wrapped1 = refRange(&buffer);
12738     auto found2 = find(wrapped1, 45);
12739     assert(*found2.ptr == [45, 12, 22]);
12740     assert(buffer == [45, 12, 22]);
12741 
12742     auto found3 = find(wrapped1.save, 22);
12743     assert(*found3.ptr == [22]);
12744     assert(buffer == [45, 12, 22]);
12745 
12746     string str = "hello world";
12747     auto wrappedStr = refRange(&str);
12748     assert(str.front == 'h');
12749     str.popFrontN(5);
12750     assert(str == " world");
12751     assert(wrappedStr.front == ' ');
12752     assert(*wrappedStr.ptr == " world");
12753 }
12754 
12755 /// opAssign Example.
12756 @system unittest
12757 {
12758     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12759     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12760     auto wrapped1 = refRange(&buffer1);
12761     auto wrapped2 = refRange(&buffer2);
12762     assert(wrapped1.ptr is &buffer1);
12763     assert(wrapped2.ptr is &buffer2);
12764     assert(wrapped1.ptr !is wrapped2.ptr);
12765     assert(buffer1 != buffer2);
12766 
12767     wrapped1 = wrapped2;
12768 
12769     //Everything points to the same stuff as before.
12770     assert(wrapped1.ptr is &buffer1);
12771     assert(wrapped2.ptr is &buffer2);
12772     assert(wrapped1.ptr !is wrapped2.ptr);
12773 
12774     //But buffer1 has changed due to the assignment.
12775     assert(buffer1 == [6, 7, 8, 9, 10]);
12776     assert(buffer2 == [6, 7, 8, 9, 10]);
12777 
12778     buffer2 = [11, 12, 13, 14, 15];
12779 
12780     //Everything points to the same stuff as before.
12781     assert(wrapped1.ptr is &buffer1);
12782     assert(wrapped2.ptr is &buffer2);
12783     assert(wrapped1.ptr !is wrapped2.ptr);
12784 
12785     //But buffer2 has changed due to the assignment.
12786     assert(buffer1 == [6, 7, 8, 9, 10]);
12787     assert(buffer2 == [11, 12, 13, 14, 15]);
12788 
12789     wrapped2 = null;
12790 
12791     //The pointer changed for wrapped2 but not wrapped1.
12792     assert(wrapped1.ptr is &buffer1);
12793     assert(wrapped2.ptr is null);
12794     assert(wrapped1.ptr !is wrapped2.ptr);
12795 
12796     //buffer2 is not affected by the assignment.
12797     assert(buffer1 == [6, 7, 8, 9, 10]);
12798     assert(buffer2 == [11, 12, 13, 14, 15]);
12799 }
12800 
12801 @system unittest
12802 {
12803     import std.algorithm.iteration : filter;
12804     {
12805         ubyte[] buffer = [1, 2, 3, 4, 5];
12806         auto wrapper = refRange(&buffer);
12807         auto p = wrapper.ptr;
12808         auto f = wrapper.front;
12809         wrapper.front = f;
12810         auto e = wrapper.empty;
12811         wrapper.popFront();
12812         auto s = wrapper.save;
12813         auto b = wrapper.back;
12814         wrapper.back = b;
12815         wrapper.popBack();
12816         auto i = wrapper[0];
12817         wrapper.moveFront();
12818         wrapper.moveBack();
12819         wrapper.moveAt(0);
12820         auto l = wrapper.length;
12821         auto sl = wrapper[0 .. 1];
12822         assert(wrapper[0 .. $].length == buffer[0 .. $].length);
12823     }
12824 
12825     {
12826         ubyte[] buffer = [1, 2, 3, 4, 5];
12827         const wrapper = refRange(&buffer);
12828         const p = wrapper.ptr;
12829         const f = wrapper.front;
12830         const e = wrapper.empty;
12831         const s = wrapper.save;
12832         const b = wrapper.back;
12833         const i = wrapper[0];
12834         const l = wrapper.length;
12835         const sl = wrapper[0 .. 1];
12836     }
12837 
12838     {
12839         ubyte[] buffer = [1, 2, 3, 4, 5];
12840         auto filtered = filter!"true"(buffer);
12841         auto wrapper = refRange(&filtered);
12842         auto p = wrapper.ptr;
12843         auto f = wrapper.front;
12844         wrapper.front = f;
12845         auto e = wrapper.empty;
12846         wrapper.popFront();
12847         auto s = wrapper.save;
12848         wrapper.moveFront();
12849     }
12850 
12851     {
12852         ubyte[] buffer = [1, 2, 3, 4, 5];
12853         auto filtered = filter!"true"(buffer);
12854         const wrapper = refRange(&filtered);
12855         const p = wrapper.ptr;
12856 
12857         //Cannot currently be const. filter needs to be updated to handle const.
12858         /+
12859         const f = wrapper.front;
12860         const e = wrapper.empty;
12861         const s = wrapper.save;
12862         +/
12863     }
12864 
12865     {
12866         string str = "hello world";
12867         auto wrapper = refRange(&str);
12868         auto p = wrapper.ptr;
12869         auto f = wrapper.front;
12870         auto e = wrapper.empty;
12871         wrapper.popFront();
12872         auto s = wrapper.save;
12873         auto b = wrapper.back;
12874         wrapper.popBack();
12875     }
12876 
12877     {
12878         // https://issues.dlang.org/show_bug.cgi?id=16534
12879         // opDollar should be defined if the wrapped range defines length.
12880         auto range = 10.iota.takeExactly(5);
12881         auto wrapper = refRange(&range);
12882         assert(wrapper.length == 5);
12883         assert(wrapper[0 .. $ - 1].length == 4);
12884     }
12885 }
12886 
12887 //Test assignment.
12888 @system unittest
12889 {
12890     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12891     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12892     RefRange!(ubyte[]) wrapper1;
12893     RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
12894     assert(wrapper1.ptr is null);
12895     assert(wrapper2.ptr is &buffer2);
12896 
12897     wrapper1 = refRange(&buffer1);
12898     assert(wrapper1.ptr is &buffer1);
12899 
12900     wrapper1 = wrapper2;
12901     assert(wrapper1.ptr is &buffer1);
12902     assert(buffer1 == buffer2);
12903 
12904     wrapper1 = RefRange!(ubyte[]).init;
12905     assert(wrapper1.ptr is null);
12906     assert(wrapper2.ptr is &buffer2);
12907     assert(buffer1 == buffer2);
12908     assert(buffer1 == [6, 7, 8, 9, 10]);
12909 
12910     wrapper2 = null;
12911     assert(wrapper2.ptr is null);
12912     assert(buffer2 == [6, 7, 8, 9, 10]);
12913 }
12914 
12915 @system unittest
12916 {
12917     import std.algorithm.comparison : equal;
12918     import std.algorithm.mutation : bringToFront;
12919     import std.algorithm.searching : commonPrefix, find, until;
12920     import std.algorithm.sorting : sort;
12921 
12922     //Test that ranges are properly consumed.
12923     {
12924         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12925         auto wrapper = refRange(&arr);
12926 
12927         assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12928         assert(arr == [41, 3, 40, 4, 42, 9]);
12929 
12930         assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12931         assert(arr == [40, 4, 42, 9]);
12932 
12933         assert(equal(until(wrapper, 42), [40, 4]));
12934         assert(arr == [42, 9]);
12935 
12936         assert(find(wrapper, 12).empty);
12937         assert(arr.empty);
12938     }
12939 
12940     {
12941         string str = "Hello, world-like object.";
12942         auto wrapper = refRange(&str);
12943 
12944         assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12945         assert(str == "llo, world-like object.");
12946 
12947         assert(equal(take(wrapper, 5), "llo, "));
12948         assert(str == "world-like object.");
12949     }
12950 
12951     //Test that operating on saved ranges does not consume the original.
12952     {
12953         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12954         auto wrapper = refRange(&arr);
12955         auto saved = wrapper.save;
12956         saved.popFrontN(3);
12957         assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12958         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12959     }
12960 
12961     {
12962         string str = "Hello, world-like object.";
12963         auto wrapper = refRange(&str);
12964         auto saved = wrapper.save;
12965         saved.popFrontN(13);
12966         assert(*saved.ptr == "like object.");
12967         assert(str == "Hello, world-like object.");
12968     }
12969 
12970     //Test that functions which use save work properly.
12971     {
12972         int[] arr = [1, 42];
12973         auto wrapper = refRange(&arr);
12974         assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12975     }
12976 
12977     {
12978         int[] arr = [4, 5, 6, 7, 1, 2, 3];
12979         auto wrapper = refRange(&arr);
12980         assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12981         assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12982     }
12983 
12984     //Test bidirectional functions.
12985     {
12986         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12987         auto wrapper = refRange(&arr);
12988 
12989         assert(wrapper.back == 9);
12990         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12991 
12992         wrapper.popBack();
12993         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12994     }
12995 
12996     {
12997         string str = "Hello, world-like object.";
12998         auto wrapper = refRange(&str);
12999 
13000         assert(wrapper.back == '.');
13001         assert(str == "Hello, world-like object.");
13002 
13003         wrapper.popBack();
13004         assert(str == "Hello, world-like object");
13005     }
13006 
13007     //Test random access functions.
13008     {
13009         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
13010         auto wrapper = refRange(&arr);
13011 
13012         assert(wrapper[2] == 2);
13013         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
13014 
13015         assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
13016         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
13017     }
13018 
13019     //Test move functions.
13020     {
13021         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
13022         auto wrapper = refRange(&arr);
13023 
13024         auto t1 = wrapper.moveFront();
13025         auto t2 = wrapper.moveBack();
13026         wrapper.front = t2;
13027         wrapper.back = t1;
13028         assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
13029 
13030         sort(wrapper.save);
13031         assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
13032     }
13033 }
13034 
13035 @system unittest
13036 {
13037     struct S
13038     {
13039         @property int front() @safe const pure nothrow { return 0; }
13040         enum bool empty = false;
13041         void popFront() @safe pure nothrow { }
13042         @property auto save() @safe pure nothrow return scope { return this; }
13043     }
13044 
13045     S s;
13046     auto wrapper = refRange(&s);
13047     static assert(isInfinite!(typeof(wrapper)));
13048 }
13049 
13050 @system unittest
13051 {
13052     class C
13053     {
13054         @property int front() @safe const pure nothrow { return 0; }
13055         @property bool empty() @safe const pure nothrow { return false; }
13056         void popFront() @safe pure nothrow { }
13057         @property auto save() @safe pure nothrow return scope { return this; }
13058     }
13059     static assert(isForwardRange!C);
13060 
13061     auto c = new C;
13062     auto cWrapper = refRange(&c);
13063     static assert(is(typeof(cWrapper) == C));
13064     assert(cWrapper is c);
13065 }
13066 
13067 // https://issues.dlang.org/show_bug.cgi?id=14373
13068 @system unittest
13069 {
13070     static struct R
13071     {
13072         @property int front() {return 0;}
13073         void popFront() {empty = true;}
13074         bool empty = false;
13075     }
13076     R r;
13077     refRange(&r).popFront();
13078     assert(r.empty);
13079 }
13080 
13081 // https://issues.dlang.org/show_bug.cgi?id=14575
13082 @system unittest
13083 {
13084     struct R
13085     {
13086         Object front;
13087         alias back = front;
13088         bool empty = false;
13089         void popFront() {empty = true;}
13090         alias popBack = popFront;
13091         @property R save() {return this;}
13092     }
13093     static assert(isBidirectionalRange!R);
13094     R r;
13095     auto rr = refRange(&r);
13096 
13097     struct R2
13098     {
13099         @property Object front() {return null;}
13100         @property const(Object) front() const {return null;}
13101         alias back = front;
13102         bool empty = false;
13103         void popFront() {empty = true;}
13104         alias popBack = popFront;
13105         @property R2 save() {return this;}
13106     }
13107     static assert(isBidirectionalRange!R2);
13108     R2 r2;
13109     auto rr2 = refRange(&r2);
13110 }
13111 
13112 // https://issues.dlang.org/show_bug.cgi?id=24801
13113 @safe unittest
13114 {
13115 
13116     {
13117         static struct R
13118         {
13119             int front() => 0;
13120             void popFront() {}
13121             bool empty() => false;
13122         }
13123         R range;
13124         auto r = RefRange!R(&range);
13125     }
13126 
13127     {
13128         static struct R
13129         {
13130             size_t start, end;
13131             size_t length() => end - start;
13132             int opIndex(size_t i) => 0;
13133 
13134 
13135             int front() => this[0];
13136             int back() => this[length-1];
13137             void popFront() { start++; }
13138             void popBack() { end--; }
13139             bool empty() => length == 0;
13140             R save() const => R();
13141         }
13142 
13143         R range;
13144         auto r = RefRange!R(&range);
13145     }
13146 
13147 
13148 }
13149 
13150 /// ditto
13151 auto refRange(R)(R* range)
13152 if (isInputRange!R)
13153 {
13154     static if (!is(R == class))
13155         return RefRange!R(range);
13156     else
13157         return *range;
13158 }
13159 
13160 // https://issues.dlang.org/show_bug.cgi?id=9060
13161 @safe unittest
13162 {
13163     import std.algorithm.iteration : map, joiner, group;
13164     import std.algorithm.searching : until;
13165     // fix for std.algorithm
13166     auto r = map!(x => 0)([1]);
13167     chain(r, r);
13168     zip(r, r);
13169     roundRobin(r, r);
13170 
13171     struct NRAR {
13172         typeof(r) input;
13173         @property empty() { return input.empty; }
13174         @property front() { return input.front; }
13175         void popFront()   { input.popFront(); }
13176         @property save()  { return NRAR(input.save); }
13177     }
13178     auto n1 = NRAR(r);
13179     cycle(n1);  // non random access range version
13180 
13181     assumeSorted(r);
13182 
13183     // fix for std.range
13184     joiner([r], [9]);
13185 
13186     struct NRAR2 {
13187         NRAR input;
13188         @property empty() { return true; }
13189         @property front() { return input; }
13190         void popFront() { }
13191         @property save()  { return NRAR2(input.save); }
13192     }
13193     auto n2 = NRAR2(n1);
13194     joiner(n2);
13195 
13196     group(r);
13197 
13198     until(r, 7);
13199     static void foo(R)(R r) { until!(x => x > 7)(r); }
13200     foo(r);
13201 }
13202 
13203 private struct Bitwise(R)
13204 if (isInputRange!R && isIntegral!(ElementType!R))
13205 {
13206     import std.traits : Unsigned;
13207 private:
13208     alias ElemType = ElementType!R;
13209     alias UnsignedElemType = Unsigned!ElemType;
13210 
13211     R parent;
13212     enum bitsNum = ElemType.sizeof * 8;
13213     size_t maskPos = 1;
13214 
13215     static if (isBidirectionalRange!R)
13216     {
13217         size_t backMaskPos = bitsNum;
13218     }
13219 
13220 public:
13221     this()(auto ref R range)
13222     {
13223         parent = range;
13224     }
13225 
13226     static if (isInfinite!R)
13227     {
13228         enum empty = false;
13229     }
13230     else
13231     {
13232         /**
13233          * Check if the range is empty
13234          *
13235          * Returns: a boolean true or false
13236          */
13237         bool empty()
13238         {
13239             static if (hasLength!R)
13240             {
13241                 return length == 0;
13242             }
13243             else static if (isBidirectionalRange!R)
13244             {
13245                 if (parent.empty)
13246                 {
13247                     return true;
13248                 }
13249                 else
13250                 {
13251                     /*
13252                        If we have consumed the last element of the range both from
13253                        the front and the back, then the masks positions will overlap
13254                      */
13255                     return parent.save.dropOne.empty && (maskPos > backMaskPos);
13256                 }
13257             }
13258             else
13259             {
13260                 /*
13261                    If we consumed the last element of the range, but not all the
13262                    bits in the last element
13263                  */
13264                 return parent.empty;
13265             }
13266         }
13267     }
13268 
13269     bool front()
13270     {
13271         assert(!empty);
13272         return (parent.front & mask(maskPos)) != 0;
13273     }
13274 
13275     void popFront()
13276     {
13277         assert(!empty);
13278         ++maskPos;
13279         if (maskPos > bitsNum)
13280         {
13281             parent.popFront;
13282             maskPos = 1;
13283         }
13284     }
13285 
13286     static if (hasLength!R)
13287     {
13288         size_t length()
13289         {
13290             auto len = parent.length * bitsNum - (maskPos - 1);
13291             static if (isBidirectionalRange!R)
13292             {
13293                 len -= bitsNum - backMaskPos;
13294             }
13295             return len;
13296         }
13297 
13298         alias opDollar = length;
13299     }
13300 
13301     static if (isForwardRange!R)
13302     {
13303         typeof(this) save()
13304         {
13305             auto result = this;
13306             result.parent = parent.save;
13307             return result;
13308         }
13309     }
13310 
13311     static if (isBidirectionalRange!R)
13312     {
13313         bool back()
13314         {
13315             assert(!empty);
13316             return (parent.back & mask(backMaskPos)) != 0;
13317         }
13318 
13319         void popBack()
13320         {
13321             assert(!empty);
13322             --backMaskPos;
13323             if (backMaskPos == 0)
13324             {
13325                 parent.popBack;
13326                 backMaskPos = bitsNum;
13327             }
13328         }
13329     }
13330 
13331     static if (isRandomAccessRange!R)
13332     {
13333         /**
13334           Return the `n`th bit within the range
13335          */
13336         bool opIndex(size_t n)
13337         in
13338         {
13339             /*
13340                If it does not have the length property, it means that R is
13341                an infinite range
13342              */
13343             static if (hasLength!R)
13344             {
13345                 assert(n < length, "Index out of bounds");
13346             }
13347         }
13348         do
13349         {
13350             immutable size_t remainingBits = bitsNum - maskPos + 1;
13351             // If n >= maskPos, then the bit sign will be 1, otherwise 0
13352             immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13353             /*
13354                By truncating n with remainingBits bits we have skipped the
13355                remaining bits in parent[0], so we need to add 1 to elemIndex.
13356 
13357                Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
13358              */
13359             import core.bitop : bsf;
13360             immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
13361 
13362             /*
13363                Since the indexing is from LSB to MSB, we need to index at the
13364                remainder of (n - remainingBits).
13365 
13366                Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
13367              */
13368             immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
13369                              + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
13370 
13371             return (parent[elemIndex] & mask(elemMaskPos)) != 0;
13372         }
13373 
13374         static if (hasAssignableElements!R)
13375         {
13376             /**
13377               Assigns `flag` to the `n`th bit within the range
13378              */
13379             void opIndexAssign(bool flag, size_t n)
13380                 in
13381                 {
13382                     static if (hasLength!R)
13383                     {
13384                         assert(n < length, "Index out of bounds");
13385                     }
13386                 }
13387             do
13388             {
13389                 import core.bitop : bsf;
13390 
13391                 immutable size_t remainingBits = bitsNum - maskPos + 1;
13392                 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13393                 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
13394                 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
13395                     + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
13396 
13397                 auto elem = parent[elemIndex];
13398                 auto elemMask = mask(elemMaskPos);
13399                 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
13400                         + (flag ^ 1) * (elem & ~elemMask));
13401             }
13402         }
13403 
13404         Bitwise!R opSlice()
13405         {
13406             return this.save;
13407         }
13408 
13409         Bitwise!R opSlice(size_t start, size_t end)
13410         in
13411         {
13412             assert(start < end, "Invalid bounds: end <= start");
13413         }
13414         do
13415         {
13416             import core.bitop : bsf;
13417 
13418             size_t remainingBits = bitsNum - maskPos + 1;
13419             ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13420             immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
13421             immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
13422                                               + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
13423 
13424             immutable size_t sliceLen = end - start - 1;
13425             remainingBits = bitsNum - startElemMaskPos + 1;
13426             sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13427             immutable size_t endElemIndex = startElemIndex
13428                                           + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
13429             immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
13430                                             + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
13431 
13432             typeof(return) result;
13433             // Get the slice to be returned from the parent
13434             result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
13435             result.maskPos = startElemMaskPos;
13436             static if (isBidirectionalRange!R)
13437             {
13438                 result.backMaskPos = endElemMaskPos;
13439             }
13440             return result;
13441         }
13442     }
13443 
13444 private:
13445     auto mask(size_t maskPos)
13446     {
13447         return (1UL << (maskPos - 1UL));
13448     }
13449 }
13450 
13451 /**
13452 Bitwise adapter over an integral type range. Consumes the range elements bit by
13453 bit, from the least significant bit to the most significant bit.
13454 
13455 Params:
13456     R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
13457     range = range to consume bit by by
13458 
13459 Returns:
13460     A `Bitwise` input range with propagated forward, bidirectional
13461     and random access capabilities
13462 */
13463 auto bitwise(R)(auto ref R range)
13464 if (isInputRange!R && isIntegral!(ElementType!R))
13465 {
13466     return Bitwise!R(range);
13467 }
13468 
13469 ///
13470 @safe pure unittest
13471 {
13472     import std.algorithm.comparison : equal;
13473     import std.format : format;
13474 
13475     // 00000011 00001001
13476     ubyte[] arr = [3, 9];
13477     auto r = arr.bitwise;
13478 
13479     // iterate through it as with any other range
13480     assert(format("%(%d%)", r) == "1100000010010000");
13481     assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
13482 
13483     auto r2 = r[5 .. $];
13484     // set a bit
13485     r[2] = 1;
13486     assert(arr[0] == 7);
13487     assert(r[5] == r2[0]);
13488 }
13489 
13490 /// You can use bitwise to implement an uniform bool generator
13491 @safe unittest
13492 {
13493     import std.algorithm.comparison : equal;
13494     import std.random : rndGen;
13495 
13496     auto rb = rndGen.bitwise;
13497     static assert(isInfinite!(typeof(rb)));
13498 
13499     auto rb2 = rndGen.bitwise;
13500     // Don't forget that structs are passed by value
13501     assert(rb.take(10).equal(rb2.take(10)));
13502 }
13503 
13504 // Test nogc inference
13505 @safe @nogc unittest
13506 {
13507     static ubyte[] arr = [3, 9];
13508     auto bw = arr.bitwise;
13509     auto bw2 = bw[];
13510     auto bw3 = bw[8 .. $];
13511     bw3[2] = true;
13512 
13513     assert(arr[1] == 13);
13514     assert(bw[$ - 6]);
13515     assert(bw[$ - 6] == bw2[$ - 6]);
13516     assert(bw[$ - 6] == bw3[$ - 6]);
13517 }
13518 
13519 // Test all range types over all integral types
13520 @safe pure nothrow unittest
13521 {
13522     import std.meta : AliasSeq;
13523     import std.internal.test.dummyrange;
13524 
13525     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13526             long, ulong);
13527     foreach (IntegralType; IntegralTypes)
13528     {
13529         foreach (T; AllDummyRangesType!(IntegralType[]))
13530         {
13531             T a;
13532             auto bw = Bitwise!T(a);
13533 
13534             static if (isForwardRange!T)
13535             {
13536                 auto bwFwdSave = bw.save;
13537             }
13538 
13539             static if (isBidirectionalRange!T)
13540             {
13541                 auto bwBack = bw.save;
13542                 auto bwBackSave = bw.save;
13543             }
13544 
13545             static if (hasLength!T)
13546             {
13547                 auto bwLength = bw.length;
13548                 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
13549                 static if (isForwardRange!T)
13550                 {
13551                     assert(bw.length == bwFwdSave.length);
13552                 }
13553             }
13554 
13555             // Make sure front and back are not the mechanisms that modify the range
13556             long numCalls = 42;
13557             bool initialFrontValue;
13558 
13559             if (!bw.empty)
13560             {
13561                 initialFrontValue = bw.front;
13562             }
13563 
13564             while (!bw.empty && (--numCalls))
13565             {
13566                 bw.front;
13567                 assert(bw.front == initialFrontValue);
13568             }
13569 
13570             /*
13571                Check that empty works properly and that popFront does not get called
13572                more times than it should
13573              */
13574             numCalls = 0;
13575             while (!bw.empty)
13576             {
13577                 ++numCalls;
13578 
13579                 static if (hasLength!T)
13580                 {
13581                     assert(bw.length == bwLength);
13582                     --bwLength;
13583                 }
13584 
13585                 static if (isForwardRange!T)
13586                 {
13587                     assert(bw.front == bwFwdSave.front);
13588                     bwFwdSave.popFront();
13589                 }
13590 
13591                 static if (isBidirectionalRange!T)
13592                 {
13593                     assert(bwBack.front == bwBackSave.front);
13594                     bwBack.popBack();
13595                     bwBackSave.popBack();
13596                 }
13597                 bw.popFront();
13598             }
13599 
13600             auto rangeLen = numCalls / (IntegralType.sizeof * 8);
13601             assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
13602             assert(bw.empty);
13603             static if (isForwardRange!T)
13604             {
13605                 assert(bwFwdSave.empty);
13606             }
13607 
13608             static if (isBidirectionalRange!T)
13609             {
13610                 assert(bwBack.empty);
13611             }
13612         }
13613     }
13614 }
13615 
13616 // Test opIndex and opSlice
13617 @system unittest
13618 {
13619     import std.meta : AliasSeq;
13620     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13621             long, ulong);
13622     foreach (IntegralType; IntegralTypes)
13623     {
13624         size_t bitsNum = IntegralType.sizeof * 8;
13625 
13626         auto first = IntegralType(1);
13627 
13628         // 2 ^ (bitsNum - 1)
13629         auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2));
13630 
13631         IntegralType[] a = [first, second];
13632         auto bw = Bitwise!(IntegralType[])(a);
13633 
13634         // Check against lsb of a[0]
13635         assert(bw[0] == true);
13636         // Check against msb - 1 of a[1]
13637         assert(bw[2 * bitsNum - 2] == true);
13638 
13639         bw.popFront();
13640         assert(bw[2 * bitsNum - 3] == true);
13641 
13642         import std.exception : assertThrown;
13643 
13644         version (D_NoBoundsChecks) {}
13645         else
13646         {
13647             // Check out of bounds error
13648             assertThrown!Error(bw[2 * bitsNum - 1]);
13649         }
13650 
13651         bw[2] = true;
13652         assert(bw[2] == true);
13653         bw.popFront();
13654         assert(bw[1] == true);
13655 
13656         auto bw2 = bw[0 .. $ - 5];
13657         auto bw3 = bw2[];
13658         assert(bw2.length == bw.length - 5);
13659         assert(bw2.length == bw3.length);
13660         bw2.popFront();
13661         assert(bw2.length != bw3.length);
13662     }
13663 }
13664 
13665 /*********************************
13666  * An OutputRange that discards the data it receives.
13667  */
13668 struct NullSink
13669 {
13670     void put(E)(scope const E) pure @safe @nogc nothrow {}
13671 }
13672 
13673 /// ditto
13674 auto ref nullSink()
13675 {
13676     static NullSink sink;
13677     return sink;
13678 }
13679 
13680 ///
13681 @safe nothrow unittest
13682 {
13683     import std.algorithm.iteration : map;
13684     import std.algorithm.mutation : copy;
13685     [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
13686 }
13687 
13688 ///
13689 @safe unittest
13690 {
13691     import std.csv : csvNextToken;
13692 
13693     string line = "a,b,c";
13694 
13695     // ignore the first column
13696     line.csvNextToken(nullSink, ',', '"');
13697     line.popFront;
13698 
13699     // look at the second column
13700     Appender!string app;
13701     line.csvNextToken(app, ',', '"');
13702     assert(app.data == "b");
13703 }
13704 
13705 @safe unittest
13706 {
13707     auto r = 10.iota
13708                 .tee(nullSink)
13709                 .dropOne;
13710 
13711     assert(r.front == 1);
13712 }
13713 
13714 /++
13715 
13716   Implements a "tee" style pipe, wrapping an input range so that elements of the
13717   range can be passed to a provided function or $(LREF OutputRange) as they are
13718   iterated over. This is useful for printing out intermediate values in a long
13719   chain of range code, performing some operation with side-effects on each call
13720   to `front` or `popFront`, or diverting the elements of a range into an
13721   auxiliary $(LREF OutputRange).
13722 
13723   It is important to note that as the resultant range is evaluated lazily,
13724   in the case of the version of `tee` that takes a function, the function
13725   will not actually be executed until the range is "walked" using functions
13726   that evaluate ranges, such as $(REF array, std,array) or
13727   $(REF fold, std,algorithm,iteration).
13728 
13729   Params:
13730   pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
13731   calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
13732   respectively, `fun`). Note that each `popFront()` call will mirror the
13733   old `front` value, not the new one. This means that the last value will
13734   not be forwarded if the range isn't iterated until empty. If
13735   `No.pipeOnPop`, only elements for which `front` does get called will be
13736   also sent to `outputRange`/`fun`. If `front` is called twice for the same
13737   element, it will still be sent only once. If this caching is undesired,
13738   consider using $(REF map, std,algorithm,iteration) instead.
13739   inputRange = The input range being passed through.
13740   outputRange = This range will receive elements of `inputRange` progressively
13741   as iteration proceeds.
13742   fun = This function will be called with elements of `inputRange`
13743   progressively as iteration proceeds.
13744 
13745   Returns:
13746   An input range that offers the elements of `inputRange`. Regardless of
13747   whether `inputRange` is a more powerful range (forward, bidirectional etc),
13748   the result is always an input range. Reading this causes `inputRange` to be
13749   iterated and returns its elements in turn. In addition, the same elements
13750   will be passed to `outputRange` or `fun` as well.
13751 
13752   See_Also: $(REF each, std,algorithm,iteration)
13753 +/
13754 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
13755 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
13756 {
13757     static struct Result
13758     {
13759         private R1 _input;
13760         private R2 _output;
13761         static if (!pipeOnPop)
13762         {
13763             private bool _frontAccessed;
13764         }
13765 
13766         mixin ImplementLength!_input;
13767 
13768         static if (isInfinite!R1)
13769         {
13770             enum bool empty = false;
13771         }
13772         else
13773         {
13774             @property bool empty() { return _input.empty; }
13775         }
13776 
13777         void popFront()
13778         {
13779             assert(!_input.empty, "Attempting to popFront an empty tee");
13780             static if (pipeOnPop)
13781             {
13782                 put(_output, _input.front);
13783             }
13784             else
13785             {
13786                 _frontAccessed = false;
13787             }
13788             _input.popFront();
13789         }
13790 
13791         @property auto ref front()
13792         {
13793             assert(!_input.empty, "Attempting to fetch the front of an empty tee");
13794             static if (!pipeOnPop)
13795             {
13796                 if (!_frontAccessed)
13797                 {
13798                     _frontAccessed = true;
13799                     put(_output, _input.front);
13800                 }
13801             }
13802             return _input.front;
13803         }
13804     }
13805 
13806     return Result(inputRange, outputRange);
13807 }
13808 
13809 /// Ditto
13810 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
13811 if (is(typeof(fun) == void) || isSomeFunction!fun)
13812 {
13813     import std.traits : isDelegate, isFunctionPointer;
13814     /*
13815         Distinguish between function literals and template lambdas
13816         when using either as an $(LREF OutputRange). Since a template
13817         has no type, typeof(template) will always return void.
13818         If it's a template lambda, it's first necessary to instantiate
13819         it with `ElementType!R1`.
13820     */
13821     static if (is(typeof(fun) == void))
13822         alias _fun = fun!(ElementType!R1);
13823     else
13824         alias _fun = fun;
13825 
13826     static if (isFunctionPointer!_fun || isDelegate!_fun)
13827     {
13828         return tee!pipeOnPop(inputRange, _fun);
13829     }
13830     else
13831     {
13832         return tee!pipeOnPop(inputRange, &_fun);
13833     }
13834 }
13835 
13836 ///
13837 @safe unittest
13838 {
13839     import std.algorithm.comparison : equal;
13840     import std.algorithm.iteration : filter, map;
13841 
13842     // Sum values while copying
13843     int[] values = [1, 4, 9, 16, 25];
13844     int sum = 0;
13845     auto newValues = values.tee!(a => sum += a).array;
13846     assert(equal(newValues, values));
13847     assert(sum == 1 + 4 + 9 + 16 + 25);
13848 
13849     // Count values that pass the first filter
13850     int count = 0;
13851     auto newValues4 = values.filter!(a => a < 10)
13852                             .tee!(a => count++)
13853                             .map!(a => a + 1)
13854                             .filter!(a => a < 10);
13855 
13856     //Fine, equal also evaluates any lazy ranges passed to it.
13857     //count is not 3 until equal evaluates newValues4
13858     assert(equal(newValues4, [2, 5]));
13859     assert(count == 3);
13860 }
13861 
13862 //
13863 @safe unittest
13864 {
13865     import std.algorithm.comparison : equal;
13866     import std.algorithm.iteration : filter, map;
13867 
13868     int[] values = [1, 4, 9, 16, 25];
13869 
13870     int count = 0;
13871     auto newValues = values.filter!(a => a < 10)
13872         .tee!(a => count++, No.pipeOnPop)
13873         .map!(a => a + 1)
13874         .filter!(a => a < 10);
13875 
13876     auto val = newValues.front;
13877     assert(count == 1);
13878     //front is only evaluated once per element
13879     val = newValues.front;
13880     assert(count == 1);
13881 
13882     //popFront() called, fun will be called
13883     //again on the next access to front
13884     newValues.popFront();
13885     newValues.front;
13886     assert(count == 2);
13887 
13888     int[] preMap = new int[](3), postMap = [];
13889     auto mappedValues = values.filter!(a => a < 10)
13890         //Note the two different ways of using tee
13891         .tee(preMap)
13892         .map!(a => a + 1)
13893         .tee!(a => postMap ~= a)
13894         .filter!(a => a < 10);
13895     assert(equal(mappedValues, [2, 5]));
13896     assert(equal(preMap, [1, 4, 9]));
13897     assert(equal(postMap, [2, 5, 10]));
13898 }
13899 
13900 //
13901 @safe unittest
13902 {
13903     import std.algorithm.comparison : equal;
13904     import std.algorithm.iteration : filter, map;
13905 
13906     char[] txt = "Line one, Line 2".dup;
13907 
13908     bool isVowel(dchar c)
13909     {
13910         import std.string : indexOf;
13911         return "AaEeIiOoUu".indexOf(c) != -1;
13912     }
13913 
13914     int vowelCount = 0;
13915     int shiftedCount = 0;
13916     auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
13917                                 .filter!(c => !isVowel(c))
13918                                 .map!(c => (c == ' ') ? c : c + 1)
13919                                 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
13920     assert(equal(removeVowels, "Mo o- Mo 3"));
13921     assert(vowelCount == 6);
13922     assert(shiftedCount == 3);
13923 }
13924 
13925 @safe unittest
13926 {
13927     // Manually stride to test different pipe behavior.
13928     void testRange(Range)(Range r)
13929     {
13930         const int strideLen = 3;
13931         int i = 0;
13932         ElementType!Range elem1;
13933         ElementType!Range elem2;
13934         while (!r.empty)
13935         {
13936             if (i % strideLen == 0)
13937             {
13938                 //Make sure front is only
13939                 //evaluated once per item
13940                 elem1 = r.front;
13941                 elem2 = r.front;
13942                 assert(elem1 == elem2);
13943             }
13944             r.popFront();
13945             i++;
13946         }
13947     }
13948 
13949     string txt = "abcdefghijklmnopqrstuvwxyz";
13950 
13951     int popCount = 0;
13952     auto pipeOnPop = txt.tee!(a => popCount++);
13953     testRange(pipeOnPop);
13954     assert(popCount == 26);
13955 
13956     int frontCount = 0;
13957     auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13958     testRange(pipeOnFront);
13959     assert(frontCount == 9);
13960 }
13961 
13962 @safe unittest
13963 {
13964     import std.algorithm.comparison : equal;
13965     import std.meta : AliasSeq;
13966 
13967     //Test diverting elements to an OutputRange
13968     string txt = "abcdefghijklmnopqrstuvwxyz";
13969 
13970     dchar[] asink1 = [];
13971     auto fsink = (dchar c) { asink1 ~= c; };
13972     auto result1 = txt.tee(fsink).array;
13973     assert(equal(txt, result1) && (equal(result1, asink1)));
13974 
13975     dchar[] _asink1 = [];
13976     auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13977     assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13978 
13979     dchar[] asink2 = new dchar[](txt.length);
13980     void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13981     auto result2 = txt.tee(&fsink2).array;
13982     assert(equal(txt, result2) && equal(result2, asink2));
13983 
13984     dchar[] asink3 = new dchar[](txt.length);
13985     auto result3 = txt.tee(asink3).array;
13986     assert(equal(txt, result3) && equal(result3, asink3));
13987 
13988     static foreach (CharType; AliasSeq!(char, wchar, dchar))
13989     {{
13990         auto appSink = appender!(CharType[])();
13991         auto appResult = txt.tee(appSink).array;
13992         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13993     }}
13994 
13995     static foreach (StringType; AliasSeq!(string, wstring, dstring))
13996     {{
13997         auto appSink = appender!StringType();
13998         auto appResult = txt.tee(appSink).array;
13999         assert(equal(txt, appResult) && equal(appResult, appSink.data));
14000     }}
14001 }
14002 
14003 // https://issues.dlang.org/show_bug.cgi?id=13483
14004 @safe unittest
14005 {
14006     static void func1(T)(T x) {}
14007     void func2(int x) {}
14008 
14009     auto r = [1, 2, 3, 4].tee!func1.tee!func2;
14010 }
14011 
14012 /**
14013 Extends the length of the input range `r` by padding out the start of the
14014 range with the element `e`. The element `e` must be of a common type with
14015 the element type of the range `r` as defined by $(REF CommonType, std, traits).
14016 If `n` is less than the length of of `r`, then `r` is returned unmodified.
14017 
14018 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
14019 about length for strings, which is not the number of characters, or
14020 graphemes, but instead the number of encoding units. If you want to treat each
14021 grapheme as only one encoding unit long, then call
14022 $(REF byGrapheme, std, uni) before calling this function.
14023 
14024 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
14025 
14026 Params:
14027     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
14028     e = element to pad the range with
14029     n = the length to pad to
14030 
14031 Returns:
14032     A range containing the elements of the original range with the extra padding
14033 
14034 See Also:
14035     $(REF leftJustifier, std, string)
14036 */
14037 auto padLeft(R, E)(R r, E e, size_t n)
14038 if (
14039     ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
14040     !is(CommonType!(ElementType!R, E) == void)
14041 )
14042 {
14043     static if (hasLength!R)
14044         auto dataLength = r.length;
14045     else
14046         auto dataLength = r.save.walkLength(n);
14047 
14048     return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
14049 }
14050 
14051 ///
14052 @safe pure unittest
14053 {
14054     import std.algorithm.comparison : equal;
14055 
14056     assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
14057     assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
14058 
14059     assert("abc".padLeft('_', 6).equal("___abc"));
14060 }
14061 
14062 @safe pure nothrow unittest
14063 {
14064     import std.algorithm.comparison : equal;
14065     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
14066     import std.meta : AliasSeq;
14067 
14068     alias DummyRanges = AliasSeq!(
14069         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
14070         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
14071         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
14072         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
14073         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
14074         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
14075         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
14076         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
14077         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
14078         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
14079     );
14080 
14081     foreach (Range; DummyRanges)
14082     {
14083         Range r;
14084         assert(r
14085             .padLeft(0, 12)
14086             .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
14087         );
14088     }
14089 }
14090 
14091 // Test nogc inference
14092 @safe @nogc pure unittest
14093 {
14094     import std.algorithm.comparison : equal;
14095 
14096     static immutable r1 = [1, 2, 3, 4];
14097     static immutable r2 = [0, 0, 1, 2, 3, 4];
14098     assert(r1.padLeft(0, 6).equal(r2));
14099 }
14100 
14101 /**
14102 Extend the length of the input range `r` by padding out the end of the range
14103 with the element `e`. The element `e` must be of a common type with the
14104 element type of the range `r` as defined by $(REF CommonType, std, traits).
14105 If `n` is less than the length of of `r`, then the contents of `r` are
14106 returned.
14107 
14108 The range primitives that the resulting range provides depends whether or not `r`
14109 provides them. Except the functions `back` and `popBack`, which also require
14110 the range to have a length as well as `back` and `popBack`
14111 
14112 Params:
14113     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
14114     e = element to pad the range with
14115     n = the length to pad to
14116 
14117 Returns:
14118     A range containing the elements of the original range with the extra padding
14119 
14120 See Also:
14121     $(REF rightJustifier, std, string)
14122 */
14123 auto padRight(R, E)(R r, E e, size_t n)
14124 if (
14125     isInputRange!R &&
14126     !isInfinite!R &&
14127     !is(CommonType!(ElementType!R, E) == void))
14128 {
14129     static struct Result
14130     {
14131         private:
14132         R data;
14133         E element;
14134         static if (hasLength!R)
14135         {
14136             size_t padLength;
14137         }
14138         else
14139         {
14140             size_t minLength;
14141             size_t consumed;
14142         }
14143 
14144         public:
14145         bool empty() @property
14146         {
14147             static if (hasLength!R)
14148             {
14149                 return data.empty && padLength == 0;
14150             }
14151             else
14152             {
14153                 return data.empty && consumed >= minLength;
14154             }
14155         }
14156 
14157         auto front() @property
14158         {
14159             assert(!empty, "Attempting to fetch the front of an empty padRight");
14160             return data.empty ? element : data.front;
14161         }
14162 
14163         void popFront()
14164         {
14165             assert(!empty, "Attempting to popFront an empty padRight");
14166 
14167             static if (hasLength!R)
14168             {
14169                 if (!data.empty)
14170                 {
14171                     data.popFront;
14172                 }
14173                 else
14174                 {
14175                     --padLength;
14176                 }
14177             }
14178             else
14179             {
14180                 ++consumed;
14181                 if (!data.empty)
14182                 {
14183                     data.popFront;
14184                 }
14185             }
14186         }
14187 
14188         static if (hasLength!R)
14189         {
14190             size_t length() @property
14191             {
14192                 return data.length + padLength;
14193             }
14194         }
14195 
14196         static if (isForwardRange!R)
14197         {
14198             auto save() @property
14199             {
14200                 typeof(this) result = this;
14201                 data = data.save;
14202                 return result;
14203             }
14204         }
14205 
14206         static if (isBidirectionalRange!R && hasLength!R)
14207         {
14208             auto back() @property
14209             {
14210                 assert(!empty, "Attempting to fetch the back of an empty padRight");
14211                 return padLength > 0 ? element : data.back;
14212             }
14213 
14214             void popBack()
14215             {
14216                 assert(!empty, "Attempting to popBack an empty padRight");
14217                 if (padLength > 0)
14218                 {
14219                     --padLength;
14220                 }
14221                 else
14222                 {
14223                     data.popBack;
14224                 }
14225             }
14226         }
14227 
14228         static if (isRandomAccessRange!R && hasLength!R)
14229         {
14230             E opIndex(size_t index)
14231             {
14232                 assert(index <= this.length, "Index out of bounds");
14233                 return index >= data.length ? element : data[index];
14234             }
14235         }
14236 
14237         static if (hasSlicing!R && hasLength!R)
14238         {
14239             auto opSlice(size_t a, size_t b)
14240             {
14241                 assert(
14242                     a <= b,
14243                     "Attempting to slice a padRight with a larger first argument than the second."
14244                 );
14245                 assert(
14246                     b <= length,
14247                     "Attempting to slice using an out of bounds index on a padRight"
14248                 );
14249                 return Result(
14250                     a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
14251                     element, b - a);
14252             }
14253 
14254             alias opDollar = length;
14255         }
14256 
14257         this(R r, E e, size_t n)
14258         {
14259             data = r;
14260             element = e;
14261             static if (hasLength!R)
14262             {
14263                 padLength = n > data.length ? n - data.length : 0;
14264             }
14265             else
14266             {
14267                 minLength = n;
14268             }
14269         }
14270 
14271         @disable this();
14272     }
14273 
14274     return Result(r, e, n);
14275 }
14276 
14277 ///
14278 @safe pure unittest
14279 {
14280     import std.algorithm.comparison : equal;
14281 
14282     assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
14283     assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
14284 
14285     assert("abc".padRight('_', 6).equal("abc___"));
14286 }
14287 
14288 pure @safe unittest
14289 {
14290     import std.algorithm.comparison : equal;
14291     import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
14292     import std.meta : AliasSeq;
14293 
14294     auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
14295     dchar padding = '_';
14296     assert(string_input_range.padRight(padding, 6).equal("abc___"));
14297 
14298     foreach (RangeType; AllDummyRanges)
14299     {
14300         RangeType r1;
14301         assert(r1
14302             .padRight(0, 12)
14303             .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14304         );
14305 
14306         // test if Result properly uses random access ranges
14307         static if (isRandomAccessRange!RangeType)
14308         {
14309             RangeType r3;
14310             assert(r3.padRight(0, 12)[0] == 1);
14311             assert(r3.padRight(0, 12)[2] == 3);
14312             assert(r3.padRight(0, 12)[9] == 10);
14313             assert(r3.padRight(0, 12)[10] == 0);
14314             assert(r3.padRight(0, 12)[11] == 0);
14315         }
14316 
14317         // test if Result properly uses slicing and opDollar
14318         static if (hasSlicing!RangeType)
14319         {
14320             RangeType r4;
14321             assert(r4
14322                 .padRight(0, 12)[0 .. 3]
14323                 .equal([1, 2, 3])
14324             );
14325             assert(r4
14326                 .padRight(0, 12)[0 .. 10]
14327                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
14328             );
14329             assert(r4
14330                 .padRight(0, 12)[0 .. 11]
14331                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
14332             );
14333             assert(r4
14334                 .padRight(0, 12)[2 .. $]
14335                 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14336             );
14337             assert(r4
14338                 .padRight(0, 12)[0 .. $]
14339                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14340             );
14341         }
14342 
14343         // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
14344         RangeType r5;
14345         foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
14346     }
14347 }
14348 
14349 // Test nogc inference
14350 @safe @nogc pure unittest
14351 {
14352     import std.algorithm.comparison : equal;
14353 
14354     static immutable r1 = [1, 2, 3, 4];
14355     static immutable r2 = [1, 2, 3, 4, 0, 0];
14356     assert(r1.padRight(0, 6).equal(r2));
14357 }
14358 
14359 // Test back, popBack, and save
14360 @safe pure unittest
14361 {
14362     import std.algorithm.comparison : equal;
14363 
14364     auto r1 = [1, 2, 3, 4].padRight(0, 6);
14365     assert(r1.back == 0);
14366 
14367     r1.popBack;
14368     auto r2 = r1.save;
14369     assert(r1.equal([1, 2, 3, 4, 0]));
14370     assert(r2.equal([1, 2, 3, 4, 0]));
14371 
14372     r1.popBackN(2);
14373     assert(r1.back == 3);
14374     assert(r1.length == 3);
14375     assert(r2.length == 5);
14376     assert(r2.equal([1, 2, 3, 4, 0]));
14377 
14378     r2.popFront;
14379     assert(r2.length == 4);
14380     assert(r2[0] == 2);
14381     assert(r2[1] == 3);
14382     assert(r2[2] == 4);
14383     assert(r2[3] == 0);
14384     assert(r2.equal([2, 3, 4, 0]));
14385 
14386     r2.popBack;
14387     assert(r2.equal([2, 3, 4]));
14388 
14389     auto r3 = [1, 2, 3, 4].padRight(0, 6);
14390     size_t len = 0;
14391     while (!r3.empty)
14392     {
14393         ++len;
14394         r3.popBack;
14395     }
14396     assert(len == 6);
14397 }
14398 
14399 // https://issues.dlang.org/show_bug.cgi?id=19042
14400 @safe pure unittest
14401 {
14402     import std.algorithm.comparison : equal;
14403 
14404     assert([2, 5, 13].padRight(42, 10).chunks(5)
14405            .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
14406 
14407     assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
14408 }
14409 
14410 /**
14411 This simplifies a commonly used idiom in phobos for accepting any kind of string
14412 parameter. The type `R` can for example be a simple string, chained string using
14413 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
14414 characters.
14415 
14416 Only finite length character ranges are allowed with this constraint.
14417 
14418 This template is equivalent to:
14419 ---
14420 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
14421 ---
14422 
14423 See_Also:
14424 $(REF isInputRange, std,range,primitives),
14425 $(REF isInfinite, std,range,primitives),
14426 $(LREF isSomeChar),
14427 $(REF ElementEncodingType, std,range,primitives)
14428 */
14429 template isSomeFiniteCharInputRange(R)
14430 {
14431     import std.traits : isSomeChar;
14432 
14433     enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
14434         && isSomeChar!(ElementEncodingType!R);
14435 }
14436 
14437 ///
14438 @safe unittest
14439 {
14440     import std.path : chainPath;
14441     import std.range : chain;
14442 
14443     void someLibraryMethod(R)(R argument)
14444     if (isSomeFiniteCharInputRange!R)
14445     {
14446         // implementation detail, would iterate over each character of argument
14447     }
14448 
14449     someLibraryMethod("simple strings work");
14450     someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
14451     someLibraryMethod(chainPath("chained", "paths", "work"));
14452     // you can also use custom structs implementing a char range
14453 }
14454