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(this.stoppingPolicy == StoppingPolicy.requireSameLength,
6099                             "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
6100 
6101                     foreach (range; ranges[1 .. $])
6102                         enforce(range.length == ranges[0].length);
6103                     };
6104                 indexInc = "--index;";
6105             }
6106             else
6107             {
6108                 indexDef = "size_t index = 0;";
6109                 indexInc = "++index;";
6110             }
6111         }
6112 
6113         foreach (idx, Range; Ranges)
6114         {
6115             params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6116             emptyChecks ~= format("!ranges[%s].empty", idx);
6117             if (reverse)
6118             {
6119                 dgArgs ~= format("ranges[%s].back", idx);
6120                 popFronts ~= format("ranges[%s].popBack();", idx);
6121             }
6122             else
6123             {
6124                 dgArgs ~= format("ranges[%s].front", idx);
6125                 popFronts ~= format("ranges[%s].popFront();", idx);
6126             }
6127         }
6128 
6129         if (reverse)
6130         {
6131             name = "opApplyReverse";
6132             if (withIndex) implName = "opApplyReverseIdxImpl";
6133             else           implName = "opApplyReverseImpl";
6134         }
6135         else
6136         {
6137             name = "opApply";
6138             if (withIndex) implName = "opApplyIdxImpl";
6139             else           implName = "opApplyImpl";
6140         }
6141     }
6142 
6143 const:
6144     string getAlias()
6145     {
6146         return format(q{
6147             alias %s = %s!(int delegate(%-(%s%|, %)));
6148         },
6149             name, implName, params
6150         );
6151     }
6152 
6153     string getImpl()
6154     {
6155         return format(q{
6156             int %s(DG)(scope DG dg) scope
6157             {
6158                 import std.exception : enforce;
6159 
6160                 auto ranges = this.ranges;
6161                 %s
6162 
6163                 while (%-(%s%| && %))
6164                 {
6165                     if (int result = dg(%-(%s%|, %))) return result;
6166                     %-(%s%|
6167                     %)
6168                     %s
6169                 }
6170 
6171                 if (this.stoppingPolicy == StoppingPolicy.requireSameLength)
6172                 {
6173                     foreach (range; ranges)
6174                         enforce(range.empty);
6175                 }
6176                 return 0;
6177             }
6178         },
6179             implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc
6180         );
6181     }
6182 }
6183 
6184 /**
6185    Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
6186    $(LREF zip) it allows reference access to its elements. If only a single
6187    range is passed in, the `Lockstep` aliases itself away.  If the
6188    ranges are of different lengths and `s` == `StoppingPolicy.shortest`
6189    stop after the shortest range is empty.  If the ranges are of different
6190    lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
6191    exception.  `s` may not be `StoppingPolicy.longest`, and passing this
6192    will throw an exception.
6193 
6194    Iterating over `Lockstep` in reverse and with an index is only possible
6195    when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
6196    indexes. If an attempt is made at iterating in reverse when `s` ==
6197    `StoppingPolicy.shortest`, an exception will be thrown.
6198 
6199    By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
6200 
6201    See_Also: $(LREF zip)
6202 
6203        `lockstep` is similar to $(LREF zip), but `zip` bundles its
6204        elements and returns a range.
6205        `lockstep` also supports reference access.
6206        Use `zip` if you want to pass the result to a range function.
6207 */
6208 struct Lockstep(Ranges...)
6209 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
6210 {
6211     private Ranges ranges;
6212     private StoppingPolicy stoppingPolicy;
6213 
6214     ///
6215     this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest)
6216     {
6217         import std.exception : enforce;
6218 
6219         this.ranges = ranges;
6220         enforce(sp != StoppingPolicy.longest,
6221             "Can't use StoppingPolicy.Longest on Lockstep.");
6222         this.stoppingPolicy = sp;
6223     }
6224 
6225     private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false);
6226     mixin(lockstepMixinFF.getImpl);
6227 
6228     private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false);
6229     mixin(lockstepMixinTF.getImpl);
6230 
6231     mixin(lockstepMixinFF.getAlias);
6232     mixin(lockstepMixinTF.getAlias);
6233 
6234     static if (allSatisfy!(isBidirectionalRange, Ranges))
6235     {
6236         private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true);
6237         mixin(lockstepMixinFT.getImpl);
6238         static if (allSatisfy!(hasLength, Ranges))
6239         {
6240             private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true);
6241             mixin(lockstepMixinTT.getImpl);
6242             mixin(lockstepMixinTT.getAlias);
6243         }
6244         else
6245         {
6246             mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
6247             alias opApplyReverse = opApplyReverseIdxFail;
6248         }
6249         mixin(lockstepMixinFT.getAlias);
6250     }
6251     else
6252     {
6253         mixin(lockstepReverseFailMixin!Ranges(withIndex: false));
6254         mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
6255         alias opApplyReverse = opApplyReverseFail;
6256         alias opApplyReverse = opApplyReverseIdxFail;
6257     }
6258 }
6259 
6260 /// Ditto
6261 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
6262 if (allSatisfy!(isInputRange, Ranges))
6263 {
6264     return Lockstep!(Ranges)(ranges);
6265 }
6266 /// Ditto
6267 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
6268 if (allSatisfy!(isInputRange, Ranges))
6269 {
6270     static if (Ranges.length > 1)
6271         return Lockstep!Ranges(ranges, s);
6272     else
6273         return ranges[0];
6274 }
6275 
6276 ///
6277 pure @safe unittest
6278 {
6279     int[6] arr1 = [1,2,3,4,5,100];
6280     int[5] arr2 = [6,7,8,9,10];
6281 
6282     foreach (ref a, b; lockstep(arr1[], arr2[]))
6283     {
6284         a += b;
6285     }
6286 
6287     assert(arr1 == [7,9,11,13,15,100]);
6288 }
6289 
6290 /// Lockstep also supports iterating with an index variable:
6291 pure @safe unittest
6292 {
6293     int[3] arr1 = [1,2,3];
6294     int[3] arr2 = [4,5,6];
6295 
6296     foreach (index, a, b; lockstep(arr1[], arr2[]))
6297     {
6298         assert(arr1[index] == a);
6299         assert(arr2[index] == b);
6300     }
6301 }
6302 
6303 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
6304 pure @safe unittest
6305 {
6306     auto arr1 = [0, 1, 2, 3];
6307     auto arr2 = [4, 5, 6, 7];
6308 
6309     size_t n = arr1.length - 1;
6310     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
6311     {
6312         assert(n == index);
6313         assert(index == a);
6314         assert(arr1[index] == a);
6315         assert(arr2[index] == b);
6316         n--;
6317     }
6318 
6319     auto arr3 = [4, 5];
6320     n = 1;
6321     foreach_reverse (a, b; lockstep(arr1, arr3))
6322     {
6323         assert(a == arr1[$-n] && b == arr3[$-n]);
6324         n++;
6325     }
6326 }
6327 
6328 pure @safe unittest
6329 {
6330     import std.algorithm.iteration : filter;
6331     import std.conv : to;
6332 
6333     // The filters are to make these the lowest common forward denominator ranges,
6334     // i.e. w/o ref return, random access, length, etc.
6335     auto foo = filter!"a"([1,2,3,4,5]);
6336     immutable bar = [6f,7f,8f,9f,10f].idup;
6337     auto l = lockstep(foo, bar);
6338 
6339     // Should work twice.  These are forward ranges with implicit save.
6340     foreach (i; 0 .. 2)
6341     {
6342         uint[] res1;
6343         float[] res2;
6344 
6345         foreach (a, ref b; l)
6346         {
6347             res1 ~= a;
6348             res2 ~= b;
6349         }
6350 
6351         assert(res1 == [1,2,3,4,5]);
6352         assert(res2 == [6,7,8,9,10]);
6353         assert(bar == [6f,7f,8f,9f,10f]);
6354     }
6355 
6356     // Doc example.
6357     auto arr1 = [1,2,3,4,5];
6358     auto arr2 = [6,7,8,9,10];
6359 
6360     foreach (ref a, ref b; lockstep(arr1, arr2))
6361     {
6362         a += b;
6363     }
6364 
6365     assert(arr1 == [7,9,11,13,15]);
6366 
6367     // Make sure StoppingPolicy.requireSameLength doesn't throw.
6368     auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6369 
6370     int k = 1;
6371     foreach (a, b; ls)
6372     {
6373         assert(a - b == k);
6374         ++k;
6375     }
6376 
6377     // Make sure StoppingPolicy.requireSameLength throws.
6378     arr2.popBack();
6379     ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6380 
6381     try {
6382         foreach (a, b; ls) {}
6383         assert(0);
6384     } catch (Exception) {}
6385 
6386     // Just make sure 1-range case instantiates. This hangs the compiler
6387     // when no explicit stopping policy is specified due to
6388     // https://issues.dlang.org/show_bug.cgi?id=4652
6389     auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
6390     foreach (i, a; stuff)
6391     {
6392         assert(stuff[i] == a);
6393     }
6394 
6395     // Test with indexing.
6396     uint[] res1;
6397     float[] res2;
6398     size_t[] indices;
6399     foreach (i, a, b; lockstep(foo, bar))
6400     {
6401         indices ~= i;
6402         res1 ~= a;
6403         res2 ~= b;
6404     }
6405 
6406     assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
6407     assert(res1 == [1,2,3,4,5]);
6408     assert(res2 == [6f,7f,8f,9f,10f]);
6409 
6410     // Make sure we've worked around the relevant compiler bugs and this at least
6411     // compiles w/ >2 ranges.
6412     lockstep(foo, foo, foo);
6413 
6414     // Make sure it works with const.
6415     const(int[])[] foo2 = [[1, 2, 3]];
6416     const(int[])[] bar2 = [[4, 5, 6]];
6417     auto c = chain(foo2, bar2);
6418 
6419     foreach (f, b; lockstep(c, c)) {}
6420 
6421     // Regression 10468
6422     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
6423 }
6424 
6425 pure @safe unittest
6426 {
6427     struct RvalueRange
6428     {
6429         int[] impl;
6430         @property bool empty() { return impl.empty; }
6431         @property int front() { return impl[0]; } // N.B. non-ref
6432         void popFront() { impl.popFront(); }
6433     }
6434     auto data1 = [ 1, 2, 3, 4 ];
6435     auto data2 = [ 5, 6, 7, 8 ];
6436     auto r1 = RvalueRange(data1);
6437     auto r2 = data2;
6438     foreach (a, ref b; lockstep(r1, r2))
6439     {
6440         a++;
6441         b++;
6442     }
6443     assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
6444     assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
6445 
6446     // Since r1 is by-value only, the compiler should reject attempts to
6447     // foreach over it with ref.
6448     static assert(!__traits(compiles, {
6449         foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
6450     }));
6451 }
6452 
6453 private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
6454 {
6455     import std.format : format;
6456     string[] params;
6457     string message;
6458 
6459     if (withIndex)
6460     {
6461         message = "Indexed reverse iteration with lockstep is only supported"
6462         ~"if all ranges are bidirectional and have a length.\n";
6463     }
6464     else
6465     {
6466         message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
6467     }
6468 
6469     if (withIndex)
6470     {
6471         params ~= "size_t";
6472     }
6473 
6474     foreach (idx, Range; Ranges)
6475     {
6476         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6477     }
6478 
6479     return format(
6480     q{
6481         int opApplyReverse%sFail()(scope int delegate(%s) dg)
6482         {
6483             static assert(false, "%s");
6484         }
6485     }, withIndex ? "Idx" : "" , params.join(", "), message);
6486 }
6487 
6488 // For generic programming, make sure Lockstep!(Range) is well defined for a
6489 // single range.
6490 template Lockstep(Range)
6491 {
6492     alias Lockstep = Range;
6493 }
6494 
6495 /**
6496 Creates a mathematical sequence given the initial values and a
6497 recurrence function that computes the next value from the existing
6498 values. The sequence comes in the form of an infinite forward
6499 range. The type `Recurrence` itself is seldom used directly; most
6500 often, recurrences are obtained by calling the function $(D
6501 recurrence).
6502 
6503 When calling `recurrence`, the function that computes the next
6504 value is specified as a template argument, and the initial values in
6505 the recurrence are passed as regular arguments. For example, in a
6506 Fibonacci sequence, there are two initial values (and therefore a
6507 state size of 2) because computing the next Fibonacci value needs the
6508 past two values.
6509 
6510 The signature of this function should be:
6511 ----
6512 auto fun(R)(R state, size_t n)
6513 ----
6514 where `n` will be the index of the current value, and `state` will be an
6515 opaque state vector that can be indexed with array-indexing notation
6516 `state[i]`, where valid values of `i` range from $(D (n - 1)) to
6517 $(D (n - State.length)).
6518 
6519 If the function is passed in string form, the state has name `"a"`
6520 and the zero-based index in the recurrence has name `"n"`. The
6521 given string must return the desired value for `a[n]` given
6522 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
6523 state size is dictated by the number of arguments passed to the call
6524 to `recurrence`. The `Recurrence` struct itself takes care of
6525 managing the recurrence's state and shifting it appropriately.
6526  */
6527 struct Recurrence(alias fun, StateType, size_t stateSize)
6528 {
6529     import std.functional : binaryFun;
6530 
6531     StateType[stateSize] _state;
6532     size_t _n;
6533 
6534     this(StateType[stateSize] initial) { _state = initial; }
6535 
6536     void popFront()
6537     {
6538         static auto trustedCycle(ref typeof(_state) s) @trusted
6539         {
6540             return cycle(s);
6541         }
6542         // The cast here is reasonable because fun may cause integer
6543         // promotion, but needs to return a StateType to make its operation
6544         // closed.  Therefore, we have no other choice.
6545         _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
6546             trustedCycle(_state), _n + stateSize);
6547         ++_n;
6548     }
6549 
6550     @property StateType front()
6551     {
6552         return _state[_n % stateSize];
6553     }
6554 
6555     @property typeof(this) save()
6556     {
6557         return this;
6558     }
6559 
6560     enum bool empty = false;
6561 }
6562 
6563 ///
6564 pure @safe nothrow unittest
6565 {
6566     import std.algorithm.comparison : equal;
6567 
6568     // The Fibonacci numbers, using function in string form:
6569     // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
6570     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6571     assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
6572 
6573     // The factorials, using function in lambda form:
6574     auto fac = recurrence!((a,n) => a[n-1] * n)(1);
6575     assert(take(fac, 10).equal([
6576         1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
6577     ]));
6578 
6579     // The triangular numbers, using function in explicit form:
6580     static size_t genTriangular(R)(R state, size_t n)
6581     {
6582         return state[n-1] + n;
6583     }
6584     auto tri = recurrence!genTriangular(0);
6585     assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
6586 }
6587 
6588 /// Ditto
6589 Recurrence!(fun, CommonType!(State), State.length)
6590 recurrence(alias fun, State...)(State initial)
6591 {
6592     CommonType!(State)[State.length] state;
6593     foreach (i, Unused; State)
6594     {
6595         state[i] = initial[i];
6596     }
6597     return typeof(return)(state);
6598 }
6599 
6600 pure @safe nothrow unittest
6601 {
6602     import std.algorithm.comparison : equal;
6603 
6604     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6605     static assert(isForwardRange!(typeof(fib)));
6606 
6607     int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
6608     assert(equal(take(fib, 10), witness));
6609     foreach (e; take(fib, 10)) {}
6610     auto fact = recurrence!("n * a[n-1]")(1);
6611     assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
6612                             2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
6613     auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
6614     foreach (e; take(piapprox, 20)) {}
6615     // Thanks to yebblies for this test and the associated fix
6616     auto r = recurrence!"a[n-2]"(1, 2);
6617     witness = [1, 2, 1, 2, 1];
6618     assert(equal(take(r, 5), witness));
6619 }
6620 
6621 /**
6622    `Sequence` is similar to `Recurrence` except that iteration is
6623    presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
6624    closed form). This means that the `n`th element in the series is
6625    computable directly from the initial values and `n` itself. This
6626    implies that the interface offered by `Sequence` is a random-access
6627    range, as opposed to the regular `Recurrence`, which only offers
6628    forward iteration.
6629 
6630    The state of the sequence is stored as a `Tuple` so it can be
6631    heterogeneous.
6632 */
6633 struct Sequence(alias fun, State)
6634 {
6635 private:
6636     import std.functional : binaryFun;
6637 
6638     alias compute = binaryFun!(fun, "a", "n");
6639     alias ElementType = typeof(compute(State.init, cast(size_t) 1));
6640     State _state;
6641     size_t _n;
6642 
6643     static struct DollarToken{}
6644 
6645 public:
6646     this(State initial, size_t n = 0)
6647     {
6648         _state = initial;
6649         _n = n;
6650     }
6651 
6652     @property ElementType front()
6653     {
6654         return compute(_state, _n);
6655     }
6656 
6657     void popFront()
6658     {
6659         ++_n;
6660     }
6661 
6662     enum opDollar = DollarToken();
6663 
6664     auto opSlice(size_t lower, size_t upper)
6665     in
6666     {
6667         assert(
6668             upper >= lower,
6669             "Attempting to slice a Sequence with a larger first argument than the second."
6670         );
6671     }
6672     do
6673     {
6674         return typeof(this)(_state, _n + lower).take(upper - lower);
6675     }
6676 
6677     auto opSlice(size_t lower, DollarToken)
6678     {
6679         return typeof(this)(_state, _n + lower);
6680     }
6681 
6682     ElementType opIndex(size_t n)
6683     {
6684         return compute(_state, n + _n);
6685     }
6686 
6687     enum bool empty = false;
6688 
6689     @property Sequence save() { return this; }
6690 }
6691 
6692 /// Ditto
6693 auto sequence(alias fun, State...)(State args)
6694 {
6695     import std.typecons : Tuple, tuple;
6696     alias Return = Sequence!(fun, Tuple!State);
6697     return Return(tuple(args));
6698 }
6699 
6700 /// Odd numbers, using function in string form:
6701 pure @safe nothrow @nogc unittest
6702 {
6703     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6704     assert(odds.front == 1);
6705     odds.popFront();
6706     assert(odds.front == 3);
6707     odds.popFront();
6708     assert(odds.front == 5);
6709 }
6710 
6711 /// Triangular numbers, using function in lambda form:
6712 pure @safe nothrow @nogc unittest
6713 {
6714     auto tri = sequence!((a,n) => n*(n+1)/2)();
6715 
6716     // Note random access
6717     assert(tri[0] == 0);
6718     assert(tri[3] == 6);
6719     assert(tri[1] == 1);
6720     assert(tri[4] == 10);
6721     assert(tri[2] == 3);
6722 }
6723 
6724 /// Fibonacci numbers, using function in explicit form:
6725 @safe nothrow @nogc unittest
6726 {
6727     import std.math.exponential : pow;
6728     import std.math.rounding : round;
6729     import std.math.algebraic : sqrt;
6730     static ulong computeFib(S)(S state, size_t n)
6731     {
6732         // Binet's formula
6733         return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6734                                  state[2]));
6735     }
6736     auto fib = sequence!computeFib(
6737         (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
6738         (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
6739         sqrt(5.0));
6740 
6741     // Note random access with [] operator
6742     assert(fib[1] == 1);
6743     assert(fib[4] == 5);
6744     assert(fib[3] == 3);
6745     assert(fib[2] == 2);
6746     assert(fib[9] == 55);
6747 }
6748 
6749 pure @safe nothrow @nogc unittest
6750 {
6751     import std.typecons : Tuple, tuple;
6752     auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6753     static assert(isForwardRange!(typeof(y)));
6754 
6755     //@@BUG
6756     //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6757     //foreach (e; take(y, 15))
6758     {}                                 //writeln(e);
6759 
6760     auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6761         tuple(1, 2));
6762     for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6763     {
6764         assert(odds.front == odds[0]);
6765         assert(odds[0] == currentOdd);
6766         odds.popFront();
6767     }
6768 }
6769 
6770 pure @safe nothrow @nogc unittest
6771 {
6772     import std.algorithm.comparison : equal;
6773 
6774     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6775     static assert(hasSlicing!(typeof(odds)));
6776 
6777     //Note: don't use drop or take as the target of an equal,
6778     //since they'll both just forward to opSlice, making the tests irrelevant
6779 
6780     // static slicing tests
6781     assert(equal(odds[0 .. 5], only(1,  3,  5,  7,  9)));
6782     assert(equal(odds[3 .. 7], only(7,  9, 11, 13)));
6783 
6784     // relative slicing test, testing slicing is NOT agnostic of state
6785     auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6786     assert(equal(odds_less5[0 ..  3], only(11, 13, 15)));
6787     assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6788 
6789     //Infinite slicing tests
6790     odds = odds[10 .. $];
6791     assert(equal(odds.take(3), only(21, 23, 25)));
6792 }
6793 
6794 // https://issues.dlang.org/show_bug.cgi?id=5036
6795 pure @safe nothrow unittest
6796 {
6797     auto s = sequence!((a, n) => new int)(0);
6798     assert(s.front != s.front);  // no caching
6799 }
6800 
6801 // iota
6802 /**
6803    Creates a range of values that span the given starting and stopping
6804    values.
6805 
6806    Params:
6807    begin = The starting value.
6808    end = The value that serves as the stopping criterion. This value is not
6809         included in the range.
6810    step = The value to add to the current value at each iteration.
6811 
6812    Returns:
6813    A range that goes through the numbers `begin`, $(D begin + step),
6814    $(D begin + 2 * step), `...`, up to and excluding `end`.
6815 
6816    The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6817    0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6818    is returned. If $(D step == 0) then $(D begin == end) is an error.
6819 
6820    For built-in types, the range returned is a random access range. For
6821    user-defined types that support `++`, the range is an input
6822    range.
6823 
6824    An integral iota also supports `in` operator from the right. It takes
6825    the stepping into account, the integral won't be considered
6826    contained if it falls between two consecutive values of the range.
6827    `contains` does the same as in, but from lefthand side.
6828 
6829     Example:
6830     ---
6831     void main()
6832     {
6833         import std.stdio;
6834 
6835         // The following groups all produce the same output of:
6836         // 0 1 2 3 4
6837 
6838         foreach (i; 0 .. 5)
6839             writef("%s ", i);
6840         writeln();
6841 
6842         import std.range : iota;
6843         foreach (i; iota(0, 5))
6844             writef("%s ", i);
6845         writeln();
6846 
6847         writefln("%(%s %|%)", iota(0, 5));
6848 
6849         import std.algorithm.iteration : map;
6850         import std.algorithm.mutation : copy;
6851         import std.format;
6852         iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6853         writeln();
6854     }
6855     ---
6856 */
6857 auto iota(B, E, S)(B begin, E end, S step)
6858 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6859         && isIntegral!S)
6860 {
6861     import std.conv : unsigned;
6862 
6863     alias Value = CommonType!(Unqual!B, Unqual!E);
6864     alias StepType = Unqual!S;
6865 
6866     assert(step != 0 || begin == end);
6867 
6868     static struct Result
6869     {
6870         private Value current, last;
6871         private StepType step; // by convention, 0 if range is empty
6872 
6873         this(Value current, Value pastLast, StepType step)
6874         {
6875             if (current < pastLast && step > 0)
6876             {
6877                 // Iterating upward
6878                 assert(unsigned((pastLast - current) / step) <= size_t.max);
6879                 // Cast below can't fail because current < pastLast
6880                 this.last = cast(Value) (pastLast - 1);
6881                 this.last -= unsigned(this.last - current) % step;
6882             }
6883             else if (current > pastLast && step < 0)
6884             {
6885                 // Iterating downward
6886                 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6887                 // Cast below can't fail because current > pastLast
6888                 this.last = cast(Value) (pastLast + 1);
6889                 this.last += unsigned(current - this.last) % (0 - step);
6890             }
6891             else
6892             {
6893                 // Initialize an empty range
6894                 this.step = 0;
6895                 return;
6896             }
6897             this.step = step;
6898             this.current = current;
6899         }
6900 
6901         @property bool empty() const { return step == 0; }
6902         @property inout(Value) front() inout { assert(!empty); return current; }
6903         void popFront()
6904         {
6905             assert(!empty);
6906             if (current == last) step = 0;
6907             else current += step;
6908         }
6909 
6910         @property inout(Value) back() inout
6911         {
6912             assert(!empty);
6913             return last;
6914         }
6915         void popBack()
6916         {
6917             assert(!empty);
6918             if (current == last) step = 0;
6919             else last -= step;
6920         }
6921 
6922         @property auto save() { return this; }
6923 
6924         inout(Value) opIndex(ulong n) inout
6925         {
6926             assert(n < this.length);
6927 
6928             // Just cast to Value here because doing so gives overflow behavior
6929             // consistent with calling popFront() n times.
6930             return cast(inout Value) (current + step * n);
6931         }
6932         auto opBinaryRight(string op)(Value val) const
6933         if (op == "in")
6934         {
6935             if (empty) return false;
6936             //cast to avoid becoming unsigned
6937             auto supposedIndex = cast(StepType)(val - current) / step;
6938             return supposedIndex < length && supposedIndex * step + current == val;
6939         }
6940         auto contains(Value x){return x in this;}
6941         inout(Result) opSlice() inout { return this; }
6942         inout(Result) opSlice(ulong lower, ulong upper) inout
6943         {
6944             assert(upper >= lower && upper <= this.length);
6945 
6946             return cast(inout Result) Result(
6947                 cast(Value)(current + lower * step),
6948                 cast(Value)(current + upper * step),
6949                 step);
6950         }
6951         @property size_t length() const
6952         {
6953             if (step > 0)
6954                 return 1 + cast(size_t) (unsigned(last - current) / step);
6955             if (step < 0)
6956                 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6957             return 0;
6958         }
6959 
6960         alias opDollar = length;
6961     }
6962 
6963     return Result(begin, end, step);
6964 }
6965 
6966 /// Ditto
6967 auto iota(B, E)(B begin, E end)
6968 if (isFloatingPoint!(CommonType!(B, E)))
6969 {
6970     return iota(begin, end, CommonType!(B, E)(1));
6971 }
6972 
6973 /// Ditto
6974 auto iota(B, E)(B begin, E end)
6975 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6976 {
6977     import std.conv : unsigned;
6978 
6979     alias Value = CommonType!(Unqual!B, Unqual!E);
6980 
6981     static struct Result
6982     {
6983         private Value current, pastLast;
6984 
6985         this(Value current, Value pastLast)
6986         {
6987             if (current < pastLast)
6988             {
6989                 assert(unsigned(pastLast - current) <= size_t.max,
6990                     "`iota` range is too long");
6991 
6992                 this.current = current;
6993                 this.pastLast = pastLast;
6994             }
6995             else
6996             {
6997                 // Initialize an empty range
6998                 this.current = this.pastLast = current;
6999             }
7000         }
7001 
7002         @property bool empty() const { return current == pastLast; }
7003         @property inout(Value) front() inout
7004         {
7005             assert(!empty, "Attempt to access `front` of empty `iota` range");
7006             return current;
7007         }
7008         void popFront()
7009         {
7010             assert(!empty, "Attempt to `popFront` of empty `iota` range");
7011             ++current;
7012         }
7013 
7014         @property inout(Value) back() inout
7015         {
7016             assert(!empty, "Attempt to access `back` of empty `iota` range");
7017             return cast(inout(Value))(pastLast - 1);
7018         }
7019         void popBack()
7020         {
7021             assert(!empty, "Attempt to `popBack` of empty `iota` range");
7022             --pastLast;
7023         }
7024 
7025         @property auto save() { return this; }
7026 
7027         inout(Value) opIndex(size_t n) inout
7028         {
7029             assert(n < this.length,
7030                 "Attempt to read out-of-bounds index of `iota` range");
7031 
7032             // Just cast to Value here because doing so gives overflow behavior
7033             // consistent with calling popFront() n times.
7034             return cast(inout Value) (current + n);
7035         }
7036         auto opBinaryRight(string op)(Value val) const
7037         if (op == "in")
7038         {
7039             return current <= val && val < pastLast;
7040         }
7041         auto contains(Value x){return x in this;}
7042         inout(Result) opSlice() inout { return this; }
7043         inout(Result) opSlice(ulong lower, ulong upper) inout
7044         {
7045             assert(upper >= lower && upper <= this.length,
7046                 "Attempt to get out-of-bounds slice of `iota` range");
7047 
7048             return cast(inout Result) Result(cast(Value)(current + lower),
7049                                             cast(Value)(pastLast - (length - upper)));
7050         }
7051         @property size_t length() const
7052         {
7053             return cast(size_t)(pastLast - current);
7054         }
7055 
7056         alias opDollar = length;
7057     }
7058 
7059     return Result(begin, end);
7060 }
7061 
7062 /// Ditto
7063 auto iota(E)(E end)
7064 if (is(typeof(iota(E(0), end))))
7065 {
7066     E begin = E(0);
7067     return iota(begin, end);
7068 }
7069 
7070 /// Ditto
7071 // Specialization for floating-point types
7072 auto iota(B, E, S)(B begin, E end, S step)
7073 if (isFloatingPoint!(CommonType!(B, E, S)))
7074 in
7075 {
7076     assert(step != 0, "iota: step must not be 0");
7077     assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
7078 }
7079 do
7080 {
7081     alias Value = Unqual!(CommonType!(B, E, S));
7082     static struct Result
7083     {
7084         private Value start, step;
7085         private size_t index, count;
7086 
7087         this(Value start, Value end, Value step)
7088         {
7089             import std.conv : to;
7090 
7091             this.start = start;
7092             this.step = step;
7093             immutable fcount = (end - start) / step;
7094             count = to!size_t(fcount);
7095             auto pastEnd = start + count * step;
7096             if (step > 0)
7097             {
7098                 if (pastEnd < end) ++count;
7099                 assert(start + count * step >= end);
7100             }
7101             else
7102             {
7103                 if (pastEnd > end) ++count;
7104                 assert(start + count * step <= end);
7105             }
7106         }
7107 
7108         @property bool empty() const { return index == count; }
7109         @property Value front() const { assert(!empty); return start + step * index; }
7110         void popFront()
7111         {
7112             assert(!empty);
7113             ++index;
7114         }
7115         @property Value back() const
7116         {
7117             assert(!empty);
7118             return start + step * (count - 1);
7119         }
7120         void popBack()
7121         {
7122             assert(!empty);
7123             --count;
7124         }
7125 
7126         @property auto save() { return this; }
7127 
7128         Value opIndex(size_t n) const
7129         {
7130             assert(n < count);
7131             return start + step * (n + index);
7132         }
7133         inout(Result) opSlice() inout
7134         {
7135             return this;
7136         }
7137         inout(Result) opSlice(size_t lower, size_t upper) inout
7138         {
7139             assert(upper >= lower && upper <= count);
7140 
7141             Result ret = this;
7142             ret.index += lower;
7143             ret.count = upper - lower + ret.index;
7144             return cast(inout Result) ret;
7145         }
7146         @property size_t length() const
7147         {
7148             return count - index;
7149         }
7150 
7151         alias opDollar = length;
7152     }
7153 
7154     return Result(begin, end, step);
7155 }
7156 
7157 ///
7158 pure @safe unittest
7159 {
7160     import std.algorithm.comparison : equal;
7161     import std.math.operations : isClose;
7162 
7163     auto r = iota(0, 10, 1);
7164     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
7165     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
7166     assert(3 in r);
7167     assert(r.contains(3)); //Same as above
7168     assert(!(10 in r));
7169     assert(!(-8 in r));
7170     r = iota(0, 11, 3);
7171     assert(equal(r, [0, 3, 6, 9]));
7172     assert(r[2] == 6);
7173     assert(!(2 in r));
7174     auto rf = iota(0.0, 0.5, 0.1);
7175     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
7176 }
7177 
7178 pure nothrow @nogc @safe unittest
7179 {
7180     import std.traits : Signed;
7181    //float overloads use std.conv.to so can't be @nogc or nothrow
7182     alias ssize_t = Signed!size_t;
7183     assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
7184     assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
7185     assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
7186     assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
7187     assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
7188 }
7189 
7190 debug @system unittest
7191 {//check the contracts
7192     import core.exception : AssertError;
7193     import std.exception : assertThrown;
7194     assertThrown!AssertError(iota(1,2,0));
7195     assertThrown!AssertError(iota(0f,1f,0f));
7196     assertThrown!AssertError(iota(1f,0f,0.1f));
7197     assertThrown!AssertError(iota(0f,1f,-0.1f));
7198 }
7199 
7200 pure @system nothrow unittest
7201 {
7202     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
7203     auto r1 = iota(a.ptr, a.ptr + a.length, 1);
7204     assert(r1.front == a.ptr);
7205     assert(r1.back == a.ptr + a.length - 1);
7206     assert(&a[4] in r1);
7207 }
7208 
7209 pure @safe nothrow @nogc unittest
7210 {
7211     assert(iota(1UL, 0UL).length == 0);
7212     assert(iota(1UL, 0UL, 1).length == 0);
7213     assert(iota(0, 1, 1).length == 1);
7214     assert(iota(1, 0, -1).length == 1);
7215     assert(iota(0, 1, -1).length == 0);
7216     assert(iota(ulong.max, 0).length == 0);
7217 }
7218 
7219 pure @safe unittest
7220 {
7221     import std.algorithm.comparison : equal;
7222     import std.algorithm.searching : count;
7223     import std.math.operations : isClose, nextUp, nextDown;
7224     import std.meta : AliasSeq;
7225 
7226     static assert(is(ElementType!(typeof(iota(0f))) == float));
7227 
7228     static assert(hasLength!(typeof(iota(0, 2))));
7229     auto r = iota(0, 10, 1);
7230     assert(r[$ - 1] == 9);
7231     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7232 
7233     auto rSlice = r[2 .. 8];
7234     assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
7235 
7236     rSlice.popFront();
7237     assert(rSlice[0] == rSlice.front);
7238     assert(rSlice.front == 3);
7239 
7240     rSlice.popBack();
7241     assert(rSlice[rSlice.length - 1] == rSlice.back);
7242     assert(rSlice.back == 6);
7243 
7244     rSlice = r[0 .. 4];
7245     assert(equal(rSlice, [0, 1, 2, 3]));
7246     assert(3 in rSlice);
7247     assert(!(4 in rSlice));
7248 
7249     auto rr = iota(10);
7250     assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7251 
7252     r = iota(0, -10, -1);
7253     assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
7254     rSlice = r[3 .. 9];
7255     assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
7256 
7257     r = iota(0, -6, -3);
7258     assert(equal(r, [0, -3][]));
7259     rSlice = r[1 .. 2];
7260     assert(equal(rSlice, [-3]));
7261 
7262     r = iota(0, -7, -3);
7263     assert(equal(r, [0, -3, -6][]));
7264     assert(0 in r);
7265     assert(-6 in r);
7266     rSlice = r[1 .. 3];
7267     assert(equal(rSlice, [-3, -6]));
7268     assert(!(0 in rSlice));
7269     assert(!(-2 in rSlice));
7270     assert(!(-5 in rSlice));
7271     assert(!(3 in rSlice));
7272     assert(!(-9 in rSlice));
7273 
7274     r = iota(0, 11, 3);
7275     assert(equal(r, [0, 3, 6, 9][]));
7276     assert(r[2] == 6);
7277     rSlice = r[1 .. 3];
7278     assert(equal(rSlice, [3, 6]));
7279 
7280     auto rf = iota(0.0, 0.5, 0.1);
7281     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
7282     assert(rf.length == 5);
7283 
7284     rf.popFront();
7285     assert(rf.length == 4);
7286 
7287     auto rfSlice = rf[1 .. 4];
7288     assert(rfSlice.length == 3);
7289     assert(isClose(rfSlice, [0.2, 0.3, 0.4]));
7290 
7291     rfSlice.popFront();
7292     assert(isClose(rfSlice[0], 0.3));
7293 
7294     rf.popFront();
7295     assert(rf.length == 3);
7296 
7297     rfSlice = rf[1 .. 3];
7298     assert(rfSlice.length == 2);
7299     assert(isClose(rfSlice, [0.3, 0.4]));
7300     assert(isClose(rfSlice[0], 0.3));
7301 
7302     // With something just above 0.5
7303     rf = iota(0.0, nextUp(0.5), 0.1);
7304     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
7305     rf.popBack();
7306     assert(rf[rf.length - 1] == rf.back);
7307     assert(isClose(rf.back, 0.4));
7308     assert(rf.length == 5);
7309 
7310     // going down
7311     rf = iota(0.0, -0.5, -0.1);
7312     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
7313     rfSlice = rf[2 .. 5];
7314     assert(isClose(rfSlice, [-0.2, -0.3, -0.4]));
7315 
7316     rf = iota(0.0, nextDown(-0.5), -0.1);
7317     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
7318 
7319     // iota of longs
7320     auto rl = iota(5_000_000L);
7321     assert(rl.length == 5_000_000L);
7322     assert(0 in rl);
7323     assert(4_000_000L in rl);
7324     assert(!(-4_000_000L in rl));
7325     assert(!(5_000_000L in rl));
7326 
7327     // iota of longs with steps
7328     auto iota_of_longs_with_steps = iota(50L, 101L, 10);
7329     assert(iota_of_longs_with_steps.length == 6);
7330     assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
7331 
7332     // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
7333     // Actually trying to consume it is the only way to find something is wrong
7334     // because the public properties are all correct.
7335     auto iota_zero_unsigned = iota(0, 0u, 3);
7336     assert(count(iota_zero_unsigned) == 0);
7337 
7338     // https://issues.dlang.org/show_bug.cgi?id=7982
7339     // unsigned reverse iota can be buggy if `.length` doesn't
7340     // take them into account
7341     assert(iota(10u, 0u, -1).length == 10);
7342     assert(iota(10u, 0u, -2).length == 5);
7343     assert(iota(uint.max, uint.max-10, -1).length == 10);
7344     assert(iota(uint.max, uint.max-10, -2).length == 5);
7345     assert(iota(uint.max, 0u, -1).length == uint.max);
7346 
7347     assert(20 in iota(20u, 10u, -2));
7348     assert(16 in iota(20u, 10u, -2));
7349     assert(!(15 in iota(20u, 10u, -2)));
7350     assert(!(10 in iota(20u, 10u, -2)));
7351     assert(!(uint.max in iota(20u, 10u, -1)));
7352     assert(!(int.min in iota(20u, 10u, -1)));
7353     assert(!(int.max in iota(20u, 10u, -1)));
7354 
7355 
7356     // https://issues.dlang.org/show_bug.cgi?id=8920
7357     static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
7358         int, uint, long, ulong))
7359     {{
7360         Type val;
7361         foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
7362         assert(val == 10);
7363     }}
7364 }
7365 
7366 pure @safe nothrow unittest
7367 {
7368     import std.algorithm.mutation : copy;
7369     auto idx = new size_t[100];
7370     copy(iota(0, idx.length), idx);
7371 }
7372 
7373 @safe unittest
7374 {
7375     import std.meta : AliasSeq;
7376     static foreach (range; AliasSeq!(iota(2, 27, 4),
7377                              iota(3, 9),
7378                              iota(2.7, 12.3, .1),
7379                              iota(3.2, 9.7)))
7380     {{
7381         const cRange = range;
7382         const e = cRange.empty;
7383         const f = cRange.front;
7384         const b = cRange.back;
7385         const i = cRange[2];
7386         const s1 = cRange[];
7387         const s2 = cRange[0 .. 3];
7388         const l = cRange.length;
7389     }}
7390 }
7391 
7392 @system unittest
7393 {
7394     //The ptr stuff can't be done at compile time, so we unfortunately end
7395     //up with some code duplication here.
7396     auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
7397 
7398     {
7399         const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
7400         const e = cRange.empty;
7401         const f = cRange.front;
7402         const b = cRange.back;
7403         const i = cRange[2];
7404         const s1 = cRange[];
7405         const s2 = cRange[0 .. 3];
7406         const l = cRange.length;
7407     }
7408 
7409     {
7410         const cRange = iota(arr.ptr, arr.ptr + arr.length);
7411         const e = cRange.empty;
7412         const f = cRange.front;
7413         const b = cRange.back;
7414         const i = cRange[2];
7415         const s1 = cRange[];
7416         const s2 = cRange[0 .. 3];
7417         const l = cRange.length;
7418     }
7419 }
7420 
7421 @nogc nothrow pure @safe unittest
7422 {
7423     {
7424         ushort start = 0, end = 10, step = 2;
7425         foreach (i; iota(start, end, step))
7426             static assert(is(typeof(i) == ushort));
7427     }
7428     {
7429         ubyte start = 0, end = 255, step = 128;
7430         uint x;
7431         foreach (i; iota(start, end, step))
7432         {
7433             static assert(is(typeof(i) == ubyte));
7434             ++x;
7435         }
7436         assert(x == 2);
7437     }
7438 }
7439 
7440 /* Generic overload that handles arbitrary types that support arithmetic
7441  * operations.
7442  *
7443  * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
7444  * as they can be incremented with `++` and compared with `<` or `==`.
7445  */
7446 /// ditto
7447 auto iota(B, E)(B begin, E end)
7448 if (!isIntegral!(CommonType!(B, E)) &&
7449     !isFloatingPoint!(CommonType!(B, E)) &&
7450     !isPointer!(CommonType!(B, E)) &&
7451     is(typeof((ref B b) { ++b; })) &&
7452     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
7453 {
7454     static struct Result
7455     {
7456         B current;
7457         E end;
7458 
7459         @property bool empty()
7460         {
7461             static if (is(typeof(B.init < E.init)))
7462                 return !(current < end);
7463             else static if (is(typeof(B.init != E.init)))
7464                 return current == end;
7465             else
7466                 static assert(0);
7467         }
7468         @property auto front() { return current; }
7469         void popFront()
7470         {
7471             assert(!empty);
7472             ++current;
7473         }
7474         @property auto save() { return this; }
7475     }
7476     return Result(begin, end);
7477 }
7478 
7479 @safe unittest
7480 {
7481     import std.algorithm.comparison : equal;
7482 
7483     // Test iota() for a type that only supports ++ and != but does not have
7484     // '<'-ordering.
7485     struct Cyclic(int wrapAround)
7486     {
7487         int current;
7488 
7489         this(int start) { current = start % wrapAround; }
7490 
7491         bool opEquals(Cyclic c) const { return current == c.current; }
7492         bool opEquals(int i) const { return current == i; }
7493         void opUnary(string op)() if (op == "++")
7494         {
7495             current = (current + 1) % wrapAround;
7496         }
7497     }
7498     alias Cycle5 = Cyclic!5;
7499 
7500     // Easy case
7501     auto i1 = iota(Cycle5(1), Cycle5(4));
7502     assert(i1.equal([1, 2, 3]));
7503 
7504     // Wraparound case
7505     auto i2 = iota(Cycle5(3), Cycle5(2));
7506     assert(i2.equal([3, 4, 0, 1 ]));
7507 }
7508 
7509 // https://issues.dlang.org/show_bug.cgi?id=23453
7510 @safe unittest
7511 {
7512     auto r = iota('a', 'z');
7513     static assert(isForwardRange!(typeof(r)));
7514 }
7515 
7516 /**
7517    Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
7518    (below).
7519 */
7520 enum TransverseOptions
7521 {
7522 /**
7523    When transversed, the elements of a range of ranges are assumed to
7524    have different lengths (e.g. a jagged array).
7525 */
7526     assumeJagged,                      //default
7527     /**
7528        The transversal enforces that the elements of a range of ranges have
7529        all the same length (e.g. an array of arrays, all having the same
7530        length). Checking is done once upon construction of the transversal
7531        range.
7532     */
7533         enforceNotJagged,
7534     /**
7535        The transversal assumes, without verifying, that the elements of a
7536        range of ranges have all the same length. This option is useful if
7537        checking was already done from the outside of the range.
7538     */
7539         assumeNotJagged,
7540 }
7541 
7542 ///
7543 @safe pure unittest
7544 {
7545     import std.algorithm.comparison : equal;
7546     import std.exception : assertThrown;
7547 
7548     auto arr = [[1, 2], [3, 4, 5]];
7549 
7550     auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
7551     assert(r1.equal([1, 3]));
7552 
7553     // throws on construction
7554     assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
7555 
7556     auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
7557     assert(r2.equal([1, 3]));
7558 
7559     // either assuming or checking for equal lengths makes
7560     // the result a random access range
7561     assert(r2[0] == 1);
7562     static assert(!__traits(compiles, r1[0]));
7563 }
7564 
7565 /**
7566    Given a range of ranges, iterate transversally through the first
7567    elements of each of the enclosed ranges.
7568 */
7569 struct FrontTransversal(Ror,
7570         TransverseOptions opt = TransverseOptions.assumeJagged)
7571 {
7572     alias RangeOfRanges = Unqual!(Ror);
7573     alias RangeType     = .ElementType!RangeOfRanges;
7574     alias ElementType   = .ElementType!RangeType;
7575 
7576     private void prime()
7577     {
7578         static if (opt == TransverseOptions.assumeJagged)
7579         {
7580             while (!_input.empty && _input.front.empty)
7581             {
7582                 _input.popFront();
7583             }
7584             static if (isBidirectionalRange!RangeOfRanges)
7585             {
7586                 while (!_input.empty && _input.back.empty)
7587                 {
7588                     _input.popBack();
7589                 }
7590             }
7591         }
7592     }
7593 
7594 /**
7595    Construction from an input.
7596 */
7597     this(RangeOfRanges input)
7598     {
7599         _input = input;
7600         prime();
7601         static if (opt == TransverseOptions.enforceNotJagged)
7602             // (isRandomAccessRange!RangeOfRanges
7603             //     && hasLength!RangeType)
7604         {
7605             import std.exception : enforce;
7606 
7607             if (empty) return;
7608             immutable commonLength = _input.front.length;
7609             foreach (e; _input)
7610             {
7611                 enforce(e.length == commonLength);
7612             }
7613         }
7614     }
7615 
7616 /**
7617    Forward range primitives.
7618 */
7619     static if (isInfinite!RangeOfRanges)
7620     {
7621         enum bool empty = false;
7622     }
7623     else
7624     {
7625         @property bool empty()
7626         {
7627             static if (opt != TransverseOptions.assumeJagged)
7628             {
7629                 if (!_input.empty)
7630                     return _input.front.empty;
7631             }
7632 
7633             return _input.empty;
7634         }
7635     }
7636 
7637     /// Ditto
7638     @property auto ref front()
7639     {
7640         assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
7641         return _input.front.front;
7642     }
7643 
7644     /// Ditto
7645     static if (hasMobileElements!RangeType)
7646     {
7647         ElementType moveFront()
7648         {
7649             return _input.front.moveFront();
7650         }
7651     }
7652 
7653     static if (hasAssignableElements!RangeType)
7654     {
7655         @property void front(ElementType val)
7656         {
7657             import core.lifetime : forward;
7658 
7659             // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7660             _input.front.front = __ctfe ? val : forward!val;
7661         }
7662     }
7663 
7664     /// Ditto
7665     void popFront()
7666     {
7667         assert(!empty, "Attempting to popFront an empty FrontTransversal");
7668         _input.popFront();
7669         prime();
7670     }
7671 
7672 /**
7673    Duplicates this `frontTransversal`. Note that only the encapsulating
7674    range of range will be duplicated. Underlying ranges will not be
7675    duplicated.
7676 */
7677     static if (isForwardRange!RangeOfRanges)
7678     {
7679         @property FrontTransversal save()
7680         {
7681             return FrontTransversal(_input.save);
7682         }
7683     }
7684 
7685     static if (isBidirectionalRange!RangeOfRanges)
7686     {
7687 /**
7688    Bidirectional primitives. They are offered if $(D
7689    isBidirectionalRange!RangeOfRanges).
7690 */
7691         @property auto ref back()
7692         {
7693             assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7694             return _input.back.front;
7695         }
7696         /// Ditto
7697         void popBack()
7698         {
7699             assert(!empty, "Attempting to popBack an empty FrontTransversal");
7700             _input.popBack();
7701             prime();
7702         }
7703 
7704         /// Ditto
7705         static if (hasMobileElements!RangeType)
7706         {
7707             ElementType moveBack()
7708             {
7709                 return _input.back.moveFront();
7710             }
7711         }
7712 
7713         static if (hasAssignableElements!RangeType)
7714         {
7715             @property void back(ElementType val)
7716             {
7717                 import core.lifetime : forward;
7718 
7719                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7720                 _input.back.front = __ctfe ? val : forward!val;
7721             }
7722         }
7723     }
7724 
7725     static if (isRandomAccessRange!RangeOfRanges &&
7726             (opt == TransverseOptions.assumeNotJagged ||
7727                     opt == TransverseOptions.enforceNotJagged))
7728     {
7729 /**
7730    Random-access primitive. It is offered if $(D
7731    isRandomAccessRange!RangeOfRanges && (opt ==
7732    TransverseOptions.assumeNotJagged || opt ==
7733    TransverseOptions.enforceNotJagged)).
7734 */
7735         auto ref opIndex(size_t n)
7736         {
7737             return _input[n].front;
7738         }
7739 
7740         /// Ditto
7741         static if (hasMobileElements!RangeType)
7742         {
7743             ElementType moveAt(size_t n)
7744             {
7745                 return _input[n].moveFront();
7746             }
7747         }
7748         /// Ditto
7749         static if (hasAssignableElements!RangeType)
7750         {
7751             void opIndexAssign(ElementType val, size_t n)
7752             {
7753                 import core.lifetime : forward;
7754 
7755                 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7756                 _input[n].front = __ctfe ? val : forward!val;
7757             }
7758         }
7759         mixin ImplementLength!_input;
7760 
7761 /**
7762    Slicing if offered if `RangeOfRanges` supports slicing and all the
7763    conditions for supporting indexing are met.
7764 */
7765         static if (hasSlicing!RangeOfRanges)
7766         {
7767             typeof(this) opSlice(size_t lower, size_t upper)
7768             {
7769                 return typeof(this)(_input[lower .. upper]);
7770             }
7771         }
7772     }
7773 
7774     auto opSlice() { return this; }
7775 
7776 private:
7777     RangeOfRanges _input;
7778 }
7779 
7780 /// Ditto
7781 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7782     TransverseOptions opt = TransverseOptions.assumeJagged,
7783     RangeOfRanges)
7784 (RangeOfRanges rr)
7785 {
7786     return typeof(return)(rr);
7787 }
7788 
7789 ///
7790 pure @safe nothrow unittest
7791 {
7792     import std.algorithm.comparison : equal;
7793     int[][] x = new int[][2];
7794     x[0] = [1, 2];
7795     x[1] = [3, 4];
7796     auto ror = frontTransversal(x);
7797     assert(equal(ror, [ 1, 3 ][]));
7798 }
7799 
7800 @safe unittest
7801 {
7802     import std.algorithm.comparison : equal;
7803     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7804 
7805     static assert(is(FrontTransversal!(immutable int[][])));
7806 
7807     foreach (DummyType; AllDummyRanges)
7808     {
7809         auto dummies =
7810             [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7811 
7812         foreach (i, ref elem; dummies)
7813         {
7814             // Just violate the DummyRange abstraction to get what I want.
7815             elem.arr = elem.arr[i..$ - (3 - i)];
7816         }
7817 
7818         auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7819         static if (isForwardRange!DummyType)
7820         {
7821             static assert(isForwardRange!(typeof(ft)));
7822         }
7823 
7824         assert(equal(ft, [1, 2, 3, 4]));
7825 
7826         // Test slicing.
7827         assert(equal(ft[0 .. 2], [1, 2]));
7828         assert(equal(ft[1 .. 3], [2, 3]));
7829 
7830         assert(ft.front == ft.moveFront());
7831         assert(ft.back == ft.moveBack());
7832         assert(ft.moveAt(1) == ft[1]);
7833 
7834 
7835         // Test infiniteness propagation.
7836         static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7837 
7838         static if (DummyType.r == ReturnBy.Reference)
7839         {
7840             {
7841                 ft.front++;
7842                 scope(exit) ft.front--;
7843                 assert(dummies.front.front == 2);
7844             }
7845 
7846             {
7847                 ft.front = 5;
7848                 scope(exit) ft.front = 1;
7849                 assert(dummies[0].front == 5);
7850             }
7851 
7852             {
7853                 ft.back = 88;
7854                 scope(exit) ft.back = 4;
7855                 assert(dummies.back.front == 88);
7856             }
7857 
7858             {
7859                 ft[1] = 99;
7860                 scope(exit) ft[1] = 2;
7861                 assert(dummies[1].front == 99);
7862             }
7863         }
7864     }
7865 }
7866 
7867 // https://issues.dlang.org/show_bug.cgi?id=16363
7868 pure @safe nothrow unittest
7869 {
7870     import std.algorithm.comparison : equal;
7871 
7872     int[][] darr = [[0, 1], [4, 5]];
7873     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7874 
7875     assert(equal(ft, [0, 4]));
7876     static assert(isRandomAccessRange!(typeof(ft)));
7877 }
7878 
7879 // https://issues.dlang.org/show_bug.cgi?id=16442
7880 pure @safe nothrow unittest
7881 {
7882     int[][] arr = [[], []];
7883 
7884     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7885     assert(ft.empty);
7886 }
7887 
7888 // ditto
7889 pure @safe unittest
7890 {
7891     int[][] arr = [[], []];
7892 
7893     auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7894     assert(ft.empty);
7895 }
7896 
7897 // https://issues.dlang.org/show_bug.cgi?id=24481
7898 @safe unittest
7899 {
7900     bool called;
7901     struct Handle
7902     {
7903         int entry;
7904         void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
7905     }
7906 
7907     const(Handle)[][] arr = [[Handle(0), Handle(10)],
7908                              [Handle(1), Handle(11)],
7909                              [Handle(2), Handle(12)],
7910                              [Handle(3), Handle(13)],
7911                              [Handle(4), Handle(14)]];
7912 
7913     {
7914         auto range = arr.frontTransversal();
7915 
7916         called = false;
7917         range.front = Handle(42);
7918         assert(called == true);
7919 
7920         called = false;
7921         range.back = Handle(42);
7922         assert(called == true);
7923     }
7924     {
7925         auto range = arr.frontTransversal!(TransverseOptions.assumeNotJagged)();
7926 
7927         called = false;
7928         range.front = Handle(42);
7929         assert(called == true);
7930 
7931         called = false;
7932         range.back = Handle(42);
7933         assert(called == true);
7934 
7935         called = false;
7936         range[0] = Handle(42);
7937         assert(called == true);
7938     }
7939 }
7940 
7941 /**
7942     Given a range of ranges, iterate transversally through the
7943     `n`th element of each of the enclosed ranges. This function
7944     is similar to `unzip` in other languages.
7945 
7946     Params:
7947         opt = Controls the assumptions the function makes about the lengths
7948         of the ranges
7949         rr = An input range of random access ranges
7950     Returns:
7951         At minimum, an input range. Range primitives such as bidirectionality
7952         and random access are given if the element type of `rr` provides them.
7953 */
7954 struct Transversal(Ror,
7955         TransverseOptions opt = TransverseOptions.assumeJagged)
7956 {
7957     private alias RangeOfRanges = Unqual!Ror;
7958     private alias InnerRange = ElementType!RangeOfRanges;
7959     private alias E = ElementType!InnerRange;
7960 
7961     private void prime()
7962     {
7963         static if (opt == TransverseOptions.assumeJagged)
7964         {
7965             while (!_input.empty && _input.front.length <= _n)
7966             {
7967                 _input.popFront();
7968             }
7969             static if (isBidirectionalRange!RangeOfRanges)
7970             {
7971                 while (!_input.empty && _input.back.length <= _n)
7972                 {
7973                     _input.popBack();
7974                 }
7975             }
7976         }
7977     }
7978 
7979 /**
7980    Construction from an input and an index.
7981 */
7982     this(RangeOfRanges input, size_t n)
7983     {
7984         _input = input;
7985         _n = n;
7986         prime();
7987         static if (opt == TransverseOptions.enforceNotJagged)
7988         {
7989             import std.exception : enforce;
7990 
7991             if (empty) return;
7992             immutable commonLength = _input.front.length;
7993             foreach (e; _input)
7994             {
7995                 enforce(e.length == commonLength);
7996             }
7997         }
7998     }
7999 
8000 /**
8001    Forward range primitives.
8002 */
8003     static if (isInfinite!(RangeOfRanges))
8004     {
8005         enum bool empty = false;
8006     }
8007     else
8008     {
8009         @property bool empty()
8010         {
8011             return _input.empty;
8012         }
8013     }
8014 
8015     /// Ditto
8016     @property auto ref front()
8017     {
8018         assert(!empty, "Attempting to fetch the front of an empty Transversal");
8019         return _input.front[_n];
8020     }
8021 
8022     /// Ditto
8023     static if (hasMobileElements!InnerRange)
8024     {
8025         E moveFront()
8026         {
8027             return _input.front.moveAt(_n);
8028         }
8029     }
8030 
8031     /// Ditto
8032     static if (hasAssignableElements!InnerRange)
8033     {
8034         @property void front(E val)
8035         {
8036             _input.front[_n] = val;
8037         }
8038     }
8039 
8040 
8041     /// Ditto
8042     void popFront()
8043     {
8044         assert(!empty, "Attempting to popFront an empty Transversal");
8045         _input.popFront();
8046         prime();
8047     }
8048 
8049     /// Ditto
8050     static if (isForwardRange!RangeOfRanges)
8051     {
8052         @property typeof(this) save()
8053         {
8054             auto ret = this;
8055             ret._input = _input.save;
8056             return ret;
8057         }
8058     }
8059 
8060     static if (isBidirectionalRange!RangeOfRanges)
8061     {
8062 /**
8063    Bidirectional primitives. They are offered if $(D
8064    isBidirectionalRange!RangeOfRanges).
8065 */
8066         @property auto ref back()
8067         {
8068             assert(!empty, "Attempting to fetch the back of an empty Transversal");
8069             return _input.back[_n];
8070         }
8071 
8072         /// Ditto
8073         void popBack()
8074         {
8075             assert(!empty, "Attempting to popBack an empty Transversal");
8076             _input.popBack();
8077             prime();
8078         }
8079 
8080         /// Ditto
8081         static if (hasMobileElements!InnerRange)
8082         {
8083             E moveBack()
8084             {
8085                 return _input.back.moveAt(_n);
8086             }
8087         }
8088 
8089         /// Ditto
8090         static if (hasAssignableElements!InnerRange)
8091         {
8092             @property void back(E val)
8093             {
8094                 _input.back[_n] = val;
8095             }
8096         }
8097 
8098     }
8099 
8100     static if (isRandomAccessRange!RangeOfRanges &&
8101             (opt == TransverseOptions.assumeNotJagged ||
8102                     opt == TransverseOptions.enforceNotJagged))
8103     {
8104 /**
8105    Random-access primitive. It is offered if $(D
8106    isRandomAccessRange!RangeOfRanges && (opt ==
8107    TransverseOptions.assumeNotJagged || opt ==
8108    TransverseOptions.enforceNotJagged)).
8109 */
8110         auto ref opIndex(size_t n)
8111         {
8112             return _input[n][_n];
8113         }
8114 
8115         /// Ditto
8116         static if (hasMobileElements!InnerRange)
8117         {
8118             E moveAt(size_t n)
8119             {
8120                 return _input[n].moveAt(_n);
8121             }
8122         }
8123 
8124         /// Ditto
8125         static if (hasAssignableElements!InnerRange)
8126         {
8127             void opIndexAssign(E val, size_t n)
8128             {
8129                 _input[n][_n] = val;
8130             }
8131         }
8132 
8133         mixin ImplementLength!_input;
8134 
8135 /**
8136    Slicing if offered if `RangeOfRanges` supports slicing and all the
8137    conditions for supporting indexing are met.
8138 */
8139         static if (hasSlicing!RangeOfRanges)
8140         {
8141             typeof(this) opSlice(size_t lower, size_t upper)
8142             {
8143                 return typeof(this)(_input[lower .. upper], _n);
8144             }
8145         }
8146     }
8147 
8148     auto opSlice() { return this; }
8149 
8150 private:
8151     RangeOfRanges _input;
8152     size_t _n;
8153 }
8154 
8155 /// Ditto
8156 Transversal!(RangeOfRanges, opt) transversal
8157 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8158 (RangeOfRanges rr, size_t n)
8159 {
8160     return typeof(return)(rr, n);
8161 }
8162 
8163 ///
8164 @safe unittest
8165 {
8166     import std.algorithm.comparison : equal;
8167     int[][] x = new int[][2];
8168     x[0] = [1, 2];
8169     x[1] = [3, 4];
8170     auto ror = transversal(x, 1);
8171     assert(equal(ror, [ 2, 4 ]));
8172 }
8173 
8174 /// The following code does a full unzip
8175 @safe unittest
8176 {
8177     import std.algorithm.comparison : equal;
8178     import std.algorithm.iteration : map;
8179     int[][] y = [[1, 2, 3], [4, 5, 6]];
8180     auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
8181     assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
8182 }
8183 
8184 @safe unittest
8185 {
8186     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
8187 
8188     int[][] x = new int[][2];
8189     x[0] = [ 1, 2 ];
8190     x[1] = [3, 4];
8191     auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
8192     auto witness = [ 2, 4 ];
8193     uint i;
8194     foreach (e; ror) assert(e == witness[i++]);
8195     assert(i == 2);
8196     assert(ror.length == 2);
8197 
8198     static assert(is(Transversal!(immutable int[][])));
8199 
8200     // Make sure ref, assign is being propagated.
8201     {
8202         ror.front++;
8203         scope(exit) ror.front--;
8204         assert(x[0][1] == 3);
8205     }
8206     {
8207         ror.front = 5;
8208         scope(exit) ror.front = 2;
8209         assert(x[0][1] == 5);
8210         assert(ror.moveFront() == 5);
8211     }
8212     {
8213         ror.back = 999;
8214         scope(exit) ror.back = 4;
8215         assert(x[1][1] == 999);
8216         assert(ror.moveBack() == 999);
8217     }
8218     {
8219         ror[0] = 999;
8220         scope(exit) ror[0] = 2;
8221         assert(x[0][1] == 999);
8222         assert(ror.moveAt(0) == 999);
8223     }
8224 
8225     // Test w/o ref return.
8226     alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
8227     auto drs = [D.init, D.init];
8228     foreach (num; 0 .. 10)
8229     {
8230         auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
8231         assert(t[0] == t[1]);
8232         assert(t[1] == num + 1);
8233     }
8234 
8235     static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
8236 
8237     // Test slicing.
8238     auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
8239     auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
8240     assert(mat1[0] == 6);
8241     assert(mat1[1] == 10);
8242 }
8243 
8244 struct Transposed(RangeOfRanges,
8245     TransverseOptions opt = TransverseOptions.assumeJagged)
8246 if (isForwardRange!RangeOfRanges &&
8247     isInputRange!(ElementType!RangeOfRanges) &&
8248     hasAssignableElements!RangeOfRanges)
8249 {
8250     this(RangeOfRanges input)
8251     {
8252         this._input = input;
8253         static if (opt == TransverseOptions.enforceNotJagged)
8254         {
8255             import std.exception : enforce;
8256 
8257             if (empty) return;
8258             immutable commonLength = _input.front.length;
8259             foreach (e; _input)
8260             {
8261                 enforce(e.length == commonLength);
8262             }
8263         }
8264     }
8265 
8266     @property auto front()
8267     {
8268         import std.algorithm.iteration : filter, map;
8269         return _input.save
8270                      .filter!(a => !a.empty)
8271                      .map!(a => a.front);
8272     }
8273 
8274     void popFront()
8275     {
8276         // Advance the position of each subrange.
8277         auto r = _input.save;
8278         while (!r.empty)
8279         {
8280             auto e = r.front;
8281             if (!e.empty)
8282             {
8283                 e.popFront();
8284                 r.front = e;
8285             }
8286 
8287             r.popFront();
8288         }
8289     }
8290 
8291     static if (isRandomAccessRange!(ElementType!RangeOfRanges))
8292     {
8293         auto ref opIndex(size_t n)
8294         {
8295             return transversal!opt(_input, n);
8296         }
8297     }
8298 
8299     @property bool empty()
8300     {
8301         if (_input.empty) return true;
8302         foreach (e; _input.save)
8303         {
8304             if (!e.empty) return false;
8305         }
8306         return true;
8307     }
8308 
8309     auto opSlice() { return this; }
8310 
8311 private:
8312     RangeOfRanges _input;
8313 }
8314 
8315 @safe unittest
8316 {
8317     // Boundary case: transpose of empty range should be empty
8318     int[][] ror = [];
8319     assert(transposed(ror).empty);
8320 }
8321 
8322 // https://issues.dlang.org/show_bug.cgi?id=9507
8323 @safe unittest
8324 {
8325     import std.algorithm.comparison : equal;
8326 
8327     auto r = [[1,2], [3], [4,5], [], [6]];
8328     assert(r.transposed.equal!equal([
8329         [1, 3, 4, 6],
8330         [2, 5]
8331     ]));
8332 }
8333 
8334 // https://issues.dlang.org/show_bug.cgi?id=17742
8335 @safe unittest
8336 {
8337     import std.algorithm.iteration : map;
8338     import std.algorithm.comparison : equal;
8339     auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
8340     assert(ror[3][2] == 6);
8341     auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
8342     assert(result[2][3] == 6);
8343 
8344     auto x = [[1,2,3],[4,5,6]];
8345     auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
8346     assert(y.front.equal([1,4]));
8347     assert(y[0].equal([1,4]));
8348     assert(y[0][0] == 1);
8349     assert(y[1].equal([2,5]));
8350     assert(y[1][1] == 5);
8351 
8352     auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
8353     assert(yy.front.equal([1,4]));
8354     assert(yy[0].equal([1,4]));
8355     assert(yy[0][0] == 1);
8356     assert(yy[1].equal([2,5]));
8357     assert(yy[1][1] == 5);
8358 
8359     auto z = x.transposed; // assumeJagged
8360     assert(z.front.equal([1,4]));
8361     assert(z[0].equal([1,4]));
8362     assert(!is(typeof(z[0][0])));
8363 }
8364 
8365 @safe unittest
8366 {
8367     import std.exception : assertThrown;
8368 
8369     auto r = [[1,2], [3], [4,5], [], [6]];
8370     assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
8371 }
8372 
8373 /**
8374 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
8375 contains the $(I i)'th elements of the original subranges.
8376 
8377 Params:
8378     opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
8379     rr = Range of ranges
8380  */
8381 Transposed!(RangeOfRanges, opt) transposed
8382 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8383 (RangeOfRanges rr)
8384 if (isForwardRange!RangeOfRanges &&
8385     isInputRange!(ElementType!RangeOfRanges) &&
8386     hasAssignableElements!RangeOfRanges)
8387 {
8388     return Transposed!(RangeOfRanges, opt)(rr);
8389 }
8390 
8391 ///
8392 @safe unittest
8393 {
8394     import std.algorithm.comparison : equal;
8395     int[][] ror = [
8396         [1, 2, 3],
8397         [4, 5, 6]
8398     ];
8399     auto xp = transposed(ror);
8400     assert(equal!"a.equal(b)"(xp, [
8401         [1, 4],
8402         [2, 5],
8403         [3, 6]
8404     ]));
8405 }
8406 
8407 ///
8408 @safe unittest
8409 {
8410     int[][] x = new int[][2];
8411     x[0] = [1, 2];
8412     x[1] = [3, 4];
8413     auto tr = transposed(x);
8414     int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
8415     uint i;
8416 
8417     foreach (e; tr)
8418     {
8419         assert(array(e) == witness[i++]);
8420     }
8421 }
8422 
8423 // https://issues.dlang.org/show_bug.cgi?id=8764
8424 @safe unittest
8425 {
8426     import std.algorithm.comparison : equal;
8427     ulong[] t0 = [ 123 ];
8428 
8429     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
8430     assert(!is(typeof(transposed(t0[].chunks(1)))));
8431     assert(is(typeof(transposed(t0[].chunks(1).array()))));
8432 
8433     auto t1 = transposed(t0[].chunks(1).array());
8434     assert(equal!"a.equal(b)"(t1, [[123]]));
8435 }
8436 
8437 /**
8438 This struct takes two ranges, `source` and `indices`, and creates a view
8439 of `source` as if its elements were reordered according to `indices`.
8440 `indices` may include only a subset of the elements of `source` and
8441 may also repeat elements.
8442 
8443 `Source` must be a random access range.  The returned range will be
8444 bidirectional or random-access if `Indices` is bidirectional or
8445 random-access, respectively.
8446 */
8447 struct Indexed(Source, Indices)
8448 if (isRandomAccessRange!Source && isInputRange!Indices &&
8449     is(typeof(Source.init[ElementType!(Indices).init])))
8450 {
8451     this(Source source, Indices indices)
8452     {
8453         this._source = source;
8454         this._indices = indices;
8455     }
8456 
8457     /// Range primitives
8458     @property auto ref front()
8459     {
8460         assert(!empty, "Attempting to fetch the front of an empty Indexed");
8461         return _source[_indices.front];
8462     }
8463 
8464     /// Ditto
8465     void popFront()
8466     {
8467         assert(!empty, "Attempting to popFront an empty Indexed");
8468         _indices.popFront();
8469     }
8470 
8471     static if (isInfinite!Indices)
8472     {
8473         enum bool empty = false;
8474     }
8475     else
8476     {
8477         /// Ditto
8478         @property bool empty()
8479         {
8480             return _indices.empty;
8481         }
8482     }
8483 
8484     static if (isForwardRange!Indices)
8485     {
8486         /// Ditto
8487         @property typeof(this) save()
8488         {
8489             // Don't need to save _source because it's never consumed.
8490             return typeof(this)(_source, _indices.save);
8491         }
8492     }
8493 
8494     /// Ditto
8495     static if (hasAssignableElements!Source)
8496     {
8497         @property auto ref front(ElementType!Source newVal)
8498         {
8499             assert(!empty);
8500             return _source[_indices.front] = newVal;
8501         }
8502     }
8503 
8504 
8505     static if (hasMobileElements!Source)
8506     {
8507         /// Ditto
8508         auto moveFront()
8509         {
8510             assert(!empty);
8511             return _source.moveAt(_indices.front);
8512         }
8513     }
8514 
8515     static if (isBidirectionalRange!Indices)
8516     {
8517         /// Ditto
8518         @property auto ref back()
8519         {
8520             assert(!empty, "Attempting to fetch the back of an empty Indexed");
8521             return _source[_indices.back];
8522         }
8523 
8524         /// Ditto
8525         void popBack()
8526         {
8527            assert(!empty, "Attempting to popBack an empty Indexed");
8528            _indices.popBack();
8529         }
8530 
8531         /// Ditto
8532         static if (hasAssignableElements!Source)
8533         {
8534             @property auto ref back(ElementType!Source newVal)
8535             {
8536                 assert(!empty);
8537                 return _source[_indices.back] = newVal;
8538             }
8539         }
8540 
8541 
8542         static if (hasMobileElements!Source)
8543         {
8544             /// Ditto
8545             auto moveBack()
8546             {
8547                 assert(!empty);
8548                 return _source.moveAt(_indices.back);
8549             }
8550         }
8551     }
8552 
8553     mixin ImplementLength!_indices;
8554 
8555     static if (isRandomAccessRange!Indices)
8556     {
8557         /// Ditto
8558         auto ref opIndex(size_t index)
8559         {
8560             return _source[_indices[index]];
8561         }
8562 
8563         static if (hasSlicing!Indices)
8564         {
8565             /// Ditto
8566             typeof(this) opSlice(size_t a, size_t b)
8567             {
8568                 return typeof(this)(_source, _indices[a .. b]);
8569             }
8570         }
8571 
8572 
8573         static if (hasAssignableElements!Source)
8574         {
8575             /// Ditto
8576             auto opIndexAssign(ElementType!Source newVal, size_t index)
8577             {
8578                 return _source[_indices[index]] = newVal;
8579             }
8580         }
8581 
8582 
8583         static if (hasMobileElements!Source)
8584         {
8585             /// Ditto
8586             auto moveAt(size_t index)
8587             {
8588                 return _source.moveAt(_indices[index]);
8589             }
8590         }
8591     }
8592 
8593     // All this stuff is useful if someone wants to index an Indexed
8594     // without adding a layer of indirection.
8595 
8596     /**
8597     Returns the source range.
8598     */
8599     @property Source source()
8600     {
8601         return _source;
8602     }
8603 
8604     /**
8605     Returns the indices range.
8606     */
8607      @property Indices indices()
8608     {
8609         return _indices;
8610     }
8611 
8612     static if (isRandomAccessRange!Indices)
8613     {
8614         /**
8615         Returns the physical index into the source range corresponding to a
8616         given logical index.  This is useful, for example, when indexing
8617         an `Indexed` without adding another layer of indirection.
8618         */
8619         size_t physicalIndex(size_t logicalIndex)
8620         {
8621             return _indices[logicalIndex];
8622         }
8623 
8624         ///
8625         @safe unittest
8626         {
8627             auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8628             assert(ind.physicalIndex(0) == 1);
8629         }
8630     }
8631 
8632 private:
8633     Source _source;
8634     Indices _indices;
8635 
8636 }
8637 
8638 /// Ditto
8639 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
8640 {
8641     return typeof(return)(source, indices);
8642 }
8643 
8644 ///
8645 @safe unittest
8646 {
8647     import std.algorithm.comparison : equal;
8648     auto source = [1, 2, 3, 4, 5];
8649     auto indices = [4, 3, 1, 2, 0, 4];
8650     auto ind = indexed(source, indices);
8651     assert(equal(ind, [5, 4, 2, 3, 1, 5]));
8652     assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
8653 }
8654 
8655 @safe unittest
8656 {
8657     {
8658         auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8659         assert(ind.physicalIndex(0) == 1);
8660     }
8661 
8662     auto source = [1, 2, 3, 4, 5];
8663     auto indices = [4, 3, 1, 2, 0, 4];
8664     auto ind = indexed(source, indices);
8665 
8666     // When elements of indices are duplicated and Source has lvalue elements,
8667     // these are aliased in ind.
8668     ind[0]++;
8669     assert(ind[0] == 6);
8670     assert(ind[5] == 6);
8671 }
8672 
8673 @safe unittest
8674 {
8675     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
8676         propagatesRangeType, RangeType;
8677 
8678     foreach (DummyType; AllDummyRanges)
8679     {
8680         auto d = DummyType.init;
8681         auto r = indexed([1, 2, 3, 4, 5], d);
8682         static assert(propagatesRangeType!(DummyType, typeof(r)));
8683         static assert(propagatesLength!(DummyType, typeof(r)));
8684     }
8685 }
8686 
8687 /**
8688 This range iterates over fixed-sized chunks of size `chunkSize` of a
8689 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8690 `chunkSize` must be greater than zero.
8691 
8692 If `!isInfinite!Source` and `source.walkLength` is not evenly
8693 divisible by `chunkSize`, the back element of this range will contain
8694 fewer than `chunkSize` elements.
8695 
8696 If `Source` is a forward range, the resulting range will be forward ranges as
8697 well. Otherwise, the resulting chunks will be input ranges consuming the same
8698 input: iterating over `front` will shrink the chunk such that subsequent
8699 invocations of `front` will no longer return the full chunk, and calling
8700 `popFront` on the outer range will invalidate any lingering references to
8701 previous values of `front`.
8702 
8703 Params:
8704     source = Range from which the chunks will be selected
8705     chunkSize = Chunk size
8706 
8707 See_Also: $(LREF slide)
8708 
8709 Returns: Range of chunks.
8710 */
8711 struct Chunks(Source)
8712 if (isInputRange!Source)
8713 {
8714     static if (isForwardRange!Source)
8715     {
8716         /// Standard constructor
8717         this(Source source, size_t chunkSize)
8718         {
8719             assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8720             _source = source;
8721             _chunkSize = chunkSize;
8722         }
8723 
8724         /// Input range primitives. Always present.
8725         @property auto front()
8726         {
8727             assert(!empty, "Attempting to fetch the front of an empty Chunks");
8728             return _source.save.take(_chunkSize);
8729         }
8730 
8731         /// Ditto
8732         void popFront()
8733         {
8734             assert(!empty, "Attempting to popFront and empty Chunks");
8735             _source.popFrontN(_chunkSize);
8736         }
8737 
8738         static if (!isInfinite!Source)
8739             /// Ditto
8740             @property bool empty()
8741             {
8742                 return _source.empty;
8743             }
8744         else
8745             // undocumented
8746             enum empty = false;
8747 
8748         /// Forward range primitives. Only present if `Source` is a forward range.
8749         @property typeof(this) save()
8750         {
8751             return typeof(this)(_source.save, _chunkSize);
8752         }
8753 
8754         static if (hasLength!Source)
8755         {
8756             /// Length. Only if `hasLength!Source` is `true`
8757             @property size_t length()
8758             {
8759                 // Note: _source.length + _chunkSize may actually overflow.
8760                 // We cast to ulong to mitigate the problem on x86 machines.
8761                 // For x64 machines, we just suppose we'll never overflow.
8762                 // The "safe" code would require either an extra branch, or a
8763                 //   modulo operation, which is too expensive for such a rare case
8764                 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8765             }
8766             //Note: No point in defining opDollar here without slicing.
8767             //opDollar is defined below in the hasSlicing!Source section
8768         }
8769 
8770         static if (hasSlicing!Source)
8771         {
8772             //Used for various purposes
8773             private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8774 
8775             /**
8776             Indexing and slicing operations. Provided only if
8777             `hasSlicing!Source` is `true`.
8778              */
8779             auto opIndex(size_t index)
8780             {
8781                 immutable start = index * _chunkSize;
8782                 immutable end   = start + _chunkSize;
8783 
8784                 static if (isInfinite!Source)
8785                     return _source[start .. end];
8786                 else
8787                 {
8788                     import std.algorithm.comparison : min;
8789                     immutable len = _source.length;
8790                     assert(start < len, "chunks index out of bounds");
8791                     return _source[start .. min(end, len)];
8792                 }
8793             }
8794 
8795             /// Ditto
8796             static if (hasLength!Source)
8797                 typeof(this) opSlice(size_t lower, size_t upper)
8798                 {
8799                     import std.algorithm.comparison : min;
8800                     assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8801                     immutable len = _source.length;
8802                     return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8803                 }
8804             else static if (hasSliceToEnd)
8805                 //For slicing an infinite chunk, we need to slice the source to the end.
8806                 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8807                 {
8808                     assert(lower <= upper, "chunks slicing index out of bounds");
8809                     return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8810                 }
8811 
8812             static if (isInfinite!Source)
8813             {
8814                 static if (hasSliceToEnd)
8815                 {
8816                     private static struct DollarToken{}
8817                     DollarToken opDollar()
8818                     {
8819                         return DollarToken();
8820                     }
8821                     //Slice to dollar
8822                     typeof(this) opSlice(size_t lower, DollarToken)
8823                     {
8824                         return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8825                     }
8826                 }
8827             }
8828             else
8829             {
8830                 //Dollar token carries a static type, with no extra information.
8831                 //It can lazily transform into _source.length on algorithmic
8832                 //operations such as : chunks[$/2, $-1];
8833                 private static struct DollarToken
8834                 {
8835                     Chunks!Source* mom;
8836                     @property size_t momLength()
8837                     {
8838                         return mom.length;
8839                     }
8840                     alias momLength this;
8841                 }
8842                 DollarToken opDollar()
8843                 {
8844                     return DollarToken(&this);
8845                 }
8846 
8847                 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8848                 //1. Evaluate chunks.length
8849                 //2. Multiply by _chunksSize
8850                 //3. To finally just compare it (with min) to the original length of source (!)
8851                 //These overloads avoid that.
8852                 typeof(this) opSlice(DollarToken, DollarToken)
8853                 {
8854                     static if (hasSliceToEnd)
8855                         return chunks(_source[$ .. $], _chunkSize);
8856                     else
8857                     {
8858                         immutable len = _source.length;
8859                         return chunks(_source[len .. len], _chunkSize);
8860                     }
8861                 }
8862                 typeof(this) opSlice(size_t lower, DollarToken)
8863                 {
8864                     import std.algorithm.comparison : min;
8865                     assert(lower <= length, "chunks slicing index out of bounds");
8866                     static if (hasSliceToEnd)
8867                         return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8868                     else
8869                     {
8870                         immutable len = _source.length;
8871                         return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8872                     }
8873                 }
8874                 typeof(this) opSlice(DollarToken, size_t upper)
8875                 {
8876                     assert(upper == length, "chunks slicing index out of bounds");
8877                     return this[$ .. $];
8878                 }
8879             }
8880         }
8881 
8882         //Bidirectional range primitives
8883         static if (hasSlicing!Source && hasLength!Source)
8884         {
8885             /**
8886             Bidirectional range primitives. Provided only if both
8887             `hasSlicing!Source` and `hasLength!Source` are `true`.
8888              */
8889             @property auto back()
8890             {
8891                 assert(!empty, "back called on empty chunks");
8892                 immutable len = _source.length;
8893                 immutable start = (len - 1) / _chunkSize * _chunkSize;
8894                 return _source[start .. len];
8895             }
8896 
8897             /// Ditto
8898             void popBack()
8899             {
8900                 assert(!empty, "popBack() called on empty chunks");
8901                 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8902                 _source = _source[0 .. end];
8903             }
8904         }
8905 
8906     private:
8907         Source _source;
8908         size_t _chunkSize;
8909     }
8910     else // is input range only
8911     {
8912         import std.typecons : RefCounted;
8913 
8914         static struct Chunk
8915         {
8916             private RefCounted!Impl impl;
8917 
8918             @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8919             @property auto front() { return impl.r.front; }
8920             void popFront()
8921             {
8922                 assert(impl.curSizeLeft > 0 && !impl.r.empty);
8923                 impl.curSizeLeft--;
8924                 impl.r.popFront();
8925             }
8926         }
8927 
8928         static struct Impl
8929         {
8930             private Source r;
8931             private size_t chunkSize;
8932             private size_t curSizeLeft;
8933         }
8934 
8935         private RefCounted!Impl impl;
8936 
8937         private this(Source r, size_t chunkSize)
8938         {
8939             impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8940         }
8941 
8942         @property bool empty() { return impl.chunkSize == 0; }
8943         @property Chunk front() return { return Chunk(impl); }
8944 
8945         void popFront()
8946         {
8947             impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8948             if (!impl.r.empty)
8949                 impl.curSizeLeft = impl.chunkSize;
8950             else
8951                 impl.chunkSize = 0;
8952         }
8953 
8954         static assert(isInputRange!(typeof(this)));
8955     }
8956 }
8957 
8958 /// Ditto
8959 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8960 if (isInputRange!Source)
8961 {
8962     return typeof(return)(source, chunkSize);
8963 }
8964 
8965 ///
8966 @safe unittest
8967 {
8968     import std.algorithm.comparison : equal;
8969     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8970     auto chunks = chunks(source, 4);
8971     assert(chunks[0] == [1, 2, 3, 4]);
8972     assert(chunks[1] == [5, 6, 7, 8]);
8973     assert(chunks[2] == [9, 10]);
8974     assert(chunks.back == chunks[2]);
8975     assert(chunks.front == chunks[0]);
8976     assert(chunks.length == 3);
8977     assert(equal(retro(array(chunks)), array(retro(chunks))));
8978 }
8979 
8980 /// Non-forward input ranges are supported, but with limited semantics.
8981 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8982 {
8983     import std.algorithm.comparison : equal;
8984 
8985     int i;
8986 
8987     // The generator doesn't save state, so it cannot be a forward range.
8988     auto inputRange = generate!(() => ++i).take(10);
8989 
8990     // We can still process it in chunks, but it will be single-pass only.
8991     auto chunked = inputRange.chunks(2);
8992 
8993     assert(chunked.front.equal([1, 2]));
8994     assert(chunked.front.empty); // Iterating the chunk has consumed it
8995     chunked.popFront;
8996     assert(chunked.front.equal([3, 4]));
8997 }
8998 
8999 @system /*@safe*/ unittest
9000 {
9001     import std.algorithm.comparison : equal;
9002     import std.internal.test.dummyrange : ReferenceInputRange;
9003 
9004     auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
9005     auto r = new ReferenceInputRange!int(data).chunks(3);
9006     assert(r.equal!equal([
9007         [ 1, 2, 3 ],
9008         [ 4, 5, 6 ],
9009         [ 7, 8, 9 ],
9010         [ 10 ]
9011     ]));
9012 
9013     auto data2 = [ 1, 2, 3, 4, 5, 6 ];
9014     auto r2 = new ReferenceInputRange!int(data2).chunks(3);
9015     assert(r2.equal!equal([
9016         [ 1, 2, 3 ],
9017         [ 4, 5, 6 ]
9018     ]));
9019 
9020     auto data3 = [ 1, 2, 3, 4, 5 ];
9021     auto r3 = new ReferenceInputRange!int(data3).chunks(2);
9022     assert(r3.front.equal([1, 2]));
9023     r3.popFront();
9024     assert(!r3.empty);
9025     r3.popFront();
9026     assert(r3.front.equal([5]));
9027 }
9028 
9029 @safe unittest
9030 {
9031     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9032     auto chunks = chunks(source, 4);
9033     auto chunks2 = chunks.save;
9034     chunks.popFront();
9035     assert(chunks[0] == [5, 6, 7, 8]);
9036     assert(chunks[1] == [9, 10]);
9037     chunks2.popBack();
9038     assert(chunks2[1] == [5, 6, 7, 8]);
9039     assert(chunks2.length == 2);
9040 
9041     static assert(isRandomAccessRange!(typeof(chunks)));
9042 }
9043 
9044 @safe unittest
9045 {
9046     import std.algorithm.comparison : equal;
9047 
9048     //Extra toying with slicing and indexing.
9049     auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
9050     auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
9051 
9052     assert(chunks1.length == 5);
9053     assert(chunks2.length == 5);
9054     assert(chunks1[4] == [4]);
9055     assert(chunks2[4] == [4, 4]);
9056     assert(chunks1.back == [4]);
9057     assert(chunks2.back == [4, 4]);
9058 
9059     assert(chunks1[0 .. 1].equal([[0, 0]]));
9060     assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
9061     assert(chunks1[4 .. 5].equal([[4]]));
9062     assert(chunks2[4 .. 5].equal([[4, 4]]));
9063 
9064     assert(chunks1[0 .. 0].equal((int[][]).init));
9065     assert(chunks1[5 .. 5].equal((int[][]).init));
9066     assert(chunks2[5 .. 5].equal((int[][]).init));
9067 
9068     //Fun with opDollar
9069     assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
9070     assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
9071     assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
9072     assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
9073     assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
9074     assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
9075 
9076     assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
9077 }
9078 
9079 @safe unittest
9080 {
9081     import std.algorithm.comparison : equal;
9082     import std.algorithm.iteration : filter;
9083 
9084     //ForwardRange
9085     auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
9086     assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
9087 
9088     //InfiniteRange w/o RA
9089     auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
9090     assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
9091 
9092     //InfiniteRange w/ RA and slicing
9093     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9094     auto oddsByPairs = odds.chunks(2);
9095     assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
9096 
9097     //Requires phobos#991 for Sequence to have slice to end
9098     static assert(hasSlicing!(typeof(odds)));
9099     assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
9100     assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
9101 }
9102 
9103 
9104 
9105 /**
9106 This range splits a `source` range into `chunkCount` chunks of
9107 approximately equal length. `Source` must be a forward range with
9108 known length.
9109 
9110 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
9111 The returned range will contain zero or more $(D source.length /
9112 chunkCount + 1) elements followed by $(D source.length / chunkCount)
9113 elements. If $(D source.length < chunkCount), some chunks will be empty.
9114 
9115 `chunkCount` must not be zero, unless `source` is also empty.
9116 */
9117 struct EvenChunks(Source)
9118 if (isForwardRange!Source && hasLength!Source)
9119 {
9120     /// Standard constructor
9121     this(Source source, size_t chunkCount)
9122     {
9123         assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
9124         _source = source;
9125         _chunkCount = chunkCount;
9126     }
9127 
9128     /// Forward range primitives. Always present.
9129     @property auto front()
9130     {
9131         assert(!empty, "Attempting to fetch the front of an empty evenChunks");
9132         return _source.save.take(_chunkPos(1));
9133     }
9134 
9135     /// Ditto
9136     void popFront()
9137     {
9138         assert(!empty, "Attempting to popFront an empty evenChunks");
9139         _source.popFrontN(_chunkPos(1));
9140         _chunkCount--;
9141     }
9142 
9143     /// Ditto
9144     @property bool empty()
9145     {
9146         return _chunkCount == 0;
9147     }
9148 
9149     /// Ditto
9150     @property typeof(this) save()
9151     {
9152         return typeof(this)(_source.save, _chunkCount);
9153     }
9154 
9155     /// Length
9156     @property size_t length() const
9157     {
9158         return _chunkCount;
9159     }
9160     //Note: No point in defining opDollar here without slicing.
9161     //opDollar is defined below in the hasSlicing!Source section
9162 
9163     static if (hasSlicing!Source)
9164     {
9165         /**
9166         Indexing, slicing and bidirectional operations and range primitives.
9167         Provided only if `hasSlicing!Source` is `true`.
9168          */
9169         auto opIndex(size_t index)
9170         {
9171             assert(index < _chunkCount, "evenChunks index out of bounds");
9172             return _source[_chunkPos(index) .. _chunkPos(index+1)];
9173         }
9174 
9175         /// Ditto
9176         typeof(this) opSlice(size_t lower, size_t upper)
9177         {
9178             assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
9179             return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
9180         }
9181 
9182         /// Ditto
9183         @property auto back()
9184         {
9185             assert(!empty, "back called on empty evenChunks");
9186             return _source[_chunkPos(_chunkCount - 1) .. _source.length];
9187         }
9188 
9189         /// Ditto
9190         void popBack()
9191         {
9192             assert(!empty, "popBack() called on empty evenChunks");
9193             _source = _source[0 .. _chunkPos(_chunkCount - 1)];
9194             _chunkCount--;
9195         }
9196     }
9197 
9198 private:
9199     Source _source;
9200     size_t _chunkCount;
9201 
9202     size_t _chunkPos(size_t i)
9203     {
9204         /*
9205             _chunkCount = 5, _source.length = 13:
9206 
9207                chunk0
9208                  |   chunk3
9209                  |     |
9210                  v     v
9211                 +-+-+-+-+-+   ^
9212                 |0|3|.| | |   |
9213                 +-+-+-+-+-+   | div
9214                 |1|4|.| | |   |
9215                 +-+-+-+-+-+   v
9216                 |2|5|.|
9217                 +-+-+-+
9218 
9219                 <----->
9220                   mod
9221 
9222                 <--------->
9223                 _chunkCount
9224 
9225             One column is one chunk.
9226             popFront and popBack pop the left-most
9227             and right-most column, respectively.
9228         */
9229 
9230         auto div = _source.length / _chunkCount;
9231         auto mod = _source.length % _chunkCount;
9232         auto pos = i <= mod
9233             ? i   * (div+1)
9234             : mod * (div+1) + (i-mod) * div
9235         ;
9236         //auto len = i < mod
9237         //    ? div+1
9238         //    : div
9239         //;
9240         return pos;
9241     }
9242 }
9243 
9244 /// Ditto
9245 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
9246 if (isForwardRange!Source && hasLength!Source)
9247 {
9248     return typeof(return)(source, chunkCount);
9249 }
9250 
9251 ///
9252 @safe unittest
9253 {
9254     import std.algorithm.comparison : equal;
9255     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9256     auto chunks = evenChunks(source, 3);
9257     assert(chunks[0] == [1, 2, 3, 4]);
9258     assert(chunks[1] == [5, 6, 7]);
9259     assert(chunks[2] == [8, 9, 10]);
9260 }
9261 
9262 @safe unittest
9263 {
9264     import std.algorithm.comparison : equal;
9265 
9266     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9267     auto chunks = evenChunks(source, 3);
9268     assert(chunks.back == chunks[2]);
9269     assert(chunks.front == chunks[0]);
9270     assert(chunks.length == 3);
9271     assert(equal(retro(array(chunks)), array(retro(chunks))));
9272 
9273     auto chunks2 = chunks.save;
9274     chunks.popFront();
9275     assert(chunks[0] == [5, 6, 7]);
9276     assert(chunks[1] == [8, 9, 10]);
9277     chunks2.popBack();
9278     assert(chunks2[1] == [5, 6, 7]);
9279     assert(chunks2.length == 2);
9280 
9281     static assert(isRandomAccessRange!(typeof(chunks)));
9282 }
9283 
9284 @safe unittest
9285 {
9286     import std.algorithm.comparison : equal;
9287 
9288     int[] source = [];
9289     auto chunks = source.evenChunks(0);
9290     assert(chunks.length == 0);
9291     chunks = source.evenChunks(3);
9292     assert(equal(chunks, [[], [], []]));
9293     chunks = [1, 2, 3].evenChunks(5);
9294     assert(equal(chunks, [[1], [2], [3], [], []]));
9295 }
9296 
9297 /**
9298 A fixed-sized sliding window iteration
9299 of size `windowSize` over a `source` range by a custom `stepSize`.
9300 
9301 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
9302 and the `windowSize` must be greater than zero.
9303 
9304 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
9305 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
9306 
9307 Params:
9308     f = Whether the last element has fewer elements than `windowSize`
9309         it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
9310     source = Range from which the slide will be selected
9311     windowSize = Sliding window size
9312     stepSize = Steps between the windows (by default 1)
9313 
9314 Returns: Range of all sliding windows with propagated bi-directionality,
9315          forwarding, random access, and slicing.
9316 
9317 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
9318       is only available when $(REF hasSlicing, std,range,primitives)
9319       and $(REF hasLength, std,range,primitives) are true.
9320 
9321 See_Also: $(LREF chunks)
9322 */
9323 auto slide(Flag!"withPartial" f = Yes.withPartial,
9324             Source)(Source source, size_t windowSize, size_t stepSize = 1)
9325 if (isForwardRange!Source)
9326 {
9327     return Slides!(f, Source)(source, windowSize, stepSize);
9328 }
9329 
9330 /// Iterate over ranges with windows
9331 @safe pure nothrow unittest
9332 {
9333     import std.algorithm.comparison : equal;
9334 
9335     assert([0, 1, 2, 3].slide(2).equal!equal(
9336         [[0, 1], [1, 2], [2, 3]]
9337     ));
9338 
9339     assert(5.iota.slide(3).equal!equal(
9340         [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
9341     ));
9342 }
9343 
9344 /// set a custom stepsize (default 1)
9345 @safe pure nothrow unittest
9346 {
9347     import std.algorithm.comparison : equal;
9348 
9349     assert(6.iota.slide(1, 2).equal!equal(
9350         [[0], [2], [4]]
9351     ));
9352 
9353     assert(6.iota.slide(2, 4).equal!equal(
9354         [[0, 1], [4, 5]]
9355     ));
9356 
9357     assert(iota(7).slide(2, 2).equal!equal(
9358         [[0, 1], [2, 3], [4, 5], [6]]
9359     ));
9360 
9361     assert(iota(12).slide(2, 4).equal!equal(
9362         [[0, 1], [4, 5], [8, 9]]
9363     ));
9364 }
9365 
9366 /// Allow the last slide to have fewer elements than windowSize
9367 @safe pure nothrow unittest
9368 {
9369     import std.algorithm.comparison : equal;
9370 
9371     assert(3.iota.slide!(No.withPartial)(4).empty);
9372     assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
9373         [[0, 1, 2]]
9374     ));
9375 }
9376 
9377 /// Count all the possible substrings of length 2
9378 @safe pure nothrow unittest
9379 {
9380     import std.algorithm.iteration : each;
9381 
9382     int[dstring] d;
9383     "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
9384     assert(d == ["AG"d: 2, "GA"d: 2]);
9385 }
9386 
9387 /// withPartial only has an effect if last element in the range doesn't have the full size
9388 @safe pure nothrow unittest
9389 {
9390     import std.algorithm.comparison : equal;
9391 
9392     assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
9393     assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
9394     assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9395 
9396     assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9397     assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9398     assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9399 }
9400 
9401 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
9402 if (isForwardRange!Source)
9403 {
9404 private:
9405     Source source;
9406     size_t windowSize;
9407     size_t stepSize;
9408 
9409     static if (hasLength!Source)
9410     {
9411         enum needsEndTracker = false;
9412     }
9413     else
9414     {
9415         // If there's no information about the length, track needs to be kept manually
9416         Source nextSource;
9417         enum needsEndTracker = true;
9418     }
9419 
9420     bool _empty;
9421 
9422     static if (hasSlicing!Source)
9423         enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
9424 
9425     static if (withPartial)
9426         bool hasShownPartialBefore;
9427 
9428 public:
9429     /// Standard constructor
9430     this(Source source, size_t windowSize, size_t stepSize)
9431     {
9432         assert(windowSize > 0, "windowSize must be greater than zero");
9433         assert(stepSize > 0, "stepSize must be greater than zero");
9434         this.source = source;
9435         this.windowSize = windowSize;
9436         this.stepSize = stepSize;
9437 
9438         static if (needsEndTracker)
9439         {
9440             // `nextSource` is used to "look one step into the future" and check for the end
9441             // this means `nextSource` is advanced by `stepSize` on every `popFront`
9442             nextSource = source.save;
9443             auto poppedElems = nextSource.popFrontN(windowSize);
9444         }
9445 
9446         if (source.empty)
9447         {
9448             _empty = true;
9449             return;
9450         }
9451 
9452         static if (withPartial)
9453         {
9454             static if (needsEndTracker)
9455             {
9456                 if (nextSource.empty)
9457                     hasShownPartialBefore = true;
9458             }
9459             else
9460             {
9461                 if (source.length <= windowSize)
9462                     hasShownPartialBefore = true;
9463             }
9464         }
9465         else
9466         {
9467             // empty source range is needed, s.t. length, slicing etc. works properly
9468             static if (needsEndTracker)
9469             {
9470                 if (poppedElems < windowSize)
9471                      _empty = true;
9472             }
9473             else
9474             {
9475                 if (source.length < windowSize)
9476                      _empty = true;
9477             }
9478         }
9479     }
9480 
9481     /// Forward range primitives. Always present.
9482     @property auto front()
9483     {
9484         assert(!empty, "Attempting to access front on an empty slide.");
9485         static if (hasSlicing!Source && hasLength!Source)
9486         {
9487             static if (withPartial)
9488             {
9489                 import std.algorithm.comparison : min;
9490                 return source[0 .. min(windowSize, source.length)];
9491             }
9492             else
9493             {
9494                 assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
9495                 return source[0 .. windowSize];
9496             }
9497         }
9498         else
9499         {
9500             static if (withPartial)
9501                 return source.save.take(windowSize);
9502             else
9503                 return source.save.takeExactly(windowSize);
9504         }
9505     }
9506 
9507     /// Ditto
9508     void popFront()
9509     {
9510         assert(!empty, "Attempting to call popFront() on an empty slide.");
9511         source.popFrontN(stepSize);
9512 
9513         if (source.empty)
9514         {
9515             _empty = true;
9516             return;
9517         }
9518 
9519         static if (withPartial)
9520         {
9521             if (hasShownPartialBefore)
9522                 _empty = true;
9523         }
9524 
9525         static if (needsEndTracker)
9526         {
9527             // Check the upcoming slide
9528             auto poppedElements = nextSource.popFrontN(stepSize);
9529             static if (withPartial)
9530             {
9531                 if (poppedElements < stepSize || nextSource.empty)
9532                     hasShownPartialBefore = true;
9533             }
9534             else
9535             {
9536                 if (poppedElements < stepSize)
9537                     _empty = true;
9538             }
9539         }
9540         else
9541         {
9542             static if (withPartial)
9543             {
9544                 if (source.length <= windowSize)
9545                     hasShownPartialBefore = true;
9546             }
9547             else
9548             {
9549                 if (source.length < windowSize)
9550                     _empty = true;
9551             }
9552         }
9553     }
9554 
9555     static if (!isInfinite!Source)
9556     {
9557         /// Ditto
9558         @property bool empty() const
9559         {
9560             return _empty;
9561         }
9562     }
9563     else
9564     {
9565         // undocumented
9566         enum empty = false;
9567     }
9568 
9569     /// Ditto
9570     @property typeof(this) save()
9571     {
9572         return typeof(this)(source.save, windowSize, stepSize);
9573     }
9574 
9575     static if (hasLength!Source)
9576     {
9577         // gaps between the last element and the end of the range
9578         private size_t gap()
9579         {
9580             /*
9581             * Note:
9582             * - In the following `end` is the exclusive end as used in opSlice
9583             * - For the trivial case with `stepSize = 1`  `end` is at `len`:
9584             *
9585             *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]]    (end = 4)
9586             *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]      (end = 4)
9587             *
9588             * - For the non-trivial cases, we need to calculate the gap
9589             *   between `len` and `end` - this is the number of missing elements
9590             *   from the input range:
9591             *
9592             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
9593             *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
9594             *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
9595             *
9596             *   As it can be seen `gap` can be at most `stepSize - 1`
9597             *   More generally the elements of the sliding window with
9598             *   `w = windowSize` and `s = stepSize` are:
9599             *
9600             *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
9601             *
9602             *  We can thus calculate the gap between the `end` and `len` as:
9603             *
9604             *     gap = len - (n * s + w) = len - w - (n * s)
9605             *
9606             *  As we aren't interested in exact value of `n`, but the best
9607             *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
9608             *
9609             *     gap = len - w - (s - s ... - s) = (len - w) % s
9610             *
9611             *  So for example:
9612             *
9613             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
9614             *      gap: (7 - 2) % 3 = 5 % 3 = 2
9615             *      end: 7 - 2 = 5
9616             *
9617             *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
9618             *      gap: (7 - 4) % 2 = 3 % 2 = 1
9619             *      end: 7 - 1 = 6
9620             */
9621             return (source.length - windowSize)  % stepSize;
9622         }
9623 
9624         private size_t numberOfFullFrames()
9625         {
9626             /**
9627             5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9628             7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (3)
9629             7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (2)
9630             6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5]         (2)
9631             7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (2)
9632 
9633             As the last window is only added iff its complete,
9634             we don't count the last window except if it's full due to integer rounding.
9635             */
9636             return 1 + (source.length - windowSize) / stepSize;
9637         }
9638 
9639         // Whether the last slide frame size is less than windowSize
9640         private bool hasPartialElements()
9641         {
9642             static if (withPartial)
9643                 return gap != 0 && source.length > numberOfFullFrames * stepSize;
9644             else
9645                 return 0;
9646         }
9647 
9648         /// Length. Only if `hasLength!Source` is `true`
9649         @property size_t length()
9650         {
9651             if (source.length < windowSize)
9652             {
9653                 static if (withPartial)
9654                     return source.length > 0;
9655                 else
9656                     return 0;
9657             }
9658             else
9659             {
9660                 /***
9661                   We bump the pointer by stepSize for every element.
9662                   If withPartial, we don't count the last element if its size
9663                   isn't windowSize
9664 
9665                   At most:
9666                       [p, p + stepSize, ..., p + stepSize * n]
9667 
9668                 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9669                 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (4)
9670                 7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (3)
9671                 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6]      (3)
9672                 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (3)
9673                 */
9674                 return numberOfFullFrames + hasPartialElements;
9675             }
9676         }
9677     }
9678 
9679     static if (hasSlicing!Source)
9680     {
9681         /**
9682         Indexing and slicing operations. Provided only if
9683         `hasSlicing!Source` is `true`.
9684          */
9685         auto opIndex(size_t index)
9686         {
9687             immutable start = index * stepSize;
9688 
9689             static if (isInfinite!Source)
9690             {
9691                 immutable end = start + windowSize;
9692             }
9693             else
9694             {
9695                 import std.algorithm.comparison : min;
9696 
9697                 immutable len = source.length;
9698                 assert(start < len, "slide index out of bounds");
9699                 immutable end = min(start + windowSize, len);
9700             }
9701 
9702             return source[start .. end];
9703         }
9704 
9705         static if (!isInfinite!Source)
9706         {
9707             /// ditto
9708             typeof(this) opSlice(size_t lower, size_t upper)
9709             {
9710                 import std.algorithm.comparison : min;
9711 
9712                 assert(upper <= length, "slide slicing index out of bounds");
9713                 assert(lower <= upper, "slide slicing index out of bounds");
9714 
9715                 lower *= stepSize;
9716                 upper *= stepSize;
9717 
9718                 immutable len = source.length;
9719 
9720                 static if (withPartial)
9721                 {
9722                     import std.algorithm.comparison : max;
9723 
9724                     if (lower == upper)
9725                         return this[$ .. $];
9726 
9727                     /*
9728                     A) If `stepSize` >= `windowSize` => `rightPos = upper`
9729 
9730                        [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9731                          rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9732                          6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9733 
9734                     B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9735 
9736                        [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9737                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9738                          1.iota.slide(2) = [[0]]
9739 
9740                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9741                          1.iota.slide(2) = [[0, 1]]
9742 
9743                        More complex:
9744 
9745                        20.iota.slide(7, 6)[0 .. 2]
9746                          rightPos: (upper=2) * (stepSize=6) = 12.iota
9747                          12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9748 
9749                        Now we add up for the difference between `windowSize` and `stepSize`:
9750 
9751                          rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9752                          13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9753                     */
9754                     immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9755                 }
9756                 else
9757                 {
9758                     /*
9759                     After we have normalized `lower` and `upper` by `stepSize`,
9760                     we only need to look at the case of `stepSize=1`.
9761                     As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9762                     Notice that starting from `upper`,
9763                     we only need to move for `windowSize - 1` to the right:
9764 
9765                       - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9766                         rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9767 
9768                       - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9769                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9770 
9771                       - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9772                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9773                     */
9774                     immutable rightPos = min(upper + windowSize - 1, len);
9775                 }
9776 
9777                 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9778             }
9779         }
9780         else static if (hasSliceToEnd)
9781         {
9782             // For slicing an infinite chunk, we need to slice the source to the infinite end.
9783             auto opSlice(size_t lower, size_t upper)
9784             {
9785                 assert(lower <= upper, "slide slicing index out of bounds");
9786                 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9787                                     .takeExactly(upper - lower);
9788             }
9789         }
9790 
9791         static if (isInfinite!Source)
9792         {
9793             static if (hasSliceToEnd)
9794             {
9795                 private static struct DollarToken{}
9796                 DollarToken opDollar()
9797                 {
9798                     return DollarToken();
9799                 }
9800                 //Slice to dollar
9801                 typeof(this) opSlice(size_t lower, DollarToken)
9802                 {
9803                     return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9804                 }
9805             }
9806         }
9807         else
9808         {
9809             // Dollar token carries a static type, with no extra information.
9810             // It can lazily transform into source.length on algorithmic
9811             // operations such as : slide[$/2, $-1];
9812             private static struct DollarToken
9813             {
9814                 private size_t _length;
9815                 alias _length this;
9816             }
9817 
9818             DollarToken opDollar()
9819             {
9820                 return DollarToken(this.length);
9821             }
9822 
9823             // Optimized slice overloads optimized for using dollar.
9824             typeof(this) opSlice(DollarToken, DollarToken)
9825             {
9826                 static if (hasSliceToEnd)
9827                 {
9828                     return typeof(this)(source[$ .. $], windowSize, stepSize);
9829                 }
9830                 else
9831                 {
9832                     immutable len = source.length;
9833                     return typeof(this)(source[len .. len], windowSize, stepSize);
9834                 }
9835             }
9836 
9837             // Optimized slice overloads optimized for using dollar.
9838             typeof(this) opSlice(size_t lower, DollarToken)
9839             {
9840                 import std.algorithm.comparison : min;
9841                 assert(lower <= length, "slide slicing index out of bounds");
9842                 lower *= stepSize;
9843                 static if (hasSliceToEnd)
9844                 {
9845                     return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9846                 }
9847                 else
9848                 {
9849                     immutable len = source.length;
9850                     return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9851                 }
9852             }
9853 
9854             // Optimized slice overloads optimized for using dollar.
9855             typeof(this) opSlice(DollarToken, size_t upper)
9856             {
9857                 assert(upper == length, "slide slicing index out of bounds");
9858                 return this[$ .. $];
9859             }
9860         }
9861 
9862         // Bidirectional range primitives
9863         static if (!isInfinite!Source)
9864         {
9865             /**
9866             Bidirectional range primitives. Provided only if both
9867             `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9868              */
9869             @property auto back()
9870             {
9871                 import std.algorithm.comparison : max;
9872 
9873                 assert(!empty, "Attempting to access front on an empty slide");
9874 
9875                 immutable len = source.length;
9876 
9877                 static if (withPartial)
9878                 {
9879                     if (source.length <= windowSize)
9880                         return source[0 .. source.length];
9881 
9882                     if (hasPartialElements)
9883                         return source[numberOfFullFrames * stepSize .. len];
9884                 }
9885 
9886                 // check for underflow
9887                 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9888                 return source[start .. len - gap];
9889             }
9890 
9891             /// Ditto
9892             void popBack()
9893             {
9894                 assert(!empty, "Attempting to call popBack() on an empty slide");
9895 
9896                 // Move by stepSize
9897                 immutable end = source.length > stepSize ? source.length - stepSize : 0;
9898 
9899                 static if (withPartial)
9900                 {
9901                     if (hasShownPartialBefore || source.empty)
9902                     {
9903                         _empty = true;
9904                         return;
9905                     }
9906 
9907                     // pop by stepSize, except for the partial frame at the end
9908                     if (hasPartialElements)
9909                         source = source[0 .. source.length - gap];
9910                     else
9911                         source = source[0 .. end];
9912                 }
9913                 else
9914                 {
9915                     source = source[0 .. end];
9916                 }
9917 
9918                 if (source.length < windowSize)
9919                     _empty = true;
9920             }
9921         }
9922     }
9923 }
9924 
9925 // test @nogc
9926 @safe pure nothrow @nogc unittest
9927 {
9928     import std.algorithm.comparison : equal;
9929 
9930     static immutable res1 = [[0], [1], [2], [3]];
9931     assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9932 
9933     static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9934     assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9935 }
9936 
9937 // test different window sizes
9938 @safe pure nothrow unittest
9939 {
9940     import std.array : array;
9941     import std.algorithm.comparison : equal;
9942 
9943     assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9944     assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9945     assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9946     assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9947     assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9948     assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9949 
9950     assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9951     assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9952     assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9953     assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9954     assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9955     assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9956     assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9957 }
9958 
9959 // test combinations
9960 @safe pure nothrow unittest
9961 {
9962     import std.algorithm.comparison : equal;
9963     import std.typecons : tuple;
9964 
9965     alias t = tuple;
9966     auto list = [
9967         t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9968         t(t(1, 2), [[0], [2], [4]]),
9969         t(t(1, 3), [[0], [3]]),
9970         t(t(1, 4), [[0], [4]]),
9971         t(t(1, 5), [[0], [5]]),
9972         t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9973         t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9974         t(t(2, 3), [[0, 1], [3, 4]]),
9975         t(t(2, 4), [[0, 1], [4, 5]]),
9976         t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9977         t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9978         t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9979         t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9980         t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9981     ];
9982 
9983     static foreach (Partial; [Yes.withPartial, No.withPartial])
9984         foreach (e; list)
9985             assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9986 
9987     auto listSpecial = [
9988         t(t(2, 5), [[0, 1], [5]]),
9989         t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9990         t(t(3, 4), [[0, 1, 2], [4, 5]]),
9991         t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9992         t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9993         t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9994     ];
9995     foreach (e; listSpecial)
9996     {
9997         assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
9998         assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
9999     }
10000 }
10001 
10002 // test emptiness and copyability
10003 @safe pure nothrow unittest
10004 {
10005     import std.algorithm.comparison : equal;
10006     import std.algorithm.iteration : map;
10007 
10008     // check with empty input
10009     int[] d;
10010     assert(d.slide!(Yes.withPartial)(2).empty);
10011     assert(d.slide!(Yes.withPartial)(2, 2).empty);
10012 
10013     // is copyable?
10014     auto e = iota(5).slide!(Yes.withPartial)(2);
10015     e.popFront;
10016     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
10017     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
10018     assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
10019 }
10020 
10021 // test with strings
10022 @safe pure nothrow unittest
10023 {
10024     import std.algorithm.iteration : each;
10025 
10026     int[dstring] f;
10027     "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
10028     assert(f == ["AGA"d: 2, "GAG"d: 1]);
10029 
10030     int[dstring] g;
10031     "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
10032     assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
10033     g = null;
10034     "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
10035     assert(g == ["ABC"d:1, "DEF"d:1]);
10036 }
10037 
10038 // test with utf8 strings
10039 @safe unittest
10040 {
10041     import std.stdio;
10042     import std.algorithm.comparison : equal;
10043 
10044     assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."]));
10045     assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"]));
10046 
10047     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
10048     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
10049     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]);
10050     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]);
10051 }
10052 
10053 // test length
10054 @safe pure nothrow unittest
10055 {
10056     // Slides with fewer elements are empty or 1 for Yes.withPartial
10057     static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
10058     {{
10059         assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
10060         assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
10061         assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
10062     }}
10063 
10064     static immutable list = [
10065     //  iota   slide    expected
10066         [4,    2, 1,     3, 3],
10067         [5,    3, 1,     3, 3],
10068         [7,    2, 2,     4, 3],
10069         [12,   2, 4,     3, 3],
10070         [6,    1, 2,     3, 3],
10071         [6,    2, 4,     2, 2],
10072         [3,    2, 4,     1, 1],
10073         [5,    2, 1,     4, 4],
10074         [7,    2, 2,     4, 3],
10075         [7,    2, 3,     3, 2],
10076         [7,    3, 2,     3, 3],
10077         [7,    3, 3,     3, 2],
10078     ];
10079     foreach (e; list)
10080     {
10081         assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
10082         assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
10083     }
10084 }
10085 
10086 // test index and slicing
10087 @safe pure nothrow unittest
10088 {
10089     import std.algorithm.comparison : equal;
10090     import std.array : array;
10091 
10092     static foreach (Partial; [Yes.withPartial, No.withPartial])
10093     {
10094         foreach (s; [5, 7, 10, 15, 20])
10095         foreach (windowSize; 1 .. 10)
10096         foreach (stepSize; 1 .. 10)
10097         {
10098             auto r = s.iota.slide!Partial(windowSize, stepSize);
10099             auto arr = r.array;
10100             assert(r.length == arr.length);
10101 
10102             // test indexing
10103             foreach (i; 0 .. arr.length)
10104                 assert(r[i] == arr[i]);
10105 
10106             // test slicing
10107             foreach (i; 0 .. arr.length)
10108             {
10109                 foreach (j; i .. arr.length)
10110                     assert(r[i .. j].equal(arr[i .. j]));
10111 
10112                 assert(r[i .. $].equal(arr[i .. $]));
10113             }
10114 
10115             // test opDollar slicing
10116             assert(r[$/2 .. $].equal(arr[$/2 .. $]));
10117             assert(r[$ .. $].empty);
10118             if (arr.empty)
10119             {
10120                 assert(r[$ .. 0].empty);
10121                 assert(r[$/2 .. $].empty);
10122 
10123             }
10124         }
10125     }
10126 }
10127 
10128 // test with infinite ranges
10129 @safe pure nothrow unittest
10130 {
10131     import std.algorithm.comparison : equal;
10132 
10133     static foreach (Partial; [Yes.withPartial, No.withPartial])
10134     {{
10135         // InfiniteRange without RandomAccess
10136         auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
10137         assert(fibs.slide!Partial(2).take(2).equal!equal([[1,  1], [1,  2]]));
10138         assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
10139 
10140         // InfiniteRange with RandomAccess and slicing
10141         auto odds = sequence!("a[0] + n * a[1]")(1, 2);
10142         auto oddsByPairs = odds.slide!Partial(2);
10143         assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
10144         assert(oddsByPairs[1].equal([3, 5]));
10145         assert(oddsByPairs[4].equal([9, 11]));
10146 
10147         static assert(hasSlicing!(typeof(odds)));
10148         assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
10149         assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
10150 
10151         auto oddsWithGaps = odds.slide!Partial(2, 4);
10152         assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
10153         assert(oddsWithGaps[2].equal([17, 19]));
10154         assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
10155         assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
10156     }}
10157 }
10158 
10159 // test reverse
10160 @safe pure nothrow unittest
10161 {
10162     import std.algorithm.comparison : equal;
10163 
10164     static foreach (Partial; [Yes.withPartial, No.withPartial])
10165     {{
10166         foreach (windowSize; 1 .. 15)
10167         foreach (stepSize; 1 .. 15)
10168         {
10169             auto r = 20.iota.slide!Partial(windowSize, stepSize);
10170             auto rArr = r.array.retro;
10171             auto rRetro = r.retro;
10172 
10173             assert(rRetro.length == rArr.length);
10174             assert(rRetro.equal(rArr));
10175             assert(rRetro.array.retro.equal(r));
10176         }
10177     }}
10178 }
10179 
10180 // test with dummy ranges
10181 @safe pure nothrow unittest
10182 {
10183     import std.algorithm.comparison : equal;
10184     import std.internal.test.dummyrange : AllDummyRanges;
10185     import std.meta : Filter;
10186 
10187     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10188     {{
10189         Range r;
10190 
10191         static foreach (Partial; [Yes.withPartial, No.withPartial])
10192         {
10193             assert(r.slide!Partial(1).equal!equal(
10194                 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
10195             ));
10196             assert(r.slide!Partial(2).equal!equal(
10197                 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
10198             ));
10199             assert(r.slide!Partial(3).equal!equal(
10200                 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
10201                 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
10202             ));
10203             assert(r.slide!Partial(6).equal!equal(
10204                 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
10205                 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
10206             ));
10207         }
10208 
10209         // special cases
10210         assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
10211         assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
10212         assert(r.slide!(No.withPartial)(15).empty);
10213         assert(r.slide!(No.withPartial)(15).walkLength == 0);
10214     }}
10215 }
10216 
10217 // test with dummy ranges
10218 @safe pure nothrow unittest
10219 {
10220     import std.algorithm.comparison : equal;
10221     import std.internal.test.dummyrange : AllDummyRanges;
10222     import std.meta : Filter;
10223     import std.typecons : tuple;
10224 
10225     alias t = tuple;
10226     static immutable list = [
10227     // iota   slide    expected
10228         t(6,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
10229         t(6,  t(4, 6), [[1, 2, 3, 4]]),
10230         t(6,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
10231         t(7,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
10232         t(7,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
10233         t(8,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
10234         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]]),
10235         t(8,  t(3, 4), [[1, 2, 3], [5, 6, 7]]),
10236         t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
10237     ];
10238 
10239     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10240     static foreach (Partial; [Yes.withPartial, No.withPartial])
10241     foreach (e; list)
10242         assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
10243 
10244     static immutable listSpecial = [
10245     // iota   slide    expected
10246         t(6,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
10247         t(7,  t(4, 5), [[1, 2, 3, 4], [6, 7]]),
10248         t(7,  t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
10249         t(7,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
10250         t(8,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
10251         t(8,  t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
10252         t(8,  t(3, 6), [[1, 2, 3], [7, 8]]),
10253         t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
10254         t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
10255     ];
10256     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10257     static foreach (Partial; [Yes.withPartial, No.withPartial])
10258     foreach (e; listSpecial)
10259     {
10260         Range r;
10261         assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
10262         assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
10263     }
10264 }
10265 
10266 // test reverse with dummy ranges
10267 @safe pure nothrow unittest
10268 {
10269     import std.algorithm.comparison : equal;
10270     import std.internal.test.dummyrange : AllDummyRanges;
10271     import std.meta : Filter, templateAnd;
10272     import std.typecons : tuple;
10273     alias t = tuple;
10274 
10275     static immutable list = [
10276     //   slide   expected
10277         t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
10278         t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
10279         t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
10280                  [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
10281         t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
10282         t(2, 4, [[9, 10], [5, 6], [1, 2]]),
10283     ];
10284 
10285     static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
10286     {{
10287         Range r;
10288         static foreach (Partial; [Yes.withPartial, No.withPartial])
10289         {
10290             foreach (e; list)
10291                 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
10292 
10293             // front = back
10294             foreach (windowSize; 1 .. 10)
10295             foreach (stepSize; 1 .. 10)
10296             {
10297                 auto slider = r.slide!Partial(windowSize, stepSize);
10298                 auto sliderRetro = slider.retro.array;
10299                 assert(slider.length == sliderRetro.length);
10300                 assert(sliderRetro.retro.equal!equal(slider));
10301             }
10302         }
10303 
10304         // special cases
10305         assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
10306         assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
10307     }}
10308 }
10309 
10310 // test different sliceable ranges
10311 @safe pure nothrow unittest
10312 {
10313     import std.algorithm.comparison : equal;
10314     import std.internal.test.dummyrange : AllDummyRanges;
10315     import std.meta : AliasSeq;
10316 
10317     struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
10318                                  Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
10319     {
10320         Range arr = 10.iota.array; // similar to DummyRange
10321         @property auto save() { return typeof(this)(arr); }
10322         @property auto front() { return arr[0]; }
10323         void popFront() { arr.popFront(); }
10324         auto opSlice(size_t i, size_t j)
10325         {
10326             // subslices can't be infinite
10327             return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
10328         }
10329 
10330         static if (withInfiniteness)
10331         {
10332             enum empty = false;
10333         }
10334         else
10335         {
10336             @property bool empty() { return arr.empty; }
10337             @property auto length() { return arr.length; }
10338         }
10339 
10340         static if (withOpDollar)
10341         {
10342             static if (withInfiniteness)
10343             {
10344                 struct Dollar {}
10345                 Dollar opDollar() const { return Dollar.init; }
10346 
10347                 // Slice to dollar
10348                 typeof(this) opSlice(size_t lower, Dollar)
10349                 {
10350                     return typeof(this)(arr[lower .. $]);
10351                 }
10352 
10353             }
10354             else
10355             {
10356                 alias opDollar = length;
10357             }
10358         }
10359     }
10360 
10361     import std.meta : Filter,  templateNot;
10362     alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
10363 
10364     static foreach (Partial; [Yes.withPartial, No.withPartial])
10365     {{
10366         static foreach (Range; SliceableDummyRanges)
10367         {{
10368             Range r;
10369             r.reinit;
10370             r.arr[] -= 1; // use a 0-based array (for clarity)
10371 
10372             assert(r.slide!Partial(2)[0].equal([0, 1]));
10373             assert(r.slide!Partial(2)[1].equal([1, 2]));
10374 
10375             // saveable
10376             auto s = r.slide!Partial(2);
10377             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10378             s.save.popFront;
10379             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10380 
10381             assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
10382         }}
10383 
10384         static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
10385         {{
10386             Range r;
10387             r.reinit;
10388             r.arr[] -= 1; // use a 0-based array (for clarity)
10389 
10390             assert(r.slide!(No.withPartial)(6).equal!equal(
10391                 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
10392                 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
10393             ));
10394             assert(r.slide!(No.withPartial)(16).empty);
10395 
10396             assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
10397             assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
10398             assert(r.slide!Partial(2)[$ .. $].empty);
10399 
10400             assert(r.slide!Partial(3).retro.equal!equal(
10401                 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
10402             ));
10403         }}
10404 
10405         alias T = int[];
10406 
10407         // separate checks for infinity
10408         auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
10409         assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
10410         assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
10411 
10412         auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
10413         assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
10414         assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
10415         assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
10416     }}
10417 }
10418 
10419 // https://issues.dlang.org/show_bug.cgi?id=19082
10420 @safe unittest
10421 {
10422     import std.algorithm.comparison : equal;
10423     import std.algorithm.iteration : map;
10424     assert([1].map!(x => x).slide(2).equal!equal([[1]]));
10425 }
10426 
10427 // https://issues.dlang.org/show_bug.cgi?id=19642
10428 @safe unittest
10429 {
10430     import std.algorithm.comparison : equal;
10431     import std.algorithm.iteration : splitter;
10432 
10433     assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]]));
10434 }
10435 
10436 // https://issues.dlang.org/show_bug.cgi?id=23976
10437 @safe unittest
10438 {
10439     import std.algorithm.comparison : equal;
10440     import std.algorithm.iteration : splitter;
10441 
10442     assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]]));
10443 }
10444 
10445 private struct OnlyResult(Values...)
10446 if (Values.length > 1)
10447 {
10448     import std.meta : ApplyRight;
10449     import std.traits : isAssignable;
10450 
10451     private enum arity = Values.length;
10452 
10453     private alias UnqualValues = staticMap!(Unqual, Values);
10454 
10455     private enum canAssignElements = allSatisfy!(
10456         ApplyRight!(isAssignable, CommonType!Values),
10457         Values
10458     );
10459 
10460     private this(return scope ref Values values)
10461     {
10462         ref @trusted unqual(T)(ref T x){return cast() x;}
10463 
10464         // TODO: this calls any possible copy constructors without qualifiers.
10465         // Find a way to initialize values using qualified copy constructors.
10466         static foreach (i; 0 .. Values.length)
10467         {
10468             this.values[i] = unqual(values[i]);
10469         }
10470         this.backIndex = arity;
10471     }
10472 
10473     bool empty() @property
10474     {
10475         return frontIndex >= backIndex;
10476     }
10477 
10478     CommonType!Values front() @property
10479     {
10480         assert(!empty, "Attempting to fetch the front of an empty Only range");
10481         return this[0];
10482     }
10483 
10484     static if (canAssignElements)
10485     {
10486         void front(CommonType!Values value) @property
10487         {
10488             assert(!empty, "Attempting to assign the front of an empty Only range");
10489             this[0] = value;
10490         }
10491     }
10492 
10493     void popFront()
10494     {
10495         assert(!empty, "Attempting to popFront an empty Only range");
10496         ++frontIndex;
10497     }
10498 
10499     CommonType!Values back() @property
10500     {
10501         assert(!empty, "Attempting to fetch the back of an empty Only range");
10502         return this[$ - 1];
10503     }
10504 
10505     static if (canAssignElements)
10506     {
10507         void back(CommonType!Values value) @property
10508         {
10509             assert(!empty, "Attempting to assign the back of an empty Only range");
10510             this[$ - 1] = value;
10511         }
10512     }
10513 
10514     void popBack()
10515     {
10516         assert(!empty, "Attempting to popBack an empty Only range");
10517         --backIndex;
10518     }
10519 
10520     OnlyResult save() @property
10521     {
10522         return this;
10523     }
10524 
10525     size_t length() const @property
10526     {
10527         return backIndex - frontIndex;
10528     }
10529 
10530     alias opDollar = length;
10531 
10532     @trusted CommonType!Values opIndex(size_t idx)
10533     {
10534         // when i + idx points to elements popped
10535         // with popBack
10536         assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
10537         final switch (frontIndex + idx)
10538             static foreach (i, T; Values)
10539             case i:
10540                 return cast(T) values[i];
10541     }
10542 
10543     static if (canAssignElements)
10544     {
10545         void opIndexAssign(CommonType!Values value, size_t idx)
10546         {
10547             assert(idx < length, "Attempting to assign to an out of bounds index of an Only range");
10548             final switch (frontIndex + idx)
10549                 static foreach (i; 0 .. Values.length)
10550                 case i:
10551                     values[i] = value;
10552         }
10553     }
10554 
10555     OnlyResult opSlice()
10556     {
10557         return this;
10558     }
10559 
10560     OnlyResult opSlice(size_t from, size_t to)
10561     {
10562         OnlyResult result = this;
10563         result.frontIndex += from;
10564         result.backIndex = this.frontIndex + to;
10565         assert(
10566             from <= to,
10567             "Attempting to slice an Only range with a larger first argument than the second."
10568         );
10569         assert(
10570             to <= length,
10571             "Attempting to slice using an out of bounds index on an Only range"
10572         );
10573         return result;
10574     }
10575 
10576     private size_t frontIndex = 0;
10577     private size_t backIndex = 0;
10578 
10579     // https://issues.dlang.org/show_bug.cgi?id=10643
10580     version (none)
10581     {
10582         import std.traits : hasElaborateAssign;
10583         static if (hasElaborateAssign!T)
10584             private UnqualValues values;
10585         else
10586             private UnqualValues values = void;
10587     }
10588     else
10589         // These may alias to shared or immutable data. Do not let the user
10590         // to access these directly, and do not allow mutation without checking
10591         // the qualifier.
10592         private UnqualValues values;
10593 }
10594 
10595 // Specialize for single-element results
10596 private struct OnlyResult(T)
10597 {
10598     import std.traits : isAssignable;
10599 
10600     @property T front()
10601     {
10602         assert(!empty, "Attempting to fetch the front of an empty Only range");
10603         return fetchFront();
10604     }
10605     static if (isAssignable!T)
10606     {
10607         @property void front(T value)
10608         {
10609             assert(!empty, "Attempting to assign the front of an empty Only range");
10610             assignFront(value);
10611         }
10612     }
10613     @property T back()
10614     {
10615         assert(!empty, "Attempting to fetch the back of an empty Only range");
10616         return fetchFront();
10617     }
10618     static if (isAssignable!T)
10619     {
10620         @property void back(T value)
10621         {
10622             assert(!empty, "Attempting to assign the front of an empty Only range");
10623             assignFront(value);
10624         }
10625     }
10626     @property bool empty() const { return _empty; }
10627     @property size_t length() const { return !_empty; }
10628     @property auto save() { return this; }
10629     void popFront()
10630     {
10631         assert(!_empty, "Attempting to popFront an empty Only range");
10632         _empty = true;
10633     }
10634     void popBack()
10635     {
10636         assert(!_empty, "Attempting to popBack an empty Only range");
10637         _empty = true;
10638     }
10639     alias opDollar = length;
10640 
10641     // FIXME Workaround for https://issues.dlang.org/show_bug.cgi?id=24415
10642     import std.traits : hasElaborateCopyConstructor;
10643     static if (hasElaborateCopyConstructor!T)
10644     {
10645         private static struct WorkaroundBugzilla24415 {}
10646         public this()(WorkaroundBugzilla24415) {}
10647     }
10648 
10649     private this()(return scope auto ref T value)
10650     {
10651         ref @trusted unqual(ref T x){return cast() x;}
10652         // TODO: this calls the possible copy constructor without qualifiers.
10653         // Find a way to initialize value using a qualified copy constructor.
10654         this._value = unqual(value);
10655         this._empty = false;
10656     }
10657 
10658     T opIndex(size_t i)
10659     {
10660         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
10661         return fetchFront();
10662     }
10663 
10664     static if (isAssignable!T)
10665     {
10666         void opIndexAssign(T value, size_t i)
10667         {
10668             assert(!_empty && i == 0, "Attempting to assign an out of bounds index of an Only range");
10669             assignFront(value);
10670         }
10671     }
10672 
10673     OnlyResult opSlice()
10674     {
10675         return this;
10676     }
10677 
10678     OnlyResult opSlice(size_t from, size_t to)
10679     {
10680         assert(
10681             from <= to,
10682             "Attempting to slice an Only range with a larger first argument than the second."
10683         );
10684         assert(
10685             to <= length,
10686             "Attempting to slice using an out of bounds index on an Only range"
10687         );
10688         OnlyResult copy = this;
10689         copy._empty = _empty || from == to;
10690         return copy;
10691     }
10692 
10693     // This may alias to shared or immutable data. Do not let the user
10694     // to access this directly, and do not allow mutation without checking
10695     // the qualifier.
10696     private Unqual!T _value;
10697     private bool _empty = true;
10698     private @trusted T fetchFront()
10699     {
10700         return *cast(T*)&_value;
10701     }
10702     static if (isAssignable!T)
10703     {
10704         private @trusted void assignFront(T newValue)
10705         {
10706             *cast(T*) &_value = newValue;
10707         }
10708     }
10709 }
10710 
10711 /**
10712 Assemble `values` into a range that carries all its
10713 elements in-situ.
10714 
10715 Useful when a single value or multiple disconnected values
10716 must be passed to an algorithm expecting a range, without
10717 having to perform dynamic memory allocation.
10718 
10719 As copying the range means copying all elements, it can be
10720 safely returned from functions. For the same reason, copying
10721 the returned range may be expensive for a large number of arguments.
10722 
10723 Params:
10724     values = the values to assemble together
10725 
10726 Returns:
10727     A `RandomAccessRange` of the assembled values.
10728 
10729     The returned range can be sliced. Its elements can be assigned to if every
10730     type in `Values` supports assignment from the range's element type.
10731 
10732 See_Also: $(LREF chain) to chain ranges
10733  */
10734 auto only(Values...)(return scope Values values)
10735 if (!is(CommonType!Values == void))
10736 {
10737     return OnlyResult!Values(values);
10738 }
10739 
10740 /// ditto
10741 auto only()()
10742 {
10743     // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383
10744     struct EmptyElementType {}
10745     EmptyElementType[] result;
10746     return result;
10747 }
10748 
10749 ///
10750 @safe unittest
10751 {
10752     import std.algorithm.comparison : equal;
10753     import std.algorithm.iteration : filter, joiner, map;
10754     import std.algorithm.searching : findSplitBefore;
10755     import std.uni : isUpper;
10756 
10757     assert(equal(only('♡'), "♡"));
10758     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
10759 
10760     assert(only("one", "two", "three").joiner(" ").equal("one two three"));
10761 
10762     string title = "The D Programming Language";
10763     assert(title
10764         .filter!isUpper // take the upper case letters
10765         .map!only       // make each letter its own range
10766         .joiner(".")    // join the ranges together lazily
10767         .equal("T.D.P.L"));
10768 }
10769 
10770 // https://issues.dlang.org/show_bug.cgi?id=20314
10771 @safe unittest
10772 {
10773     import std.algorithm.iteration : joiner;
10774 
10775     const string s = "foo", t = "bar";
10776 
10777     assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
10778 }
10779 
10780 // Tests the zero-element result
10781 @safe unittest
10782 {
10783     import std.algorithm.comparison : equal;
10784 
10785     auto emptyRange = only();
10786 
10787     alias EmptyRange = typeof(emptyRange);
10788     static assert(isInputRange!EmptyRange);
10789     static assert(isForwardRange!EmptyRange);
10790     static assert(isBidirectionalRange!EmptyRange);
10791     static assert(isRandomAccessRange!EmptyRange);
10792     static assert(hasLength!EmptyRange);
10793     static assert(hasSlicing!EmptyRange);
10794 
10795     assert(emptyRange.empty);
10796     assert(emptyRange.length == 0);
10797     assert(emptyRange.equal(emptyRange[]));
10798     assert(emptyRange.equal(emptyRange.save));
10799     assert(emptyRange[0 .. 0].equal(emptyRange));
10800 }
10801 
10802 // Tests the single-element result
10803 @safe unittest
10804 {
10805     import std.algorithm.comparison : equal;
10806     import std.typecons : tuple;
10807     foreach (x; tuple(1, '1', 1.0, "1", [1]))
10808     {
10809         auto a = only(x);
10810         typeof(x)[] e = [];
10811         assert(a.front == x);
10812         assert(a.back == x);
10813         assert(!a.empty);
10814         assert(a.length == 1);
10815         assert(equal(a, a[]));
10816         assert(equal(a, a[0 .. 1]));
10817         assert(equal(a[0 .. 0], e));
10818         assert(equal(a[1 .. 1], e));
10819         assert(a[0] == x);
10820 
10821         auto b = a.save;
10822         assert(equal(a, b));
10823         a.popFront();
10824         assert(a.empty && a.length == 0 && a[].empty);
10825         b.popBack();
10826         assert(b.empty && b.length == 0 && b[].empty);
10827 
10828         alias A = typeof(a);
10829         static assert(isInputRange!A);
10830         static assert(isForwardRange!A);
10831         static assert(isBidirectionalRange!A);
10832         static assert(isRandomAccessRange!A);
10833         static assert(hasLength!A);
10834         static assert(hasSlicing!A);
10835     }
10836 
10837     auto imm = only!(immutable int)(1);
10838     immutable int[] imme = [];
10839     assert(imm.front == 1);
10840     assert(imm.back == 1);
10841     assert(!imm.empty);
10842     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10843     assert(imm.length == 1);
10844     assert(equal(imm, imm[]));
10845     assert(equal(imm, imm[0 .. 1]));
10846     assert(equal(imm[0 .. 0], imme));
10847     assert(equal(imm[1 .. 1], imme));
10848     assert(imm[0] == 1);
10849 }
10850 
10851 // Tests multiple-element results
10852 @safe unittest
10853 {
10854     import std.algorithm.comparison : equal;
10855     import std.algorithm.iteration : joiner;
10856     import std.meta : AliasSeq;
10857     static assert(!__traits(compiles, only(1, "1")));
10858 
10859     auto nums = only!(byte, uint, long)(1, 2, 3);
10860     static assert(is(ElementType!(typeof(nums)) == long));
10861     assert(nums.length == 3);
10862 
10863     foreach (i; 0 .. 3)
10864         assert(nums[i] == i + 1);
10865 
10866     auto saved = nums.save;
10867 
10868     foreach (i; 1 .. 4)
10869     {
10870         assert(nums.front == nums[0]);
10871         assert(nums.front == i);
10872         nums.popFront();
10873         assert(nums.length == 3 - i);
10874     }
10875 
10876     assert(nums.empty);
10877 
10878     assert(saved.equal(only(1, 2, 3)));
10879     assert(saved.equal(saved[]));
10880     assert(saved[0 .. 1].equal(only(1)));
10881     assert(saved[0 .. 2].equal(only(1, 2)));
10882     assert(saved[0 .. 3].equal(saved));
10883     assert(saved[1 .. 3].equal(only(2, 3)));
10884     assert(saved[2 .. 3].equal(only(3)));
10885     assert(saved[0 .. 0].empty);
10886     assert(saved[3 .. 3].empty);
10887 
10888     alias data = AliasSeq!("one", "two", "three", "four");
10889     static joined =
10890         ["one two", "one two three", "one two three four"];
10891     string[] joinedRange = joined;
10892 
10893     static foreach (argCount; 2 .. 5)
10894     {{
10895         auto values = only(data[0 .. argCount]);
10896         alias Values = typeof(values);
10897         static assert(is(ElementType!Values == string));
10898         static assert(isInputRange!Values);
10899         static assert(isForwardRange!Values);
10900         static assert(isBidirectionalRange!Values);
10901         static assert(isRandomAccessRange!Values);
10902         static assert(hasSlicing!Values);
10903         static assert(hasLength!Values);
10904 
10905         assert(values.length == argCount);
10906         assert(values[0 .. $].equal(values[0 .. values.length]));
10907         assert(values.joiner(" ").equal(joinedRange.front));
10908         joinedRange.popFront();
10909     }}
10910 
10911     assert(saved.retro.equal(only(3, 2, 1)));
10912     assert(saved.length == 3);
10913 
10914     assert(saved.back == 3);
10915     saved.popBack();
10916     assert(saved.length == 2);
10917     assert(saved.back == 2);
10918 
10919     assert(saved.front == 1);
10920     saved.popFront();
10921     assert(saved.length == 1);
10922     assert(saved.front == 2);
10923 
10924     saved.popBack();
10925     assert(saved.empty);
10926 
10927     auto imm = only!(immutable int, immutable int)(42, 24);
10928     alias Imm = typeof(imm);
10929     static assert(is(ElementType!Imm == immutable(int)));
10930     assert(!imm.empty);
10931     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10932     assert(imm.front == 42);
10933     imm.popFront();
10934     assert(imm.front == 24);
10935     imm.popFront();
10936     assert(imm.empty);
10937 
10938     static struct Test { int* a; }
10939     immutable(Test) test;
10940     cast(void) only(test, test); // Works with mutable indirection
10941 }
10942 
10943 // https://issues.dlang.org/show_bug.cgi?id=21129
10944 @safe unittest
10945 {
10946     auto range = () @safe {
10947         const(char)[5] staticStr = "Hello";
10948 
10949         // `only` must store a char[5] - not a char[]!
10950         return only(staticStr, " World");
10951     } ();
10952 
10953     assert(range.join == "Hello World");
10954 }
10955 
10956 // https://issues.dlang.org/show_bug.cgi?id=21129
10957 @safe unittest
10958 {
10959     struct AliasedString
10960     {
10961         const(char)[5] staticStr = "Hello";
10962 
10963         @property const(char)[] slice() const
10964         {
10965             return staticStr[];
10966         }
10967         alias slice this;
10968     }
10969 
10970     auto range = () @safe {
10971         auto hello = AliasedString();
10972 
10973         // a copy of AliasedString is stored in the range.
10974         return only(hello, " World");
10975     } ();
10976 
10977     assert(range.join == "Hello World");
10978 }
10979 
10980 // https://issues.dlang.org/show_bug.cgi?id=21022
10981 @safe pure nothrow unittest
10982 {
10983     struct S
10984     {
10985         int* mem;
10986     }
10987 
10988     immutable S x;
10989     immutable(S)[] arr;
10990     auto r1 = arr.chain(x.only, only(x, x));
10991 }
10992 
10993 // https://issues.dlang.org/show_bug.cgi?id=24382
10994 @safe unittest
10995 {
10996     auto r1 = only(123);
10997     r1.front = 456;
10998     r1.back = 456;
10999     r1[0] = 456;
11000 
11001     auto r2 = only(123, 456);
11002     r2.front = 789;
11003     r2.back = 789;
11004     r2[0] = 789;
11005 
11006     auto r3 = only(1.23, 456);
11007     // Can't assign double to int
11008     static assert(!__traits(compiles, r3.front = 7.89));
11009     static assert(!__traits(compiles, r3.back = 7.89));
11010     // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
11011     static assert(!__traits(compiles, () { r3[0] = 7.89; }));
11012     // Can't assign type other than element type (even if compatible)
11013     static assert(!__traits(compiles, r3.front = 789));
11014     static assert(!__traits(compiles, r3.back = 789));
11015     // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
11016     static assert(!__traits(compiles, () { r3[0] = 789; }));
11017 }
11018 
11019 /**
11020 Iterate over `range` with an attached index variable.
11021 
11022 Each element is a $(REF Tuple, std,typecons) containing the index
11023 and the element, in that order, where the index member is named `index`
11024 and the element member is named `value`.
11025 
11026 The index starts at `start` and is incremented by one on every iteration.
11027 
11028 Overflow:
11029     If `range` has length, then it is an error to pass a value for `start`
11030     so that `start + range.length` is bigger than `Enumerator.max`, thus
11031     it is ensured that overflow cannot happen.
11032 
11033     If `range` does not have length, and `popFront` is called when
11034     `front.index == Enumerator.max`, the index will overflow and
11035     continue from `Enumerator.min`.
11036 
11037 Params:
11038     range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
11039     start = the number to start the index counter from
11040 
11041 Returns:
11042     At minimum, an input range. All other range primitives are given in the
11043     resulting range if `range` has them. The exceptions are the bidirectional
11044     primitives, which are propagated only if `range` has length.
11045 
11046 Example:
11047 Useful for using `foreach` with an index loop variable:
11048 ----
11049     import std.stdio : stdin, stdout;
11050     import std.range : enumerate;
11051 
11052     foreach (lineNum, line; stdin.byLine().enumerate(1))
11053         stdout.writefln("line #%s: %s", lineNum, line);
11054 ----
11055 */
11056 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
11057 if (isIntegral!Enumerator && isInputRange!Range)
11058 in
11059 {
11060     static if (hasLength!Range)
11061     {
11062         // TODO: core.checkedint supports mixed signedness yet?
11063         import core.checkedint : adds, addu;
11064         import std.conv : ConvException, to;
11065         import std.traits : isSigned, Largest, Signed;
11066 
11067         alias LengthType = typeof(range.length);
11068         bool overflow;
11069         static if (isSigned!Enumerator && isSigned!LengthType)
11070             auto result = adds(start, range.length, overflow);
11071         else static if (isSigned!Enumerator)
11072         {
11073             alias signed_t = Largest!(Enumerator, Signed!LengthType);
11074             signed_t signedLength;
11075             //This is to trick the compiler because if length is enum
11076             //the compiler complains about unreachable code.
11077             auto getLength()
11078             {
11079                 return range.length;
11080             }
11081             //Can length fit in the signed type
11082             assert(getLength() < signed_t.max,
11083                 "a signed length type is required but the range's length() is too great");
11084             signedLength = range.length;
11085             auto result = adds(start, signedLength, overflow);
11086         }
11087         else
11088         {
11089             static if (isSigned!LengthType)
11090                 assert(range.length >= 0);
11091             auto result = addu(start, range.length, overflow);
11092         }
11093 
11094         assert(!overflow && result <= Enumerator.max);
11095     }
11096 }
11097 do
11098 {
11099     // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
11100     static struct Result
11101     {
11102         import std.typecons : Tuple;
11103 
11104         private:
11105         alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
11106         Range range;
11107         Unqual!Enumerator index;
11108 
11109         public:
11110         ElemType front() @property
11111         {
11112             assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
11113             return typeof(return)(index, range.front);
11114         }
11115 
11116         static if (isInfinite!Range)
11117             enum bool empty = false;
11118         else
11119         {
11120             bool empty() @property
11121             {
11122                 return range.empty;
11123             }
11124         }
11125 
11126         void popFront()
11127         {
11128             assert(!range.empty, "Attempting to popFront an empty enumerate");
11129             range.popFront();
11130             ++index; // When !hasLength!Range, overflow is expected
11131         }
11132 
11133         static if (isForwardRange!Range)
11134         {
11135             Result save() @property
11136             {
11137                 return typeof(return)(range.save, index);
11138             }
11139         }
11140 
11141         static if (hasLength!Range)
11142         {
11143             mixin ImplementLength!range;
11144 
11145             static if (isBidirectionalRange!Range)
11146             {
11147                 ElemType back() @property
11148                 {
11149                     assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
11150                     return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
11151                 }
11152 
11153                 void popBack()
11154                 {
11155                     assert(!range.empty, "Attempting to popBack an empty enumerate");
11156                     range.popBack();
11157                 }
11158             }
11159         }
11160 
11161         static if (isRandomAccessRange!Range)
11162         {
11163              ElemType opIndex(size_t i)
11164              {
11165                 return typeof(return)(cast(Enumerator)(index + i), range[i]);
11166              }
11167         }
11168 
11169         static if (hasSlicing!Range)
11170         {
11171             static if (hasLength!Range)
11172             {
11173                 Result opSlice(size_t i, size_t j)
11174                 {
11175                     return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
11176                 }
11177             }
11178             else
11179             {
11180                 static struct DollarToken {}
11181                 enum opDollar = DollarToken.init;
11182 
11183                 Result opSlice(size_t i, DollarToken)
11184                 {
11185                     return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
11186                 }
11187 
11188                 auto opSlice(size_t i, size_t j)
11189                 {
11190                     return this[i .. $].takeExactly(j - 1);
11191                 }
11192             }
11193         }
11194     }
11195 
11196     return Result(range, start);
11197 }
11198 
11199 /// Can start enumeration from a negative position:
11200 pure @safe nothrow unittest
11201 {
11202     import std.array : assocArray;
11203     import std.range : enumerate;
11204 
11205     bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
11206     assert(aa[-1]);
11207     assert(aa[0]);
11208     assert(aa[1]);
11209 }
11210 
11211 // Make sure passing qualified types works
11212 pure @safe nothrow unittest
11213 {
11214     char[4] v;
11215     immutable start = 2;
11216     v[2 .. $].enumerate(start);
11217 }
11218 
11219 pure @safe nothrow unittest
11220 {
11221     import std.internal.test.dummyrange : AllDummyRanges;
11222     import std.meta : AliasSeq;
11223     import std.typecons : tuple;
11224 
11225     static struct HasSlicing
11226     {
11227         typeof(this) front() @property { return typeof(this).init; }
11228         bool empty() @property { return true; }
11229         void popFront() {}
11230 
11231         typeof(this) opSlice(size_t, size_t)
11232         {
11233             return typeof(this)();
11234         }
11235     }
11236 
11237     static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
11238     {{
11239         alias R = typeof(enumerate(DummyType.init));
11240         static assert(isInputRange!R);
11241         static assert(isForwardRange!R == isForwardRange!DummyType);
11242         static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
11243         static assert(!hasAssignableElements!R);
11244 
11245         static if (hasLength!DummyType)
11246         {
11247             static assert(hasLength!R);
11248             static assert(isBidirectionalRange!R ==
11249                 isBidirectionalRange!DummyType);
11250         }
11251 
11252         static assert(hasSlicing!R == hasSlicing!DummyType);
11253     }}
11254 
11255     static immutable values = ["zero", "one", "two", "three"];
11256     auto enumerated = values[].enumerate();
11257     assert(!enumerated.empty);
11258     assert(enumerated.front == tuple(0, "zero"));
11259     assert(enumerated.back == tuple(3, "three"));
11260 
11261     typeof(enumerated) saved = enumerated.save;
11262     saved.popFront();
11263     assert(enumerated.front == tuple(0, "zero"));
11264     assert(saved.front == tuple(1, "one"));
11265     assert(saved.length == enumerated.length - 1);
11266     saved.popBack();
11267     assert(enumerated.back == tuple(3, "three"));
11268     assert(saved.back == tuple(2, "two"));
11269     saved.popFront();
11270     assert(saved.front == tuple(2, "two"));
11271     assert(saved.back == tuple(2, "two"));
11272     saved.popFront();
11273     assert(saved.empty);
11274 
11275     size_t control = 0;
11276     foreach (i, v; enumerated)
11277     {
11278         static assert(is(typeof(i) == size_t));
11279         static assert(is(typeof(v) == typeof(values[0])));
11280         assert(i == control);
11281         assert(v == values[i]);
11282         assert(tuple(i, v) == enumerated[i]);
11283         ++control;
11284     }
11285 
11286     assert(enumerated[0 .. $].front == tuple(0, "zero"));
11287     assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
11288 
11289     foreach (i; 0 .. 10)
11290     {
11291         auto shifted = values[0 .. 2].enumerate(i);
11292         assert(shifted.front == tuple(i, "zero"));
11293         assert(shifted[0] == shifted.front);
11294 
11295         auto next = tuple(i + 1, "one");
11296         assert(shifted[1] == next);
11297         shifted.popFront();
11298         assert(shifted.front == next);
11299         shifted.popFront();
11300         assert(shifted.empty);
11301     }
11302 
11303     static foreach (T; AliasSeq!(ubyte, byte, uint, int))
11304     {{
11305         auto inf = 42.repeat().enumerate(T.max);
11306         alias Inf = typeof(inf);
11307         static assert(isInfinite!Inf);
11308         static assert(hasSlicing!Inf);
11309 
11310         // test overflow
11311         assert(inf.front == tuple(T.max, 42));
11312         inf.popFront();
11313         assert(inf.front == tuple(T.min, 42));
11314 
11315         // test slicing
11316         inf = inf[42 .. $];
11317         assert(inf.front == tuple(T.min + 42, 42));
11318         auto window = inf[0 .. 2];
11319         assert(window.length == 1);
11320         assert(window.front == inf.front);
11321         window.popFront();
11322         assert(window.empty);
11323     }}
11324 }
11325 
11326 pure @safe unittest
11327 {
11328     import std.algorithm.comparison : equal;
11329     import std.meta : AliasSeq;
11330     static immutable int[] values = [0, 1, 2, 3, 4];
11331     static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
11332     {{
11333         auto enumerated = values.enumerate!T();
11334         static assert(is(typeof(enumerated.front.index) == T));
11335         assert(enumerated.equal(values[].zip(values)));
11336 
11337         foreach (T i; 0 .. 5)
11338         {
11339             auto subset = values[cast(size_t) i .. $];
11340             auto offsetEnumerated = subset.enumerate(i);
11341             static assert(is(typeof(enumerated.front.index) == T));
11342             assert(offsetEnumerated.equal(subset.zip(subset)));
11343         }
11344     }}
11345 }
11346 @nogc @safe unittest
11347 {
11348    const val = iota(1, 100).enumerate(1);
11349 }
11350 @nogc @safe unittest
11351 {
11352     import core.exception : AssertError;
11353     import std.exception : assertThrown;
11354     struct RangePayload {
11355         enum length = size_t.max;
11356         void popFront() {}
11357         int front() { return 0; }
11358         bool empty() { return true; }
11359     }
11360     RangePayload thePayload;
11361     //Assertion won't happen when contracts are disabled for -release.
11362     debug assertThrown!AssertError(enumerate(thePayload, -10));
11363 }
11364 // https://issues.dlang.org/show_bug.cgi?id=10939
11365 version (none)
11366 {
11367     // Re-enable (or remove) if 10939 is resolved.
11368     /+pure+/ @safe unittest // Impure because of std.conv.to
11369     {
11370         import core.exception : RangeError;
11371         import std.exception : assertNotThrown, assertThrown;
11372         import std.meta : AliasSeq;
11373 
11374         static immutable values = [42];
11375 
11376         static struct SignedLengthRange
11377         {
11378             immutable(int)[] _values = values;
11379 
11380             int front() @property { assert(false); }
11381             bool empty() @property { assert(false); }
11382             void popFront() { assert(false); }
11383 
11384             int length() @property
11385             {
11386                 return cast(int)_values.length;
11387             }
11388         }
11389 
11390         SignedLengthRange svalues;
11391         static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
11392         {
11393             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
11394             assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
11395             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
11396 
11397             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
11398             assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
11399             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
11400         }
11401 
11402         static foreach (Enumerator; AliasSeq!(byte, short, int))
11403         {
11404             assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
11405         }
11406 
11407         assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
11408     }
11409 }
11410 
11411 /**
11412   Returns true if `fn` accepts variables of type T1 and T2 in any order.
11413   The following code should compile:
11414   ---
11415   (ref T1 a, ref T2 b)
11416   {
11417     fn(a, b);
11418     fn(b, a);
11419   }
11420   ---
11421 */
11422 template isTwoWayCompatible(alias fn, T1, T2)
11423 {
11424     enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
11425         {
11426             cast(void) fn(a, b);
11427             cast(void) fn(b, a);
11428         }
11429     ));
11430 }
11431 
11432 ///
11433 @safe unittest
11434 {
11435     void func1(int a, int b);
11436     void func2(int a, float b);
11437 
11438     static assert(isTwoWayCompatible!(func1, int, int));
11439     static assert(isTwoWayCompatible!(func1, short, int));
11440     static assert(!isTwoWayCompatible!(func2, int, float));
11441 
11442     void func3(ref int a, ref int b);
11443     static assert( isTwoWayCompatible!(func3, int, int));
11444     static assert(!isTwoWayCompatible!(func3, short, int));
11445 }
11446 
11447 
11448 /**
11449    Policy used with the searching primitives `lowerBound`, $(D
11450    upperBound), and `equalRange` of $(LREF SortedRange) below.
11451  */
11452 enum SearchPolicy
11453 {
11454     /**
11455        Searches in a linear fashion.
11456     */
11457     linear,
11458 
11459     /**
11460        Searches with a step that is grows linearly (1, 2, 3,...)
11461        leading to a quadratic search schedule (indexes tried are 0, 1,
11462        3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
11463        the remaining interval is searched using binary search. The
11464        search is completed in $(BIGOH sqrt(n)) time. Use it when you
11465        are reasonably confident that the value is around the beginning
11466        of the range.
11467     */
11468     trot,
11469 
11470     /**
11471        Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
11472        galloping search algorithm), i.e. searches
11473        with a step that doubles every time, (1, 2, 4, 8, ...)  leading
11474        to an exponential search schedule (indexes tried are 0, 1, 3,
11475        7, 15, 31, 63,...) Once the search overshoots its target, the
11476        remaining interval is searched using binary search. A value is
11477        found in $(BIGOH log(n)) time.
11478     */
11479     gallop,
11480 
11481     /**
11482        Searches using a classic interval halving policy. The search
11483        starts in the middle of the range, and each search step cuts
11484        the range in half. This policy finds a value in $(BIGOH log(n))
11485        time but is less cache friendly than `gallop` for large
11486        ranges. The `binarySearch` policy is used as the last step
11487        of `trot`, `gallop`, `trotBackwards`, and $(D
11488        gallopBackwards) strategies.
11489     */
11490     binarySearch,
11491 
11492     /**
11493        Similar to `trot` but starts backwards. Use it when
11494        confident that the value is around the end of the range.
11495     */
11496     trotBackwards,
11497 
11498     /**
11499        Similar to `gallop` but starts backwards. Use it when
11500        confident that the value is around the end of the range.
11501     */
11502     gallopBackwards
11503 }
11504 
11505 ///
11506 @safe unittest
11507 {
11508     import std.algorithm.comparison : equal;
11509 
11510     auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
11511     auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
11512     assert(p1.equal([4, 5, 6, 7, 8, 9]));
11513 
11514     auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
11515     assert(p2.equal([0, 1, 2, 3]));
11516 }
11517 
11518 /**
11519    Options for $(LREF SortedRange) ranges (below).
11520 */
11521 enum SortedRangeOptions
11522 {
11523    /**
11524       Assume, that the range is sorted without checking.
11525    */
11526    assumeSorted,
11527 
11528    /**
11529       All elements of the range are checked to be sorted.
11530       The check is performed in O(n) time.
11531    */
11532    checkStrictly,
11533 
11534    /**
11535       Some elements of the range are checked to be sorted.
11536       For ranges with random order, this will almost surely
11537       detect, that it is not sorted. For almost sorted ranges
11538       it's more likely to fail. The checked elements are choosen
11539       in a deterministic manner, which makes this check reproducable.
11540       The check is performed in O(log(n)) time.
11541    */
11542    checkRoughly,
11543 }
11544 
11545 ///
11546 @safe pure unittest
11547 {
11548     // create a SortedRange, that's checked strictly
11549     SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
11550 }
11551 
11552 /**
11553    Represents a sorted range. In addition to the regular range
11554    primitives, supports additional operations that take advantage of the
11555    ordering, such as merge and binary search. To obtain a $(D
11556    SortedRange) from an unsorted range `r`, use
11557    $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
11558    corresponding `SortedRange`. To construct a `SortedRange` from a range
11559    `r` that is known to be already sorted, use $(LREF assumeSorted).
11560 
11561    Params:
11562        pred: The predicate used to define the sortedness
11563        opt: Controls how strongly the range is checked for sortedness.
11564             Will only be used for `RandomAccessRanges`.
11565             Will not be used in CTFE.
11566 */
11567 struct SortedRange(Range, alias pred = "a < b",
11568     SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11569 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
11570 {
11571     import std.functional : binaryFun;
11572 
11573     private alias predFun = binaryFun!pred;
11574     private bool geq(L, R)(L lhs, R rhs)
11575     {
11576         return !predFun(lhs, rhs);
11577     }
11578     private bool gt(L, R)(L lhs, R rhs)
11579     {
11580         return predFun(rhs, lhs);
11581     }
11582     private Range _input;
11583 
11584     // Undocummented because a clearer way to invoke is by calling
11585     // assumeSorted.
11586     this(Range input)
11587     {
11588         static if (opt == SortedRangeOptions.checkRoughly)
11589         {
11590             roughlyVerifySorted(input);
11591         }
11592         static if (opt == SortedRangeOptions.checkStrictly)
11593         {
11594             strictlyVerifySorted(input);
11595         }
11596         this._input = input;
11597     }
11598 
11599     // Assertion only.
11600     static if (opt == SortedRangeOptions.checkRoughly)
11601     private void roughlyVerifySorted(Range r)
11602     {
11603         if (!__ctfe)
11604         {
11605             static if (isRandomAccessRange!Range && hasLength!Range)
11606             {
11607                 import core.bitop : bsr;
11608                 import std.algorithm.sorting : isSorted;
11609                 import std.exception : enforce;
11610 
11611                 // Check the sortedness of the input
11612                 if (r.length < 2) return;
11613 
11614                 immutable size_t msb = bsr(r.length) + 1;
11615                 assert(msb > 0 && msb <= r.length);
11616                 immutable step = r.length / msb;
11617                 auto st = stride(r, step);
11618 
11619                 enforce(isSorted!pred(st), "Range is not sorted");
11620             }
11621         }
11622     }
11623 
11624     // Assertion only.
11625     static if (opt == SortedRangeOptions.checkStrictly)
11626     private void strictlyVerifySorted(Range r)
11627     {
11628         if (!__ctfe)
11629         {
11630             static if (isRandomAccessRange!Range && hasLength!Range)
11631             {
11632                 import std.algorithm.sorting : isSorted;
11633                 import std.exception : enforce;
11634 
11635                 enforce(isSorted!pred(r), "Range is not sorted");
11636             }
11637         }
11638     }
11639 
11640     /// Range primitives.
11641     @property bool empty()             //const
11642     {
11643         return this._input.empty;
11644     }
11645 
11646     /// Ditto
11647     static if (isForwardRange!Range)
11648     @property auto save()
11649     {
11650         // Avoid the constructor
11651         typeof(this) result = this;
11652         result._input = _input.save;
11653         return result;
11654     }
11655 
11656     /// Ditto
11657     @property auto ref front()
11658     {
11659         return _input.front;
11660     }
11661 
11662     /// Ditto
11663     void popFront()
11664     {
11665         _input.popFront();
11666     }
11667 
11668     /// Ditto
11669     static if (isBidirectionalRange!Range)
11670     {
11671         @property auto ref back()
11672         {
11673             return _input.back;
11674         }
11675 
11676         /// Ditto
11677         void popBack()
11678         {
11679             _input.popBack();
11680         }
11681     }
11682 
11683     /// Ditto
11684     static if (isRandomAccessRange!Range)
11685         auto ref opIndex(size_t i)
11686         {
11687             return _input[i];
11688         }
11689 
11690     /// Ditto
11691     static if (hasSlicing!Range)
11692         auto opSlice(size_t a, size_t b) return scope
11693         {
11694             assert(
11695                 a <= b,
11696                 "Attempting to slice a SortedRange with a larger first argument than the second."
11697             );
11698             typeof(this) result = this;
11699             result._input = _input[a .. b];// skip checking
11700             return result;
11701         }
11702 
11703     mixin ImplementLength!_input;
11704 
11705 /**
11706     Releases the controlled range and returns it.
11707 
11708     This does the opposite of $(LREF assumeSorted): instead of turning a range
11709     into a `SortedRange`, it extracts the original range back out of the `SortedRange`
11710     using $(REF, move, std,algorithm,mutation).
11711 */
11712     auto release() return scope
11713     {
11714         import std.algorithm.mutation : move;
11715         return move(_input);
11716     }
11717 
11718     ///
11719     static if (is(Range : int[]))
11720     @safe unittest
11721     {
11722         import std.algorithm.sorting : sort;
11723         int[3] data = [ 1, 2, 3 ];
11724         auto a = assumeSorted(data[]);
11725         assert(a == sort!"a < b"(data[]));
11726         int[] p = a.release();
11727         assert(p == [ 1, 2, 3 ]);
11728     }
11729 
11730     // Assuming a predicate "test" that returns 0 for a left portion
11731     // of the range and then 1 for the rest, returns the index at
11732     // which the first 1 appears. Used internally by the search routines.
11733     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11734     if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
11735     {
11736         size_t first = 0, count = _input.length;
11737         while (count > 0)
11738         {
11739             immutable step = count / 2, it = first + step;
11740             if (!test(_input[it], v))
11741             {
11742                 first = it + 1;
11743                 count -= step + 1;
11744             }
11745             else
11746             {
11747                 count = step;
11748             }
11749         }
11750         return first;
11751     }
11752 
11753     // Specialization for trot and gallop
11754     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11755     if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
11756         && isRandomAccessRange!Range)
11757     {
11758         if (empty || test(front, v)) return 0;
11759         immutable count = length;
11760         if (count == 1) return 1;
11761         size_t below = 0, above = 1, step = 2;
11762         while (!test(_input[above], v))
11763         {
11764             // Still too small, update below and increase gait
11765             below = above;
11766             immutable next = above + step;
11767             if (next >= count)
11768             {
11769                 // Overshot - the next step took us beyond the end. So
11770                 // now adjust next and simply exit the loop to do the
11771                 // binary search thingie.
11772                 above = count;
11773                 break;
11774             }
11775             // Still in business, increase step and continue
11776             above = next;
11777             static if (sp == SearchPolicy.trot)
11778                 ++step;
11779             else
11780                 step <<= 1;
11781         }
11782         return below + this[below .. above].getTransitionIndex!(
11783             SearchPolicy.binarySearch, test, V)(v);
11784     }
11785 
11786     // Specialization for trotBackwards and gallopBackwards
11787     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11788     if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
11789         && isRandomAccessRange!Range)
11790     {
11791         immutable count = length;
11792         if (empty || !test(back, v)) return count;
11793         if (count == 1) return 0;
11794         size_t below = count - 2, above = count - 1, step = 2;
11795         while (test(_input[below], v))
11796         {
11797             // Still too large, update above and increase gait
11798             above = below;
11799             if (below < step)
11800             {
11801                 // Overshot - the next step took us beyond the end. So
11802                 // now adjust next and simply fall through to do the
11803                 // binary search thingie.
11804                 below = 0;
11805                 break;
11806             }
11807             // Still in business, increase step and continue
11808             below -= step;
11809             static if (sp == SearchPolicy.trot)
11810                 ++step;
11811             else
11812                 step <<= 1;
11813         }
11814         return below + this[below .. above].getTransitionIndex!(
11815             SearchPolicy.binarySearch, test, V)(v);
11816     }
11817 
11818 // lowerBound
11819 /**
11820    This function uses a search with policy `sp` to find the
11821    largest left subrange on which $(D pred(x, value)) is `true` for
11822    all `x` (e.g., if `pred` is "less than", returns the portion of
11823    the range with elements strictly smaller than `value`). The search
11824    schedule and its complexity are documented in
11825    $(LREF SearchPolicy).
11826 */
11827     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11828     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11829          && hasSlicing!Range)
11830     {
11831         return this[0 .. getTransitionIndex!(sp, geq)(value)];
11832     }
11833 
11834     ///
11835     static if (is(Range : int[]))
11836     @safe unittest
11837     {
11838         import std.algorithm.comparison : equal;
11839         auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
11840         auto p = a.lowerBound(4);
11841         assert(equal(p, [ 0, 1, 2, 3 ]));
11842     }
11843 
11844 // upperBound
11845 /**
11846 This function searches with policy `sp` to find the largest right
11847 subrange on which $(D pred(value, x)) is `true` for all `x`
11848 (e.g., if `pred` is "less than", returns the portion of the range
11849 with elements strictly greater than `value`). The search schedule
11850 and its complexity are documented in $(LREF SearchPolicy).
11851 
11852 For ranges that do not offer random access, `SearchPolicy.linear`
11853 is the only policy allowed (and it must be specified explicitly lest it exposes
11854 user code to unexpected inefficiencies). For random-access searches, all
11855 policies are allowed, and `SearchPolicy.binarySearch` is the default.
11856 */
11857     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11858     if (isTwoWayCompatible!(predFun, ElementType!Range, V))
11859     {
11860         static assert(hasSlicing!Range || sp == SearchPolicy.linear,
11861             "Specify SearchPolicy.linear explicitly for "
11862             ~ typeof(this).stringof);
11863         static if (sp == SearchPolicy.linear)
11864         {
11865             for (; !_input.empty && !predFun(value, _input.front);
11866                  _input.popFront())
11867             {
11868             }
11869             return this;
11870         }
11871         else
11872         {
11873             return this[getTransitionIndex!(sp, gt)(value) .. length];
11874         }
11875     }
11876 
11877     ///
11878     static if (is(Range : int[]))
11879     @safe unittest
11880     {
11881         import std.algorithm.comparison : equal;
11882         auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
11883         auto p = a.upperBound(3);
11884         assert(equal(p, [4, 4, 5, 6]));
11885     }
11886 
11887 
11888 // equalRange
11889 /**
11890    Returns the subrange containing all elements `e` for which both $(D
11891    pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11892    if `pred` is "less than", returns the portion of the range with
11893    elements equal to `value`). Uses a classic binary search with
11894    interval halving until it finds a value that satisfies the condition,
11895    then uses `SearchPolicy.gallopBackwards` to find the left boundary
11896    and `SearchPolicy.gallop` to find the right boundary. These
11897    policies are justified by the fact that the two boundaries are likely
11898    to be near the first found value (i.e., equal ranges are relatively
11899    small). Completes the entire search in $(BIGOH log(n)) time.
11900 */
11901     auto equalRange(V)(V value)
11902     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11903         && isRandomAccessRange!Range)
11904     {
11905         size_t first = 0, count = _input.length;
11906         while (count > 0)
11907         {
11908             immutable step = count / 2;
11909             auto it = first + step;
11910             if (predFun(_input[it], value))
11911             {
11912                 // Less than value, bump left bound up
11913                 first = it + 1;
11914                 count -= step + 1;
11915             }
11916             else if (predFun(value, _input[it]))
11917             {
11918                 // Greater than value, chop count
11919                 count = step;
11920             }
11921             else
11922             {
11923                 // Equal to value, do binary searches in the
11924                 // leftover portions
11925                 // Gallop towards the left end as it's likely nearby
11926                 immutable left = first
11927                     + this[first .. it]
11928                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11929                 first += count;
11930                 // Gallop towards the right end as it's likely nearby
11931                 immutable right = first
11932                     - this[it + 1 .. first]
11933                     .upperBound!(SearchPolicy.gallop)(value).length;
11934                 return this[left .. right];
11935             }
11936         }
11937         return this.init;
11938     }
11939 
11940     ///
11941     static if (is(Range : int[]))
11942     @safe unittest
11943     {
11944         import std.algorithm.comparison : equal;
11945         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11946         auto r = a.assumeSorted.equalRange(3);
11947         assert(equal(r, [ 3, 3, 3 ]));
11948     }
11949 
11950 // trisect
11951 /**
11952 Returns a tuple `r` such that `r[0]` is the same as the result
11953 of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11954 equalRange(value)), and `r[2]` is the same as the result of $(D
11955 upperBound(value)). The call is faster than computing all three
11956 separately. Uses a search schedule similar to $(D
11957 equalRange). Completes the entire search in $(BIGOH log(n)) time.
11958 */
11959     auto trisect(V)(V value)
11960     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11961         && isRandomAccessRange!Range && hasLength!Range)
11962     {
11963         import std.typecons : tuple;
11964         size_t first = 0, count = _input.length;
11965         while (count > 0)
11966         {
11967             immutable step = count / 2;
11968             auto it = first + step;
11969             if (predFun(_input[it], value))
11970             {
11971                 // Less than value, bump left bound up
11972                 first = it + 1;
11973                 count -= step + 1;
11974             }
11975             else if (predFun(value, _input[it]))
11976             {
11977                 // Greater than value, chop count
11978                 count = step;
11979             }
11980             else
11981             {
11982                 // Equal to value, do binary searches in the
11983                 // leftover portions
11984                 // Gallop towards the left end as it's likely nearby
11985                 immutable left = first
11986                     + this[first .. it]
11987                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11988                 first += count;
11989                 // Gallop towards the right end as it's likely nearby
11990                 immutable right = first
11991                     - this[it + 1 .. first]
11992                     .upperBound!(SearchPolicy.gallop)(value).length;
11993                 return tuple(this[0 .. left], this[left .. right],
11994                         this[right .. length]);
11995             }
11996         }
11997         // No equal element was found
11998         return tuple(this[0 .. first], this.init, this[first .. length]);
11999     }
12000 
12001     ///
12002     static if (is(Range : int[]))
12003     @safe unittest
12004     {
12005         import std.algorithm.comparison : equal;
12006         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12007         auto r = assumeSorted(a).trisect(3);
12008         assert(equal(r[0], [ 1, 2 ]));
12009         assert(equal(r[1], [ 3, 3, 3 ]));
12010         assert(equal(r[2], [ 4, 4, 5, 6 ]));
12011     }
12012 
12013 // contains
12014 /**
12015 Returns `true` if and only if `value` can be found in $(D
12016 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
12017 evaluations of `pred`.
12018  */
12019 
12020     bool contains(V)(V value)
12021     if (isRandomAccessRange!Range)
12022     {
12023         if (empty) return false;
12024         immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
12025         if (i >= length) return false;
12026         return !predFun(value, _input[i]);
12027     }
12028 
12029 /**
12030 Like `contains`, but the value is specified before the range.
12031 */
12032     bool opBinaryRight(string op, V)(V value)
12033     if (op == "in" && isRandomAccessRange!Range)
12034     {
12035         return contains(value);
12036     }
12037 
12038 // groupBy
12039 /**
12040 Returns a range of subranges of elements that are equivalent according to the
12041 sorting relation.
12042  */
12043     auto groupBy()()
12044     {
12045         import std.algorithm.iteration : chunkBy;
12046         return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
12047     }
12048 }
12049 
12050 /// ditto
12051 template SortedRange(Range, alias pred = "a < b",
12052                      SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
12053 if (isInstanceOf!(SortedRange, Range))
12054 {
12055     // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
12056     alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
12057 }
12058 
12059 ///
12060 @safe unittest
12061 {
12062     import std.algorithm.sorting : sort;
12063     auto a = [ 1, 2, 3, 42, 52, 64 ];
12064     auto r = assumeSorted(a);
12065     assert(r.contains(3));
12066     assert(!(32 in r));
12067     auto r1 = sort!"a > b"(a);
12068     assert(3 in r1);
12069     assert(!r1.contains(32));
12070     assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
12071 }
12072 
12073 /**
12074 `SortedRange` could accept ranges weaker than random-access, but it
12075 is unable to provide interesting functionality for them. Therefore,
12076 `SortedRange` is currently restricted to random-access ranges.
12077 
12078 No copy of the original range is ever made. If the underlying range is
12079 changed concurrently with its corresponding `SortedRange` in ways
12080 that break its sorted-ness, `SortedRange` will work erratically.
12081 */
12082 @safe unittest
12083 {
12084     import std.algorithm.mutation : swap;
12085     auto a = [ 1, 2, 3, 42, 52, 64 ];
12086     auto r = assumeSorted(a);
12087     assert(r.contains(42));
12088     swap(a[3], a[5]);         // illegal to break sortedness of original range
12089     assert(!r.contains(42));  // passes although it shouldn't
12090 }
12091 
12092 /**
12093 `SortedRange` can be searched with predicates that do not take
12094 two elements of the underlying range as arguments.
12095 
12096 This is useful, if a range of structs is sorted by a member and you
12097 want to search in that range by only providing a value for that member.
12098 
12099 */
12100 @safe unittest
12101 {
12102     import std.algorithm.comparison : equal;
12103     static struct S { int i; }
12104     static bool byI(A, B)(A a, B b)
12105     {
12106         static if (is(A == S))
12107             return a.i < b;
12108         else
12109             return a < b.i;
12110     }
12111     auto r = assumeSorted!byI([S(1), S(2), S(3)]);
12112     auto lessThanTwo = r.lowerBound(2);
12113     assert(equal(lessThanTwo, [S(1)]));
12114 }
12115 
12116 @safe unittest
12117 {
12118     import std.exception : assertThrown, assertNotThrown;
12119 
12120     assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
12121     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
12122 
12123     // these two checks are implementation depended
12124     assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
12125     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
12126 }
12127 
12128 @safe unittest
12129 {
12130     import std.algorithm.comparison : equal;
12131 
12132     auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
12133     auto r = assumeSorted(a).trisect(30);
12134     assert(equal(r[0], [ 10, 20 ]));
12135     assert(equal(r[1], [ 30, 30, 30 ]));
12136     assert(equal(r[2], [ 40, 40, 50, 60 ]));
12137 
12138     r = assumeSorted(a).trisect(35);
12139     assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
12140     assert(r[1].empty);
12141     assert(equal(r[2], [ 40, 40, 50, 60 ]));
12142 }
12143 
12144 @safe unittest
12145 {
12146     import std.algorithm.comparison : equal;
12147     auto a = [ "A", "AG", "B", "E", "F" ];
12148     auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
12149     assert(equal(r[0], [ "A", "AG" ]));
12150     assert(equal(r[1], [ "B" ]));
12151     assert(equal(r[2], [ "E", "F" ]));
12152     r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
12153     assert(r[0].empty);
12154     assert(equal(r[1], [ "A" ]));
12155     assert(equal(r[2], [ "AG", "B", "E", "F" ]));
12156 }
12157 
12158 @safe unittest
12159 {
12160     import std.algorithm.comparison : equal;
12161     static void test(SearchPolicy pol)()
12162     {
12163         auto a = [ 1, 2, 3, 42, 52, 64 ];
12164         auto r = assumeSorted(a);
12165         assert(equal(r.lowerBound(42), [1, 2, 3]));
12166 
12167         assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
12168         assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
12169         assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
12170         assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
12171         assert(equal(r.lowerBound!(pol)(3), [1, 2]));
12172         assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
12173         assert(equal(r.lowerBound!(pol)(420), a));
12174         assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
12175 
12176         assert(equal(r.upperBound!(pol)(42), [52, 64]));
12177         assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
12178         assert(equal(r.upperBound!(pol)(43), [52, 64]));
12179         assert(equal(r.upperBound!(pol)(51), [52, 64]));
12180         assert(equal(r.upperBound!(pol)(53), [64]));
12181         assert(equal(r.upperBound!(pol)(55), [64]));
12182         assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
12183         assert(equal(r.upperBound!(pol)(0), a));
12184     }
12185 
12186     test!(SearchPolicy.trot)();
12187     test!(SearchPolicy.gallop)();
12188     test!(SearchPolicy.trotBackwards)();
12189     test!(SearchPolicy.gallopBackwards)();
12190     test!(SearchPolicy.binarySearch)();
12191 }
12192 
12193 @safe unittest
12194 {
12195     // Check for small arrays
12196     int[] a;
12197     auto r = assumeSorted(a);
12198     a = [ 1 ];
12199     r = assumeSorted(a);
12200     a = [ 1, 2 ];
12201     r = assumeSorted(a);
12202     a = [ 1, 2, 3 ];
12203     r = assumeSorted(a);
12204 }
12205 
12206 @safe unittest
12207 {
12208     import std.algorithm.mutation : swap;
12209     auto a = [ 1, 2, 3, 42, 52, 64 ];
12210     auto r = assumeSorted(a);
12211     assert(r.contains(42));
12212     swap(a[3], a[5]);                  // illegal to break sortedness of original range
12213     assert(!r.contains(42));            // passes although it shouldn't
12214 }
12215 
12216 @betterC @nogc nothrow @safe unittest
12217 {
12218     static immutable(int)[] arr = [ 1, 2, 3 ];
12219     auto s = assumeSorted(arr);
12220 }
12221 
12222 @system unittest
12223 {
12224     import std.algorithm.comparison : equal;
12225     int[] arr = [100, 101, 102, 200, 201, 300];
12226     auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
12227     assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
12228 }
12229 
12230 // Test on an input range
12231 @system unittest
12232 {
12233     import std.conv : text;
12234     import std.file : exists, remove, tempDir;
12235     import std.path : buildPath;
12236     import std.stdio : File;
12237     import std.uuid : randomUUID;
12238     auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
12239                           "." ~ randomUUID().toString());
12240     auto f = File(name, "w");
12241     scope(exit) if (exists(name)) remove(name);
12242     // write a sorted range of lines to the file
12243     f.write("abc\ndef\nghi\njkl");
12244     f.close();
12245     f.open(name, "r");
12246     auto r = assumeSorted(f.byLine());
12247     auto r1 = r.upperBound!(SearchPolicy.linear)("def");
12248     assert(r1.front == "ghi", r1.front);
12249     f.close();
12250 }
12251 
12252 // https://issues.dlang.org/show_bug.cgi?id=19337
12253 @safe unittest
12254 {
12255     import std.algorithm.sorting : sort;
12256     auto a = [ 1, 2, 3, 42, 52, 64 ];
12257     a.sort.sort!"a > b";
12258 }
12259 
12260 /**
12261 Assumes `r` is sorted by predicate `pred` and returns the
12262 corresponding $(D SortedRange!(pred, R)) having `r` as support.
12263 To check for sorted-ness at
12264 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
12265  */
12266 auto assumeSorted(alias pred = "a < b", R)(R r)
12267 if (isInputRange!(Unqual!R))
12268 {
12269     // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
12270     static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
12271     {
12272         static if (isInputRange!R && __traits(isSame, pred, RPred))
12273             // If the predicate is the same and we don't need to cast away
12274             // constness for the result to be an input range.
12275             return r;
12276         else
12277             return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
12278     }
12279     else
12280     {
12281         return SortedRange!(Unqual!R, pred)(r);
12282     }
12283 }
12284 
12285 ///
12286 @safe unittest
12287 {
12288     import std.algorithm.comparison : equal;
12289 
12290     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
12291     auto p = assumeSorted(a);
12292 
12293     assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
12294     assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
12295     assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
12296     assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
12297 }
12298 
12299 @safe unittest
12300 {
12301     import std.algorithm.comparison : equal;
12302     static assert(isRandomAccessRange!(SortedRange!(int[])));
12303     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12304     auto p = assumeSorted(a).upperBound(3);
12305     assert(equal(p, [4, 4, 5, 6 ]));
12306     p = assumeSorted(a).upperBound(4.2);
12307     assert(equal(p, [ 5, 6 ]));
12308 
12309     // https://issues.dlang.org/show_bug.cgi?id=18933
12310     // don't create senselessly nested SortedRange types.
12311     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
12312     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
12313 }
12314 
12315 @safe unittest
12316 {
12317     import std.algorithm.comparison : equal;
12318     import std.conv : text;
12319 
12320     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12321     auto p = assumeSorted(a).equalRange(3);
12322     assert(equal(p, [ 3, 3, 3 ]), text(p));
12323     p = assumeSorted(a).equalRange(4);
12324     assert(equal(p, [ 4, 4 ]), text(p));
12325     p = assumeSorted(a).equalRange(2);
12326     assert(equal(p, [ 2 ]));
12327     p = assumeSorted(a).equalRange(0);
12328     assert(p.empty);
12329     p = assumeSorted(a).equalRange(7);
12330     assert(p.empty);
12331     p = assumeSorted(a).equalRange(3.0);
12332     assert(equal(p, [ 3, 3, 3]));
12333 }
12334 
12335 @safe unittest
12336 {
12337     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12338     if (a.length)
12339     {
12340         auto b = a[a.length / 2];
12341         //auto r = sort(a);
12342         //assert(r.contains(b));
12343     }
12344 }
12345 
12346 @safe unittest
12347 {
12348     auto a = [ 5, 7, 34, 345, 677 ];
12349     auto r = assumeSorted(a);
12350     a = null;
12351     r = assumeSorted(a);
12352     a = [ 1 ];
12353     r = assumeSorted(a);
12354 }
12355 
12356 // https://issues.dlang.org/show_bug.cgi?id=15003
12357 @nogc @safe unittest
12358 {
12359     static immutable a = [1, 2, 3, 4];
12360     auto r = a.assumeSorted;
12361 }
12362 
12363 /++
12364     Wrapper which effectively makes it possible to pass a range by reference.
12365     Both the original range and the RefRange will always have the exact same
12366     elements. Any operation done on one will affect the other. So, for instance,
12367     if it's passed to a function which would implicitly copy the original range
12368     if it were passed to it, the original range is $(I not) copied but is
12369     consumed as if it were a reference type.
12370 
12371     Note:
12372         `save` works as normal and operates on a new range, so if
12373         `save` is ever called on the `RefRange`, then no operations on the
12374         saved range will affect the original.
12375 
12376     Params:
12377         range = the range to construct the `RefRange` from
12378 
12379     Returns:
12380         A `RefRange`. If the given range is a class type
12381         (and thus is already a reference type), then the original
12382         range is returned rather than a `RefRange`.
12383   +/
12384 struct RefRange(R)
12385 if (isInputRange!R)
12386 {
12387 public:
12388 
12389     /++ +/
12390     this(R* range) @safe pure nothrow
12391     {
12392         _range = range;
12393     }
12394 
12395 
12396     /++
12397         This does not assign the pointer of `rhs` to this `RefRange`.
12398         Rather it assigns the range pointed to by `rhs` to the range pointed
12399         to by this `RefRange`. This is because $(I any) operation on a
12400         `RefRange` is the same is if it occurred to the original range. The
12401         one exception is when a `RefRange` is assigned `null` either
12402         directly or because `rhs` is `null`. In that case, `RefRange`
12403         no longer refers to the original range but is `null`.
12404       +/
12405     auto opAssign(RefRange rhs)
12406     {
12407         if (_range && rhs._range)
12408             *_range = *rhs._range;
12409         else
12410             _range = rhs._range;
12411 
12412         return this;
12413     }
12414 
12415     /++ +/
12416     void opAssign(typeof(null) rhs)
12417     {
12418         _range = null;
12419     }
12420 
12421 
12422     /++
12423         A pointer to the wrapped range.
12424       +/
12425     @property inout(R*) ptr() @safe inout pure nothrow
12426     {
12427         return _range;
12428     }
12429 
12430 
12431     version (StdDdoc)
12432     {
12433         /++ +/
12434         @property auto front() {assert(0);}
12435         /++ Ditto +/
12436         @property auto front() const {assert(0);}
12437         /++ Ditto +/
12438         @property auto front(ElementType!R value) {assert(0);}
12439     }
12440     else
12441     {
12442         @property auto front()
12443         {
12444             return (*_range).front;
12445         }
12446 
12447         static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
12448         {
12449             return (*_range).front;
12450         }
12451 
12452         static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
12453         {
12454             return (*_range).front = value;
12455         }
12456     }
12457 
12458 
12459     version (StdDdoc)
12460     {
12461         @property bool empty(); ///
12462         @property bool empty() const; ///Ditto
12463     }
12464     else static if (isInfinite!R)
12465         enum empty = false;
12466     else
12467     {
12468         @property bool empty()
12469         {
12470             return (*_range).empty;
12471         }
12472 
12473         static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
12474         {
12475             return (*_range).empty;
12476         }
12477     }
12478 
12479 
12480     /++ +/
12481     void popFront()
12482     {
12483         return (*_range).popFront();
12484     }
12485 
12486 
12487     version (StdDdoc)
12488     {
12489         /++
12490             Only defined if `isForwardRange!R` is `true`.
12491           +/
12492         @property auto save() {assert(0);}
12493         /++ Ditto +/
12494         @property auto save() const {assert(0);}
12495         /++ Ditto +/
12496         auto opSlice() {assert(0);}
12497         /++ Ditto +/
12498         auto opSlice() const {assert(0);}
12499     }
12500     else static if (isForwardRange!R)
12501     {
12502         import std.traits : isSafe;
12503         private alias S = typeof((*_range).save);
12504 
12505         static if (is(typeof((*cast(const R*)_range).save)))
12506             private alias CS = typeof((*cast(const R*)_range).save);
12507 
12508         static if (isSafe!((R* r) => (*r).save))
12509         {
12510             @property RefRange!S save() @trusted
12511             {
12512                 mixin(_genSave());
12513             }
12514 
12515             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
12516             {
12517                 mixin(_genSave());
12518             }
12519         }
12520         else
12521         {
12522             @property RefRange!S save()
12523             {
12524                 mixin(_genSave());
12525             }
12526 
12527             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
12528             {
12529                 mixin(_genSave());
12530             }
12531         }
12532 
12533         auto opSlice()()
12534         {
12535             return save;
12536         }
12537 
12538         auto opSlice()() const
12539         {
12540             return save;
12541         }
12542 
12543         private static string _genSave() @safe pure nothrow
12544         {
12545             return `import core.lifetime : emplace;` ~
12546                    `alias S = typeof((*_range).save);` ~
12547                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
12548                    `auto mem = new void[S.sizeof];` ~
12549                    `emplace!S(mem, cast(S)(*_range).save);` ~
12550                    `return RefRange!S(cast(S*) mem.ptr);`;
12551         }
12552 
12553         static assert(isForwardRange!RefRange);
12554     }
12555 
12556 
12557     version (StdDdoc)
12558     {
12559         /++
12560             Only defined if `isBidirectionalRange!R` is `true`.
12561           +/
12562         @property auto back() {assert(0);}
12563         /++ Ditto +/
12564         @property auto back() const {assert(0);}
12565         /++ Ditto +/
12566         @property auto back(ElementType!R value) {assert(0);}
12567     }
12568     else static if (isBidirectionalRange!R)
12569     {
12570         @property auto back()
12571         {
12572             return (*_range).back;
12573         }
12574 
12575         static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
12576         {
12577             return (*_range).back;
12578         }
12579 
12580         static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
12581         {
12582             return (*_range).back = value;
12583         }
12584     }
12585 
12586 
12587     /++ Ditto +/
12588     static if (isBidirectionalRange!R) void popBack()
12589     {
12590         return (*_range).popBack();
12591     }
12592 
12593 
12594     version (StdDdoc)
12595     {
12596         /++
12597             Only defined if `isRandomAccessRange!R` is `true`.
12598           +/
12599         auto ref opIndex(IndexType)(IndexType index) {assert(0);}
12600 
12601         /++ Ditto +/
12602         auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
12603     }
12604     else static if (isRandomAccessRange!R)
12605     {
12606         auto ref opIndex(IndexType)(IndexType index)
12607             if (is(typeof((*_range)[index])))
12608         {
12609             return (*_range)[index];
12610         }
12611 
12612         auto ref opIndex(IndexType)(IndexType index) const
12613             if (is(typeof((*cast(const R*)_range)[index])))
12614         {
12615             return (*_range)[index];
12616         }
12617     }
12618 
12619 
12620     /++
12621         Only defined if `hasMobileElements!R` and `isForwardRange!R` are
12622         `true`.
12623       +/
12624     static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
12625     {
12626         return (*_range).moveFront();
12627     }
12628 
12629 
12630     /++
12631         Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
12632         are `true`.
12633       +/
12634     static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
12635     {
12636         return (*_range).moveBack();
12637     }
12638 
12639 
12640     /++
12641         Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
12642         are `true`.
12643       +/
12644     static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
12645     {
12646         return (*_range).moveAt(index);
12647     }
12648 
12649 
12650     version (StdDdoc)
12651     {
12652         /// Only defined if `hasLength!R` is `true`.
12653         @property size_t length();
12654         /// ditto
12655         @property size_t length() const;
12656         /// Ditto
12657         alias opDollar = length;
12658     }
12659     else static if (hasLength!R)
12660     {
12661         @property auto length()
12662         {
12663             return (*_range).length;
12664         }
12665         static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
12666         {
12667             return (*_range).length;
12668         }
12669         alias opDollar = length;
12670     }
12671 
12672 
12673     version (StdDdoc)
12674     {
12675         /++
12676             Only defined if `hasSlicing!R` is `true`.
12677           +/
12678         auto opSlice(IndexType1, IndexType2)
12679                     (IndexType1 begin, IndexType2 end) {assert(0);}
12680 
12681         /++ Ditto +/
12682         auto opSlice(IndexType1, IndexType2)
12683                     (IndexType1 begin, IndexType2 end) const {assert(0);}
12684     }
12685     else static if (hasSlicing!R)
12686     {
12687         private alias T = typeof((*_range)[1 .. 2]);
12688         static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
12689         {
12690             private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
12691         }
12692 
12693         RefRange!T opSlice(IndexType1, IndexType2)
12694                     (IndexType1 begin, IndexType2 end)
12695             if (is(typeof((*_range)[begin .. end])))
12696         {
12697             mixin(_genOpSlice());
12698         }
12699 
12700         RefRange!CT opSlice(IndexType1, IndexType2)
12701                     (IndexType1 begin, IndexType2 end) const
12702             if (is(typeof((*cast(const R*)_range)[begin .. end])))
12703         {
12704             mixin(_genOpSlice());
12705         }
12706 
12707         private static string _genOpSlice() @safe pure nothrow
12708         {
12709             return `import core.lifetime : emplace;` ~
12710                    `alias S = typeof((*_range)[begin .. end]);` ~
12711                    `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
12712                    `auto mem = new void[S.sizeof];` ~
12713                    `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
12714                    `return RefRange!S(cast(S*) mem.ptr);`;
12715         }
12716     }
12717 
12718 
12719 private:
12720 
12721     R* _range;
12722 }
12723 
12724 /// Basic Example
12725 @system unittest
12726 {
12727     import std.algorithm.searching : find;
12728     ubyte[] buffer = [1, 9, 45, 12, 22];
12729     auto found1 = find(buffer, 45);
12730     assert(found1 == [45, 12, 22]);
12731     assert(buffer == [1, 9, 45, 12, 22]);
12732 
12733     auto wrapped1 = refRange(&buffer);
12734     auto found2 = find(wrapped1, 45);
12735     assert(*found2.ptr == [45, 12, 22]);
12736     assert(buffer == [45, 12, 22]);
12737 
12738     auto found3 = find(wrapped1.save, 22);
12739     assert(*found3.ptr == [22]);
12740     assert(buffer == [45, 12, 22]);
12741 
12742     string str = "hello world";
12743     auto wrappedStr = refRange(&str);
12744     assert(str.front == 'h');
12745     str.popFrontN(5);
12746     assert(str == " world");
12747     assert(wrappedStr.front == ' ');
12748     assert(*wrappedStr.ptr == " world");
12749 }
12750 
12751 /// opAssign Example.
12752 @system unittest
12753 {
12754     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12755     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12756     auto wrapped1 = refRange(&buffer1);
12757     auto wrapped2 = refRange(&buffer2);
12758     assert(wrapped1.ptr is &buffer1);
12759     assert(wrapped2.ptr is &buffer2);
12760     assert(wrapped1.ptr !is wrapped2.ptr);
12761     assert(buffer1 != buffer2);
12762 
12763     wrapped1 = wrapped2;
12764 
12765     //Everything points to the same stuff as before.
12766     assert(wrapped1.ptr is &buffer1);
12767     assert(wrapped2.ptr is &buffer2);
12768     assert(wrapped1.ptr !is wrapped2.ptr);
12769 
12770     //But buffer1 has changed due to the assignment.
12771     assert(buffer1 == [6, 7, 8, 9, 10]);
12772     assert(buffer2 == [6, 7, 8, 9, 10]);
12773 
12774     buffer2 = [11, 12, 13, 14, 15];
12775 
12776     //Everything points to the same stuff as before.
12777     assert(wrapped1.ptr is &buffer1);
12778     assert(wrapped2.ptr is &buffer2);
12779     assert(wrapped1.ptr !is wrapped2.ptr);
12780 
12781     //But buffer2 has changed due to the assignment.
12782     assert(buffer1 == [6, 7, 8, 9, 10]);
12783     assert(buffer2 == [11, 12, 13, 14, 15]);
12784 
12785     wrapped2 = null;
12786 
12787     //The pointer changed for wrapped2 but not wrapped1.
12788     assert(wrapped1.ptr is &buffer1);
12789     assert(wrapped2.ptr is null);
12790     assert(wrapped1.ptr !is wrapped2.ptr);
12791 
12792     //buffer2 is not affected by the assignment.
12793     assert(buffer1 == [6, 7, 8, 9, 10]);
12794     assert(buffer2 == [11, 12, 13, 14, 15]);
12795 }
12796 
12797 @system unittest
12798 {
12799     import std.algorithm.iteration : filter;
12800     {
12801         ubyte[] buffer = [1, 2, 3, 4, 5];
12802         auto wrapper = refRange(&buffer);
12803         auto p = wrapper.ptr;
12804         auto f = wrapper.front;
12805         wrapper.front = f;
12806         auto e = wrapper.empty;
12807         wrapper.popFront();
12808         auto s = wrapper.save;
12809         auto b = wrapper.back;
12810         wrapper.back = b;
12811         wrapper.popBack();
12812         auto i = wrapper[0];
12813         wrapper.moveFront();
12814         wrapper.moveBack();
12815         wrapper.moveAt(0);
12816         auto l = wrapper.length;
12817         auto sl = wrapper[0 .. 1];
12818         assert(wrapper[0 .. $].length == buffer[0 .. $].length);
12819     }
12820 
12821     {
12822         ubyte[] buffer = [1, 2, 3, 4, 5];
12823         const wrapper = refRange(&buffer);
12824         const p = wrapper.ptr;
12825         const f = wrapper.front;
12826         const e = wrapper.empty;
12827         const s = wrapper.save;
12828         const b = wrapper.back;
12829         const i = wrapper[0];
12830         const l = wrapper.length;
12831         const sl = wrapper[0 .. 1];
12832     }
12833 
12834     {
12835         ubyte[] buffer = [1, 2, 3, 4, 5];
12836         auto filtered = filter!"true"(buffer);
12837         auto wrapper = refRange(&filtered);
12838         auto p = wrapper.ptr;
12839         auto f = wrapper.front;
12840         wrapper.front = f;
12841         auto e = wrapper.empty;
12842         wrapper.popFront();
12843         auto s = wrapper.save;
12844         wrapper.moveFront();
12845     }
12846 
12847     {
12848         ubyte[] buffer = [1, 2, 3, 4, 5];
12849         auto filtered = filter!"true"(buffer);
12850         const wrapper = refRange(&filtered);
12851         const p = wrapper.ptr;
12852 
12853         //Cannot currently be const. filter needs to be updated to handle const.
12854         /+
12855         const f = wrapper.front;
12856         const e = wrapper.empty;
12857         const s = wrapper.save;
12858         +/
12859     }
12860 
12861     {
12862         string str = "hello world";
12863         auto wrapper = refRange(&str);
12864         auto p = wrapper.ptr;
12865         auto f = wrapper.front;
12866         auto e = wrapper.empty;
12867         wrapper.popFront();
12868         auto s = wrapper.save;
12869         auto b = wrapper.back;
12870         wrapper.popBack();
12871     }
12872 
12873     {
12874         // https://issues.dlang.org/show_bug.cgi?id=16534
12875         // opDollar should be defined if the wrapped range defines length.
12876         auto range = 10.iota.takeExactly(5);
12877         auto wrapper = refRange(&range);
12878         assert(wrapper.length == 5);
12879         assert(wrapper[0 .. $ - 1].length == 4);
12880     }
12881 }
12882 
12883 //Test assignment.
12884 @system unittest
12885 {
12886     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12887     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12888     RefRange!(ubyte[]) wrapper1;
12889     RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
12890     assert(wrapper1.ptr is null);
12891     assert(wrapper2.ptr is &buffer2);
12892 
12893     wrapper1 = refRange(&buffer1);
12894     assert(wrapper1.ptr is &buffer1);
12895 
12896     wrapper1 = wrapper2;
12897     assert(wrapper1.ptr is &buffer1);
12898     assert(buffer1 == buffer2);
12899 
12900     wrapper1 = RefRange!(ubyte[]).init;
12901     assert(wrapper1.ptr is null);
12902     assert(wrapper2.ptr is &buffer2);
12903     assert(buffer1 == buffer2);
12904     assert(buffer1 == [6, 7, 8, 9, 10]);
12905 
12906     wrapper2 = null;
12907     assert(wrapper2.ptr is null);
12908     assert(buffer2 == [6, 7, 8, 9, 10]);
12909 }
12910 
12911 @system unittest
12912 {
12913     import std.algorithm.comparison : equal;
12914     import std.algorithm.mutation : bringToFront;
12915     import std.algorithm.searching : commonPrefix, find, until;
12916     import std.algorithm.sorting : sort;
12917 
12918     //Test that ranges are properly consumed.
12919     {
12920         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12921         auto wrapper = refRange(&arr);
12922 
12923         assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12924         assert(arr == [41, 3, 40, 4, 42, 9]);
12925 
12926         assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12927         assert(arr == [40, 4, 42, 9]);
12928 
12929         assert(equal(until(wrapper, 42), [40, 4]));
12930         assert(arr == [42, 9]);
12931 
12932         assert(find(wrapper, 12).empty);
12933         assert(arr.empty);
12934     }
12935 
12936     {
12937         string str = "Hello, world-like object.";
12938         auto wrapper = refRange(&str);
12939 
12940         assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12941         assert(str == "llo, world-like object.");
12942 
12943         assert(equal(take(wrapper, 5), "llo, "));
12944         assert(str == "world-like object.");
12945     }
12946 
12947     //Test that operating on saved ranges does not consume the original.
12948     {
12949         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12950         auto wrapper = refRange(&arr);
12951         auto saved = wrapper.save;
12952         saved.popFrontN(3);
12953         assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12954         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12955     }
12956 
12957     {
12958         string str = "Hello, world-like object.";
12959         auto wrapper = refRange(&str);
12960         auto saved = wrapper.save;
12961         saved.popFrontN(13);
12962         assert(*saved.ptr == "like object.");
12963         assert(str == "Hello, world-like object.");
12964     }
12965 
12966     //Test that functions which use save work properly.
12967     {
12968         int[] arr = [1, 42];
12969         auto wrapper = refRange(&arr);
12970         assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12971     }
12972 
12973     {
12974         int[] arr = [4, 5, 6, 7, 1, 2, 3];
12975         auto wrapper = refRange(&arr);
12976         assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12977         assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12978     }
12979 
12980     //Test bidirectional functions.
12981     {
12982         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12983         auto wrapper = refRange(&arr);
12984 
12985         assert(wrapper.back == 9);
12986         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12987 
12988         wrapper.popBack();
12989         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12990     }
12991 
12992     {
12993         string str = "Hello, world-like object.";
12994         auto wrapper = refRange(&str);
12995 
12996         assert(wrapper.back == '.');
12997         assert(str == "Hello, world-like object.");
12998 
12999         wrapper.popBack();
13000         assert(str == "Hello, world-like object");
13001     }
13002 
13003     //Test random access functions.
13004     {
13005         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
13006         auto wrapper = refRange(&arr);
13007 
13008         assert(wrapper[2] == 2);
13009         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
13010 
13011         assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
13012         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
13013     }
13014 
13015     //Test move functions.
13016     {
13017         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
13018         auto wrapper = refRange(&arr);
13019 
13020         auto t1 = wrapper.moveFront();
13021         auto t2 = wrapper.moveBack();
13022         wrapper.front = t2;
13023         wrapper.back = t1;
13024         assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
13025 
13026         sort(wrapper.save);
13027         assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
13028     }
13029 }
13030 
13031 @system unittest
13032 {
13033     struct S
13034     {
13035         @property int front() @safe const pure nothrow { return 0; }
13036         enum bool empty = false;
13037         void popFront() @safe pure nothrow { }
13038         @property auto save() @safe pure nothrow return scope { return this; }
13039     }
13040 
13041     S s;
13042     auto wrapper = refRange(&s);
13043     static assert(isInfinite!(typeof(wrapper)));
13044 }
13045 
13046 @system unittest
13047 {
13048     class C
13049     {
13050         @property int front() @safe const pure nothrow { return 0; }
13051         @property bool empty() @safe const pure nothrow { return false; }
13052         void popFront() @safe pure nothrow { }
13053         @property auto save() @safe pure nothrow return scope { return this; }
13054     }
13055     static assert(isForwardRange!C);
13056 
13057     auto c = new C;
13058     auto cWrapper = refRange(&c);
13059     static assert(is(typeof(cWrapper) == C));
13060     assert(cWrapper is c);
13061 }
13062 
13063 // https://issues.dlang.org/show_bug.cgi?id=14373
13064 @system unittest
13065 {
13066     static struct R
13067     {
13068         @property int front() {return 0;}
13069         void popFront() {empty = true;}
13070         bool empty = false;
13071     }
13072     R r;
13073     refRange(&r).popFront();
13074     assert(r.empty);
13075 }
13076 
13077 // https://issues.dlang.org/show_bug.cgi?id=14575
13078 @system unittest
13079 {
13080     struct R
13081     {
13082         Object front;
13083         alias back = front;
13084         bool empty = false;
13085         void popFront() {empty = true;}
13086         alias popBack = popFront;
13087         @property R save() {return this;}
13088     }
13089     static assert(isBidirectionalRange!R);
13090     R r;
13091     auto rr = refRange(&r);
13092 
13093     struct R2
13094     {
13095         @property Object front() {return null;}
13096         @property const(Object) front() const {return null;}
13097         alias back = front;
13098         bool empty = false;
13099         void popFront() {empty = true;}
13100         alias popBack = popFront;
13101         @property R2 save() {return this;}
13102     }
13103     static assert(isBidirectionalRange!R2);
13104     R2 r2;
13105     auto rr2 = refRange(&r2);
13106 }
13107 
13108 /// ditto
13109 auto refRange(R)(R* range)
13110 if (isInputRange!R)
13111 {
13112     static if (!is(R == class))
13113         return RefRange!R(range);
13114     else
13115         return *range;
13116 }
13117 
13118 // https://issues.dlang.org/show_bug.cgi?id=9060
13119 @safe unittest
13120 {
13121     import std.algorithm.iteration : map, joiner, group;
13122     import std.algorithm.searching : until;
13123     // fix for std.algorithm
13124     auto r = map!(x => 0)([1]);
13125     chain(r, r);
13126     zip(r, r);
13127     roundRobin(r, r);
13128 
13129     struct NRAR {
13130         typeof(r) input;
13131         @property empty() { return input.empty; }
13132         @property front() { return input.front; }
13133         void popFront()   { input.popFront(); }
13134         @property save()  { return NRAR(input.save); }
13135     }
13136     auto n1 = NRAR(r);
13137     cycle(n1);  // non random access range version
13138 
13139     assumeSorted(r);
13140 
13141     // fix for std.range
13142     joiner([r], [9]);
13143 
13144     struct NRAR2 {
13145         NRAR input;
13146         @property empty() { return true; }
13147         @property front() { return input; }
13148         void popFront() { }
13149         @property save()  { return NRAR2(input.save); }
13150     }
13151     auto n2 = NRAR2(n1);
13152     joiner(n2);
13153 
13154     group(r);
13155 
13156     until(r, 7);
13157     static void foo(R)(R r) { until!(x => x > 7)(r); }
13158     foo(r);
13159 }
13160 
13161 private struct Bitwise(R)
13162 if (isInputRange!R && isIntegral!(ElementType!R))
13163 {
13164     import std.traits : Unsigned;
13165 private:
13166     alias ElemType = ElementType!R;
13167     alias UnsignedElemType = Unsigned!ElemType;
13168 
13169     R parent;
13170     enum bitsNum = ElemType.sizeof * 8;
13171     size_t maskPos = 1;
13172 
13173     static if (isBidirectionalRange!R)
13174     {
13175         size_t backMaskPos = bitsNum;
13176     }
13177 
13178 public:
13179     this()(auto ref R range)
13180     {
13181         parent = range;
13182     }
13183 
13184     static if (isInfinite!R)
13185     {
13186         enum empty = false;
13187     }
13188     else
13189     {
13190         /**
13191          * Check if the range is empty
13192          *
13193          * Returns: a boolean true or false
13194          */
13195         bool empty()
13196         {
13197             static if (hasLength!R)
13198             {
13199                 return length == 0;
13200             }
13201             else static if (isBidirectionalRange!R)
13202             {
13203                 if (parent.empty)
13204                 {
13205                     return true;
13206                 }
13207                 else
13208                 {
13209                     /*
13210                        If we have consumed the last element of the range both from
13211                        the front and the back, then the masks positions will overlap
13212                      */
13213                     return parent.save.dropOne.empty && (maskPos > backMaskPos);
13214                 }
13215             }
13216             else
13217             {
13218                 /*
13219                    If we consumed the last element of the range, but not all the
13220                    bits in the last element
13221                  */
13222                 return parent.empty;
13223             }
13224         }
13225     }
13226 
13227     bool front()
13228     {
13229         assert(!empty);
13230         return (parent.front & mask(maskPos)) != 0;
13231     }
13232 
13233     void popFront()
13234     {
13235         assert(!empty);
13236         ++maskPos;
13237         if (maskPos > bitsNum)
13238         {
13239             parent.popFront;
13240             maskPos = 1;
13241         }
13242     }
13243 
13244     static if (hasLength!R)
13245     {
13246         size_t length()
13247         {
13248             auto len = parent.length * bitsNum - (maskPos - 1);
13249             static if (isBidirectionalRange!R)
13250             {
13251                 len -= bitsNum - backMaskPos;
13252             }
13253             return len;
13254         }
13255 
13256         alias opDollar = length;
13257     }
13258 
13259     static if (isForwardRange!R)
13260     {
13261         typeof(this) save()
13262         {
13263             auto result = this;
13264             result.parent = parent.save;
13265             return result;
13266         }
13267     }
13268 
13269     static if (isBidirectionalRange!R)
13270     {
13271         bool back()
13272         {
13273             assert(!empty);
13274             return (parent.back & mask(backMaskPos)) != 0;
13275         }
13276 
13277         void popBack()
13278         {
13279             assert(!empty);
13280             --backMaskPos;
13281             if (backMaskPos == 0)
13282             {
13283                 parent.popBack;
13284                 backMaskPos = bitsNum;
13285             }
13286         }
13287     }
13288 
13289     static if (isRandomAccessRange!R)
13290     {
13291         /**
13292           Return the `n`th bit within the range
13293          */
13294         bool opIndex(size_t n)
13295         in
13296         {
13297             /*
13298                If it does not have the length property, it means that R is
13299                an infinite range
13300              */
13301             static if (hasLength!R)
13302             {
13303                 assert(n < length, "Index out of bounds");
13304             }
13305         }
13306         do
13307         {
13308             immutable size_t remainingBits = bitsNum - maskPos + 1;
13309             // If n >= maskPos, then the bit sign will be 1, otherwise 0
13310             immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13311             /*
13312                By truncating n with remainingBits bits we have skipped the
13313                remaining bits in parent[0], so we need to add 1 to elemIndex.
13314 
13315                Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
13316              */
13317             import core.bitop : bsf;
13318             immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
13319 
13320             /*
13321                Since the indexing is from LSB to MSB, we need to index at the
13322                remainder of (n - remainingBits).
13323 
13324                Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
13325              */
13326             immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
13327                              + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
13328 
13329             return (parent[elemIndex] & mask(elemMaskPos)) != 0;
13330         }
13331 
13332         static if (hasAssignableElements!R)
13333         {
13334             /**
13335               Assigns `flag` to the `n`th bit within the range
13336              */
13337             void opIndexAssign(bool flag, size_t n)
13338                 in
13339                 {
13340                     static if (hasLength!R)
13341                     {
13342                         assert(n < length, "Index out of bounds");
13343                     }
13344                 }
13345             do
13346             {
13347                 import core.bitop : bsf;
13348 
13349                 immutable size_t remainingBits = bitsNum - maskPos + 1;
13350                 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13351                 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
13352                 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
13353                     + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
13354 
13355                 auto elem = parent[elemIndex];
13356                 auto elemMask = mask(elemMaskPos);
13357                 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
13358                         + (flag ^ 1) * (elem & ~elemMask));
13359             }
13360         }
13361 
13362         Bitwise!R opSlice()
13363         {
13364             return this.save;
13365         }
13366 
13367         Bitwise!R opSlice(size_t start, size_t end)
13368         in
13369         {
13370             assert(start < end, "Invalid bounds: end <= start");
13371         }
13372         do
13373         {
13374             import core.bitop : bsf;
13375 
13376             size_t remainingBits = bitsNum - maskPos + 1;
13377             ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13378             immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
13379             immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
13380                                               + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
13381 
13382             immutable size_t sliceLen = end - start - 1;
13383             remainingBits = bitsNum - startElemMaskPos + 1;
13384             sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13385             immutable size_t endElemIndex = startElemIndex
13386                                           + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
13387             immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
13388                                             + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
13389 
13390             typeof(return) result;
13391             // Get the slice to be returned from the parent
13392             result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
13393             result.maskPos = startElemMaskPos;
13394             static if (isBidirectionalRange!R)
13395             {
13396                 result.backMaskPos = endElemMaskPos;
13397             }
13398             return result;
13399         }
13400     }
13401 
13402 private:
13403     auto mask(size_t maskPos)
13404     {
13405         return (1UL << (maskPos - 1UL));
13406     }
13407 }
13408 
13409 /**
13410 Bitwise adapter over an integral type range. Consumes the range elements bit by
13411 bit, from the least significant bit to the most significant bit.
13412 
13413 Params:
13414     R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
13415     range = range to consume bit by by
13416 
13417 Returns:
13418     A `Bitwise` input range with propagated forward, bidirectional
13419     and random access capabilities
13420 */
13421 auto bitwise(R)(auto ref R range)
13422 if (isInputRange!R && isIntegral!(ElementType!R))
13423 {
13424     return Bitwise!R(range);
13425 }
13426 
13427 ///
13428 @safe pure unittest
13429 {
13430     import std.algorithm.comparison : equal;
13431     import std.format : format;
13432 
13433     // 00000011 00001001
13434     ubyte[] arr = [3, 9];
13435     auto r = arr.bitwise;
13436 
13437     // iterate through it as with any other range
13438     assert(format("%(%d%)", r) == "1100000010010000");
13439     assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
13440 
13441     auto r2 = r[5 .. $];
13442     // set a bit
13443     r[2] = 1;
13444     assert(arr[0] == 7);
13445     assert(r[5] == r2[0]);
13446 }
13447 
13448 /// You can use bitwise to implement an uniform bool generator
13449 @safe unittest
13450 {
13451     import std.algorithm.comparison : equal;
13452     import std.random : rndGen;
13453 
13454     auto rb = rndGen.bitwise;
13455     static assert(isInfinite!(typeof(rb)));
13456 
13457     auto rb2 = rndGen.bitwise;
13458     // Don't forget that structs are passed by value
13459     assert(rb.take(10).equal(rb2.take(10)));
13460 }
13461 
13462 // Test nogc inference
13463 @safe @nogc unittest
13464 {
13465     static ubyte[] arr = [3, 9];
13466     auto bw = arr.bitwise;
13467     auto bw2 = bw[];
13468     auto bw3 = bw[8 .. $];
13469     bw3[2] = true;
13470 
13471     assert(arr[1] == 13);
13472     assert(bw[$ - 6]);
13473     assert(bw[$ - 6] == bw2[$ - 6]);
13474     assert(bw[$ - 6] == bw3[$ - 6]);
13475 }
13476 
13477 // Test all range types over all integral types
13478 @safe pure nothrow unittest
13479 {
13480     import std.meta : AliasSeq;
13481     import std.internal.test.dummyrange;
13482 
13483     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13484             long, ulong);
13485     foreach (IntegralType; IntegralTypes)
13486     {
13487         foreach (T; AllDummyRangesType!(IntegralType[]))
13488         {
13489             T a;
13490             auto bw = Bitwise!T(a);
13491 
13492             static if (isForwardRange!T)
13493             {
13494                 auto bwFwdSave = bw.save;
13495             }
13496 
13497             static if (isBidirectionalRange!T)
13498             {
13499                 auto bwBack = bw.save;
13500                 auto bwBackSave = bw.save;
13501             }
13502 
13503             static if (hasLength!T)
13504             {
13505                 auto bwLength = bw.length;
13506                 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
13507                 static if (isForwardRange!T)
13508                 {
13509                     assert(bw.length == bwFwdSave.length);
13510                 }
13511             }
13512 
13513             // Make sure front and back are not the mechanisms that modify the range
13514             long numCalls = 42;
13515             bool initialFrontValue;
13516 
13517             if (!bw.empty)
13518             {
13519                 initialFrontValue = bw.front;
13520             }
13521 
13522             while (!bw.empty && (--numCalls))
13523             {
13524                 bw.front;
13525                 assert(bw.front == initialFrontValue);
13526             }
13527 
13528             /*
13529                Check that empty works properly and that popFront does not get called
13530                more times than it should
13531              */
13532             numCalls = 0;
13533             while (!bw.empty)
13534             {
13535                 ++numCalls;
13536 
13537                 static if (hasLength!T)
13538                 {
13539                     assert(bw.length == bwLength);
13540                     --bwLength;
13541                 }
13542 
13543                 static if (isForwardRange!T)
13544                 {
13545                     assert(bw.front == bwFwdSave.front);
13546                     bwFwdSave.popFront();
13547                 }
13548 
13549                 static if (isBidirectionalRange!T)
13550                 {
13551                     assert(bwBack.front == bwBackSave.front);
13552                     bwBack.popBack();
13553                     bwBackSave.popBack();
13554                 }
13555                 bw.popFront();
13556             }
13557 
13558             auto rangeLen = numCalls / (IntegralType.sizeof * 8);
13559             assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
13560             assert(bw.empty);
13561             static if (isForwardRange!T)
13562             {
13563                 assert(bwFwdSave.empty);
13564             }
13565 
13566             static if (isBidirectionalRange!T)
13567             {
13568                 assert(bwBack.empty);
13569             }
13570         }
13571     }
13572 }
13573 
13574 // Test opIndex and opSlice
13575 @system unittest
13576 {
13577     import std.meta : AliasSeq;
13578     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13579             long, ulong);
13580     foreach (IntegralType; IntegralTypes)
13581     {
13582         size_t bitsNum = IntegralType.sizeof * 8;
13583 
13584         auto first = IntegralType(1);
13585 
13586         // 2 ^ (bitsNum - 1)
13587         auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2));
13588 
13589         IntegralType[] a = [first, second];
13590         auto bw = Bitwise!(IntegralType[])(a);
13591 
13592         // Check against lsb of a[0]
13593         assert(bw[0] == true);
13594         // Check against msb - 1 of a[1]
13595         assert(bw[2 * bitsNum - 2] == true);
13596 
13597         bw.popFront();
13598         assert(bw[2 * bitsNum - 3] == true);
13599 
13600         import std.exception : assertThrown;
13601 
13602         version (D_NoBoundsChecks) {}
13603         else
13604         {
13605             // Check out of bounds error
13606             assertThrown!Error(bw[2 * bitsNum - 1]);
13607         }
13608 
13609         bw[2] = true;
13610         assert(bw[2] == true);
13611         bw.popFront();
13612         assert(bw[1] == true);
13613 
13614         auto bw2 = bw[0 .. $ - 5];
13615         auto bw3 = bw2[];
13616         assert(bw2.length == bw.length - 5);
13617         assert(bw2.length == bw3.length);
13618         bw2.popFront();
13619         assert(bw2.length != bw3.length);
13620     }
13621 }
13622 
13623 /*********************************
13624  * An OutputRange that discards the data it receives.
13625  */
13626 struct NullSink
13627 {
13628     void put(E)(scope const E) pure @safe @nogc nothrow {}
13629 }
13630 
13631 /// ditto
13632 auto ref nullSink()
13633 {
13634     static NullSink sink;
13635     return sink;
13636 }
13637 
13638 ///
13639 @safe nothrow unittest
13640 {
13641     import std.algorithm.iteration : map;
13642     import std.algorithm.mutation : copy;
13643     [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
13644 }
13645 
13646 ///
13647 @safe unittest
13648 {
13649     import std.csv : csvNextToken;
13650 
13651     string line = "a,b,c";
13652 
13653     // ignore the first column
13654     line.csvNextToken(nullSink, ',', '"');
13655     line.popFront;
13656 
13657     // look at the second column
13658     Appender!string app;
13659     line.csvNextToken(app, ',', '"');
13660     assert(app.data == "b");
13661 }
13662 
13663 @safe unittest
13664 {
13665     auto r = 10.iota
13666                 .tee(nullSink)
13667                 .dropOne;
13668 
13669     assert(r.front == 1);
13670 }
13671 
13672 /++
13673 
13674   Implements a "tee" style pipe, wrapping an input range so that elements of the
13675   range can be passed to a provided function or $(LREF OutputRange) as they are
13676   iterated over. This is useful for printing out intermediate values in a long
13677   chain of range code, performing some operation with side-effects on each call
13678   to `front` or `popFront`, or diverting the elements of a range into an
13679   auxiliary $(LREF OutputRange).
13680 
13681   It is important to note that as the resultant range is evaluated lazily,
13682   in the case of the version of `tee` that takes a function, the function
13683   will not actually be executed until the range is "walked" using functions
13684   that evaluate ranges, such as $(REF array, std,array) or
13685   $(REF fold, std,algorithm,iteration).
13686 
13687   Params:
13688   pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
13689   calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
13690   respectively, `fun`). Note that each `popFront()` call will mirror the
13691   old `front` value, not the new one. This means that the last value will
13692   not be forwarded if the range isn't iterated until empty. If
13693   `No.pipeOnPop`, only elements for which `front` does get called will be
13694   also sent to `outputRange`/`fun`. If `front` is called twice for the same
13695   element, it will still be sent only once. If this caching is undesired,
13696   consider using $(REF map, std,algorithm,iteration) instead.
13697   inputRange = The input range being passed through.
13698   outputRange = This range will receive elements of `inputRange` progressively
13699   as iteration proceeds.
13700   fun = This function will be called with elements of `inputRange`
13701   progressively as iteration proceeds.
13702 
13703   Returns:
13704   An input range that offers the elements of `inputRange`. Regardless of
13705   whether `inputRange` is a more powerful range (forward, bidirectional etc),
13706   the result is always an input range. Reading this causes `inputRange` to be
13707   iterated and returns its elements in turn. In addition, the same elements
13708   will be passed to `outputRange` or `fun` as well.
13709 
13710   See_Also: $(REF each, std,algorithm,iteration)
13711 +/
13712 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
13713 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
13714 {
13715     static struct Result
13716     {
13717         private R1 _input;
13718         private R2 _output;
13719         static if (!pipeOnPop)
13720         {
13721             private bool _frontAccessed;
13722         }
13723 
13724         mixin ImplementLength!_input;
13725 
13726         static if (isInfinite!R1)
13727         {
13728             enum bool empty = false;
13729         }
13730         else
13731         {
13732             @property bool empty() { return _input.empty; }
13733         }
13734 
13735         void popFront()
13736         {
13737             assert(!_input.empty, "Attempting to popFront an empty tee");
13738             static if (pipeOnPop)
13739             {
13740                 put(_output, _input.front);
13741             }
13742             else
13743             {
13744                 _frontAccessed = false;
13745             }
13746             _input.popFront();
13747         }
13748 
13749         @property auto ref front()
13750         {
13751             assert(!_input.empty, "Attempting to fetch the front of an empty tee");
13752             static if (!pipeOnPop)
13753             {
13754                 if (!_frontAccessed)
13755                 {
13756                     _frontAccessed = true;
13757                     put(_output, _input.front);
13758                 }
13759             }
13760             return _input.front;
13761         }
13762     }
13763 
13764     return Result(inputRange, outputRange);
13765 }
13766 
13767 /// Ditto
13768 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
13769 if (is(typeof(fun) == void) || isSomeFunction!fun)
13770 {
13771     import std.traits : isDelegate, isFunctionPointer;
13772     /*
13773         Distinguish between function literals and template lambdas
13774         when using either as an $(LREF OutputRange). Since a template
13775         has no type, typeof(template) will always return void.
13776         If it's a template lambda, it's first necessary to instantiate
13777         it with `ElementType!R1`.
13778     */
13779     static if (is(typeof(fun) == void))
13780         alias _fun = fun!(ElementType!R1);
13781     else
13782         alias _fun = fun;
13783 
13784     static if (isFunctionPointer!_fun || isDelegate!_fun)
13785     {
13786         return tee!pipeOnPop(inputRange, _fun);
13787     }
13788     else
13789     {
13790         return tee!pipeOnPop(inputRange, &_fun);
13791     }
13792 }
13793 
13794 ///
13795 @safe unittest
13796 {
13797     import std.algorithm.comparison : equal;
13798     import std.algorithm.iteration : filter, map;
13799 
13800     // Sum values while copying
13801     int[] values = [1, 4, 9, 16, 25];
13802     int sum = 0;
13803     auto newValues = values.tee!(a => sum += a).array;
13804     assert(equal(newValues, values));
13805     assert(sum == 1 + 4 + 9 + 16 + 25);
13806 
13807     // Count values that pass the first filter
13808     int count = 0;
13809     auto newValues4 = values.filter!(a => a < 10)
13810                             .tee!(a => count++)
13811                             .map!(a => a + 1)
13812                             .filter!(a => a < 10);
13813 
13814     //Fine, equal also evaluates any lazy ranges passed to it.
13815     //count is not 3 until equal evaluates newValues4
13816     assert(equal(newValues4, [2, 5]));
13817     assert(count == 3);
13818 }
13819 
13820 //
13821 @safe unittest
13822 {
13823     import std.algorithm.comparison : equal;
13824     import std.algorithm.iteration : filter, map;
13825 
13826     int[] values = [1, 4, 9, 16, 25];
13827 
13828     int count = 0;
13829     auto newValues = values.filter!(a => a < 10)
13830         .tee!(a => count++, No.pipeOnPop)
13831         .map!(a => a + 1)
13832         .filter!(a => a < 10);
13833 
13834     auto val = newValues.front;
13835     assert(count == 1);
13836     //front is only evaluated once per element
13837     val = newValues.front;
13838     assert(count == 1);
13839 
13840     //popFront() called, fun will be called
13841     //again on the next access to front
13842     newValues.popFront();
13843     newValues.front;
13844     assert(count == 2);
13845 
13846     int[] preMap = new int[](3), postMap = [];
13847     auto mappedValues = values.filter!(a => a < 10)
13848         //Note the two different ways of using tee
13849         .tee(preMap)
13850         .map!(a => a + 1)
13851         .tee!(a => postMap ~= a)
13852         .filter!(a => a < 10);
13853     assert(equal(mappedValues, [2, 5]));
13854     assert(equal(preMap, [1, 4, 9]));
13855     assert(equal(postMap, [2, 5, 10]));
13856 }
13857 
13858 //
13859 @safe unittest
13860 {
13861     import std.algorithm.comparison : equal;
13862     import std.algorithm.iteration : filter, map;
13863 
13864     char[] txt = "Line one, Line 2".dup;
13865 
13866     bool isVowel(dchar c)
13867     {
13868         import std.string : indexOf;
13869         return "AaEeIiOoUu".indexOf(c) != -1;
13870     }
13871 
13872     int vowelCount = 0;
13873     int shiftedCount = 0;
13874     auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
13875                                 .filter!(c => !isVowel(c))
13876                                 .map!(c => (c == ' ') ? c : c + 1)
13877                                 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
13878     assert(equal(removeVowels, "Mo o- Mo 3"));
13879     assert(vowelCount == 6);
13880     assert(shiftedCount == 3);
13881 }
13882 
13883 @safe unittest
13884 {
13885     // Manually stride to test different pipe behavior.
13886     void testRange(Range)(Range r)
13887     {
13888         const int strideLen = 3;
13889         int i = 0;
13890         ElementType!Range elem1;
13891         ElementType!Range elem2;
13892         while (!r.empty)
13893         {
13894             if (i % strideLen == 0)
13895             {
13896                 //Make sure front is only
13897                 //evaluated once per item
13898                 elem1 = r.front;
13899                 elem2 = r.front;
13900                 assert(elem1 == elem2);
13901             }
13902             r.popFront();
13903             i++;
13904         }
13905     }
13906 
13907     string txt = "abcdefghijklmnopqrstuvwxyz";
13908 
13909     int popCount = 0;
13910     auto pipeOnPop = txt.tee!(a => popCount++);
13911     testRange(pipeOnPop);
13912     assert(popCount == 26);
13913 
13914     int frontCount = 0;
13915     auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13916     testRange(pipeOnFront);
13917     assert(frontCount == 9);
13918 }
13919 
13920 @safe unittest
13921 {
13922     import std.algorithm.comparison : equal;
13923     import std.meta : AliasSeq;
13924 
13925     //Test diverting elements to an OutputRange
13926     string txt = "abcdefghijklmnopqrstuvwxyz";
13927 
13928     dchar[] asink1 = [];
13929     auto fsink = (dchar c) { asink1 ~= c; };
13930     auto result1 = txt.tee(fsink).array;
13931     assert(equal(txt, result1) && (equal(result1, asink1)));
13932 
13933     dchar[] _asink1 = [];
13934     auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13935     assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13936 
13937     dchar[] asink2 = new dchar[](txt.length);
13938     void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13939     auto result2 = txt.tee(&fsink2).array;
13940     assert(equal(txt, result2) && equal(result2, asink2));
13941 
13942     dchar[] asink3 = new dchar[](txt.length);
13943     auto result3 = txt.tee(asink3).array;
13944     assert(equal(txt, result3) && equal(result3, asink3));
13945 
13946     static foreach (CharType; AliasSeq!(char, wchar, dchar))
13947     {{
13948         auto appSink = appender!(CharType[])();
13949         auto appResult = txt.tee(appSink).array;
13950         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13951     }}
13952 
13953     static foreach (StringType; AliasSeq!(string, wstring, dstring))
13954     {{
13955         auto appSink = appender!StringType();
13956         auto appResult = txt.tee(appSink).array;
13957         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13958     }}
13959 }
13960 
13961 // https://issues.dlang.org/show_bug.cgi?id=13483
13962 @safe unittest
13963 {
13964     static void func1(T)(T x) {}
13965     void func2(int x) {}
13966 
13967     auto r = [1, 2, 3, 4].tee!func1.tee!func2;
13968 }
13969 
13970 /**
13971 Extends the length of the input range `r` by padding out the start of the
13972 range with the element `e`. The element `e` must be of a common type with
13973 the element type of the range `r` as defined by $(REF CommonType, std, traits).
13974 If `n` is less than the length of of `r`, then `r` is returned unmodified.
13975 
13976 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
13977 about length for strings, which is not the number of characters, or
13978 graphemes, but instead the number of encoding units. If you want to treat each
13979 grapheme as only one encoding unit long, then call
13980 $(REF byGrapheme, std, uni) before calling this function.
13981 
13982 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
13983 
13984 Params:
13985     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
13986     e = element to pad the range with
13987     n = the length to pad to
13988 
13989 Returns:
13990     A range containing the elements of the original range with the extra padding
13991 
13992 See Also:
13993     $(REF leftJustifier, std, string)
13994 */
13995 auto padLeft(R, E)(R r, E e, size_t n)
13996 if (
13997     ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
13998     !is(CommonType!(ElementType!R, E) == void)
13999 )
14000 {
14001     static if (hasLength!R)
14002         auto dataLength = r.length;
14003     else
14004         auto dataLength = r.save.walkLength(n);
14005 
14006     return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
14007 }
14008 
14009 ///
14010 @safe pure unittest
14011 {
14012     import std.algorithm.comparison : equal;
14013 
14014     assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
14015     assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
14016 
14017     assert("abc".padLeft('_', 6).equal("___abc"));
14018 }
14019 
14020 @safe pure nothrow unittest
14021 {
14022     import std.algorithm.comparison : equal;
14023     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
14024     import std.meta : AliasSeq;
14025 
14026     alias DummyRanges = AliasSeq!(
14027         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
14028         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
14029         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
14030         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
14031         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
14032         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
14033         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
14034         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
14035         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
14036         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
14037     );
14038 
14039     foreach (Range; DummyRanges)
14040     {
14041         Range r;
14042         assert(r
14043             .padLeft(0, 12)
14044             .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
14045         );
14046     }
14047 }
14048 
14049 // Test nogc inference
14050 @safe @nogc pure unittest
14051 {
14052     import std.algorithm.comparison : equal;
14053 
14054     static immutable r1 = [1, 2, 3, 4];
14055     static immutable r2 = [0, 0, 1, 2, 3, 4];
14056     assert(r1.padLeft(0, 6).equal(r2));
14057 }
14058 
14059 /**
14060 Extend the length of the input range `r` by padding out the end of the range
14061 with the element `e`. The element `e` must be of a common type with the
14062 element type of the range `r` as defined by $(REF CommonType, std, traits).
14063 If `n` is less than the length of of `r`, then the contents of `r` are
14064 returned.
14065 
14066 The range primitives that the resulting range provides depends whether or not `r`
14067 provides them. Except the functions `back` and `popBack`, which also require
14068 the range to have a length as well as `back` and `popBack`
14069 
14070 Params:
14071     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
14072     e = element to pad the range with
14073     n = the length to pad to
14074 
14075 Returns:
14076     A range containing the elements of the original range with the extra padding
14077 
14078 See Also:
14079     $(REF rightJustifier, std, string)
14080 */
14081 auto padRight(R, E)(R r, E e, size_t n)
14082 if (
14083     isInputRange!R &&
14084     !isInfinite!R &&
14085     !is(CommonType!(ElementType!R, E) == void))
14086 {
14087     static struct Result
14088     {
14089         private:
14090         R data;
14091         E element;
14092         static if (hasLength!R)
14093         {
14094             size_t padLength;
14095         }
14096         else
14097         {
14098             size_t minLength;
14099             size_t consumed;
14100         }
14101 
14102         public:
14103         bool empty() @property
14104         {
14105             static if (hasLength!R)
14106             {
14107                 return data.empty && padLength == 0;
14108             }
14109             else
14110             {
14111                 return data.empty && consumed >= minLength;
14112             }
14113         }
14114 
14115         auto front() @property
14116         {
14117             assert(!empty, "Attempting to fetch the front of an empty padRight");
14118             return data.empty ? element : data.front;
14119         }
14120 
14121         void popFront()
14122         {
14123             assert(!empty, "Attempting to popFront an empty padRight");
14124 
14125             static if (hasLength!R)
14126             {
14127                 if (!data.empty)
14128                 {
14129                     data.popFront;
14130                 }
14131                 else
14132                 {
14133                     --padLength;
14134                 }
14135             }
14136             else
14137             {
14138                 ++consumed;
14139                 if (!data.empty)
14140                 {
14141                     data.popFront;
14142                 }
14143             }
14144         }
14145 
14146         static if (hasLength!R)
14147         {
14148             size_t length() @property
14149             {
14150                 return data.length + padLength;
14151             }
14152         }
14153 
14154         static if (isForwardRange!R)
14155         {
14156             auto save() @property
14157             {
14158                 typeof(this) result = this;
14159                 data = data.save;
14160                 return result;
14161             }
14162         }
14163 
14164         static if (isBidirectionalRange!R && hasLength!R)
14165         {
14166             auto back() @property
14167             {
14168                 assert(!empty, "Attempting to fetch the back of an empty padRight");
14169                 return padLength > 0 ? element : data.back;
14170             }
14171 
14172             void popBack()
14173             {
14174                 assert(!empty, "Attempting to popBack an empty padRight");
14175                 if (padLength > 0)
14176                 {
14177                     --padLength;
14178                 }
14179                 else
14180                 {
14181                     data.popBack;
14182                 }
14183             }
14184         }
14185 
14186         static if (isRandomAccessRange!R && hasLength!R)
14187         {
14188             E opIndex(size_t index)
14189             {
14190                 assert(index <= this.length, "Index out of bounds");
14191                 return index >= data.length ? element : data[index];
14192             }
14193         }
14194 
14195         static if (hasSlicing!R && hasLength!R)
14196         {
14197             auto opSlice(size_t a, size_t b)
14198             {
14199                 assert(
14200                     a <= b,
14201                     "Attempting to slice a padRight with a larger first argument than the second."
14202                 );
14203                 assert(
14204                     b <= length,
14205                     "Attempting to slice using an out of bounds index on a padRight"
14206                 );
14207                 return Result(
14208                     a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
14209                     element, b - a);
14210             }
14211 
14212             alias opDollar = length;
14213         }
14214 
14215         this(R r, E e, size_t n)
14216         {
14217             data = r;
14218             element = e;
14219             static if (hasLength!R)
14220             {
14221                 padLength = n > data.length ? n - data.length : 0;
14222             }
14223             else
14224             {
14225                 minLength = n;
14226             }
14227         }
14228 
14229         @disable this();
14230     }
14231 
14232     return Result(r, e, n);
14233 }
14234 
14235 ///
14236 @safe pure unittest
14237 {
14238     import std.algorithm.comparison : equal;
14239 
14240     assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
14241     assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
14242 
14243     assert("abc".padRight('_', 6).equal("abc___"));
14244 }
14245 
14246 pure @safe unittest
14247 {
14248     import std.algorithm.comparison : equal;
14249     import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
14250     import std.meta : AliasSeq;
14251 
14252     auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
14253     dchar padding = '_';
14254     assert(string_input_range.padRight(padding, 6).equal("abc___"));
14255 
14256     foreach (RangeType; AllDummyRanges)
14257     {
14258         RangeType r1;
14259         assert(r1
14260             .padRight(0, 12)
14261             .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14262         );
14263 
14264         // test if Result properly uses random access ranges
14265         static if (isRandomAccessRange!RangeType)
14266         {
14267             RangeType r3;
14268             assert(r3.padRight(0, 12)[0] == 1);
14269             assert(r3.padRight(0, 12)[2] == 3);
14270             assert(r3.padRight(0, 12)[9] == 10);
14271             assert(r3.padRight(0, 12)[10] == 0);
14272             assert(r3.padRight(0, 12)[11] == 0);
14273         }
14274 
14275         // test if Result properly uses slicing and opDollar
14276         static if (hasSlicing!RangeType)
14277         {
14278             RangeType r4;
14279             assert(r4
14280                 .padRight(0, 12)[0 .. 3]
14281                 .equal([1, 2, 3])
14282             );
14283             assert(r4
14284                 .padRight(0, 12)[0 .. 10]
14285                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
14286             );
14287             assert(r4
14288                 .padRight(0, 12)[0 .. 11]
14289                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
14290             );
14291             assert(r4
14292                 .padRight(0, 12)[2 .. $]
14293                 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14294             );
14295             assert(r4
14296                 .padRight(0, 12)[0 .. $]
14297                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14298             );
14299         }
14300 
14301         // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
14302         RangeType r5;
14303         foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
14304     }
14305 }
14306 
14307 // Test nogc inference
14308 @safe @nogc pure unittest
14309 {
14310     import std.algorithm.comparison : equal;
14311 
14312     static immutable r1 = [1, 2, 3, 4];
14313     static immutable r2 = [1, 2, 3, 4, 0, 0];
14314     assert(r1.padRight(0, 6).equal(r2));
14315 }
14316 
14317 // Test back, popBack, and save
14318 @safe pure unittest
14319 {
14320     import std.algorithm.comparison : equal;
14321 
14322     auto r1 = [1, 2, 3, 4].padRight(0, 6);
14323     assert(r1.back == 0);
14324 
14325     r1.popBack;
14326     auto r2 = r1.save;
14327     assert(r1.equal([1, 2, 3, 4, 0]));
14328     assert(r2.equal([1, 2, 3, 4, 0]));
14329 
14330     r1.popBackN(2);
14331     assert(r1.back == 3);
14332     assert(r1.length == 3);
14333     assert(r2.length == 5);
14334     assert(r2.equal([1, 2, 3, 4, 0]));
14335 
14336     r2.popFront;
14337     assert(r2.length == 4);
14338     assert(r2[0] == 2);
14339     assert(r2[1] == 3);
14340     assert(r2[2] == 4);
14341     assert(r2[3] == 0);
14342     assert(r2.equal([2, 3, 4, 0]));
14343 
14344     r2.popBack;
14345     assert(r2.equal([2, 3, 4]));
14346 
14347     auto r3 = [1, 2, 3, 4].padRight(0, 6);
14348     size_t len = 0;
14349     while (!r3.empty)
14350     {
14351         ++len;
14352         r3.popBack;
14353     }
14354     assert(len == 6);
14355 }
14356 
14357 // https://issues.dlang.org/show_bug.cgi?id=19042
14358 @safe pure unittest
14359 {
14360     import std.algorithm.comparison : equal;
14361 
14362     assert([2, 5, 13].padRight(42, 10).chunks(5)
14363            .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
14364 
14365     assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
14366 }
14367 
14368 /**
14369 This simplifies a commonly used idiom in phobos for accepting any kind of string
14370 parameter. The type `R` can for example be a simple string, chained string using
14371 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
14372 characters.
14373 
14374 Only finite length character ranges are allowed with this constraint.
14375 
14376 This template is equivalent to:
14377 ---
14378 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
14379 ---
14380 
14381 See_Also:
14382 $(REF isInputRange, std,range,primitives),
14383 $(REF isInfinite, std,range,primitives),
14384 $(LREF isSomeChar),
14385 $(REF ElementEncodingType, std,range,primitives)
14386 */
14387 template isSomeFiniteCharInputRange(R)
14388 {
14389     import std.traits : isSomeChar;
14390 
14391     enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
14392         && isSomeChar!(ElementEncodingType!R);
14393 }
14394 
14395 ///
14396 @safe unittest
14397 {
14398     import std.path : chainPath;
14399     import std.range : chain;
14400 
14401     void someLibraryMethod(R)(R argument)
14402     if (isSomeFiniteCharInputRange!R)
14403     {
14404         // implementation detail, would iterate over each character of argument
14405     }
14406 
14407     someLibraryMethod("simple strings work");
14408     someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
14409     someLibraryMethod(chainPath("chained", "paths", "work"));
14410     // you can also use custom structs implementing a char range
14411 }
14412