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