1 // Written in the D programming language.
2 
3 /**
4 This module defines the notion of a range. Ranges generalize the concept of
5 arrays, lists, or anything that involves sequential access. This abstraction
6 enables the same set of algorithms (see $(MREF std, algorithm)) to be used
7 with a vast variety of different concrete types. For example,
8 a linear search algorithm such as $(REF find, std, algorithm, searching)
9 works not just for arrays, but for linked-lists, input files,
10 incoming network data, etc.
11 
12 Guides:
13 
14 There are many articles available that can bolster understanding ranges:
15 
16 $(UL
17     $(LI Ali Çehreli's $(HTTP ddili.org/ders/d.en/ranges.html, tutorial on ranges)
18         for the basics of working with and creating range-based code.)
19     $(LI Jonathan M. Davis $(LINK2 http://dconf.org/2015/talks/davis.html, $(I Introduction to Ranges))
20         talk at DConf 2015 a vivid introduction from its core constructs to practical advice.)
21     $(LI The DLang Tour's $(LINK2 http://tour.dlang.org/tour/en/basics/ranges, chapter on ranges)
22         for an interactive introduction.)
23     $(LI H. S. Teoh's $(LINK2 http://wiki.dlang.org/Component_programming_with_ranges, tutorial on
24         component programming with ranges) for a real-world showcase of the influence
25         of range-based programming on complex algorithms.)
26     $(LI Andrei Alexandrescu's article
27         $(LINK2 http://www.informit.com/articles/printerfriendly.aspx?p=1407357$(AMP)rll=1,
28         $(I On Iteration)) for conceptual aspect of ranges and the motivation
29     )
30 )
31 
32 Submodules:
33 
34 This module has two submodules:
35 
36 The $(MREF std, range, primitives) submodule
37 provides basic range functionality. It defines several templates for testing
38 whether a given object is a range, what kind of range it is, and provides
39 some common range operations.
40 
41 The $(MREF std, range, interfaces) submodule
42 provides object-based interfaces for working with ranges via runtime
43 polymorphism.
44 
45 The remainder of this module provides a rich set of range creation and
46 composition templates that let you construct new ranges out of existing ranges:
47 
48 
49 $(SCRIPT inhibitQuickIndex = 1;)
50 $(DIVC quickindex,
51 $(BOOKTABLE ,
52     $(TR $(TD $(LREF chain))
53         $(TD Concatenates several ranges into a single range.
54     ))
55     $(TR $(TD $(LREF choose))
56         $(TD Chooses one of two ranges at runtime based on a boolean condition.
57     ))
58     $(TR $(TD $(LREF chooseAmong))
59         $(TD Chooses one of several ranges at runtime based on an index.
60     ))
61     $(TR $(TD $(LREF chunks))
62         $(TD Creates a range that returns fixed-size chunks of the original
63         range.
64     ))
65     $(TR $(TD $(LREF cycle))
66         $(TD Creates an infinite range that repeats the given forward range
67         indefinitely. Good for implementing circular buffers.
68     ))
69     $(TR $(TD $(LREF drop))
70         $(TD Creates the range that results from discarding the first $(I n)
71         elements from the given range.
72     ))
73     $(TR $(TD $(LREF dropBack))
74         $(TD Creates the range that results from discarding the last $(I n)
75         elements from the given range.
76     ))
77     $(TR $(TD $(LREF dropExactly))
78         $(TD Creates the range that results from discarding exactly $(I n)
79         of the first elements from the given range.
80     ))
81     $(TR $(TD $(LREF dropBackExactly))
82         $(TD Creates the range that results from discarding exactly $(I n)
83         of the last elements from the given range.
84     ))
85     $(TR $(TD $(LREF dropOne))
86         $(TD Creates the range that results from discarding
87         the first element from the given range.
88     ))
89     $(TR $(TD $(D $(LREF dropBackOne)))
90         $(TD Creates the range that results from discarding
91         the last element from the given range.
92     ))
93     $(TR $(TD $(LREF enumerate))
94         $(TD Iterates a range with an attached index variable.
95     ))
96     $(TR $(TD $(LREF evenChunks))
97         $(TD Creates a range that returns a number of chunks of
98         approximately equal length from the original range.
99     ))
100     $(TR $(TD $(LREF frontTransversal))
101         $(TD Creates a range that iterates over the first elements of the
102         given ranges.
103     ))
104     $(TR $(TD $(LREF generate))
105         $(TD Creates a range by successive calls to a given function. This
106         allows to create ranges as a single delegate.
107     ))
108     $(TR $(TD $(LREF indexed))
109         $(TD Creates a range that offers a view of a given range as though
110         its elements were reordered according to a given range of indices.
111     ))
112     $(TR $(TD $(LREF iota))
113         $(TD Creates a range consisting of numbers between a starting point
114         and ending point, spaced apart by a given interval.
115     ))
116     $(TR $(TD $(LREF lockstep))
117         $(TD Iterates $(I n) ranges in lockstep, for use in a `foreach`
118         loop. Similar to `zip`, except that `lockstep` is designed
119         especially for `foreach` loops.
120     ))
121     $(TR $(TD $(LREF nullSink))
122         $(TD An output range that discards the data it receives.
123     ))
124     $(TR $(TD $(LREF only))
125         $(TD Creates a range that iterates over the given arguments.
126     ))
127     $(TR $(TD $(LREF padLeft))
128         $(TD Pads a range to a specified length by adding a given element to
129         the front of the range. Is lazy if the range has a known length.
130     ))
131     $(TR $(TD $(LREF padRight))
132         $(TD Lazily pads a range to a specified length by adding a given element to
133         the back of the range.
134     ))
135     $(TR $(TD $(LREF radial))
136         $(TD Given a random-access range and a starting point, creates a
137         range that alternately returns the next left and next right element to
138         the starting point.
139     ))
140     $(TR $(TD $(LREF recurrence))
141         $(TD Creates a forward range whose values are defined by a
142         mathematical recurrence relation.
143     ))
144     $(TR $(TD $(LREF refRange))
145         $(TD Pass a range by reference. Both the original range and the RefRange
146         will always have the exact same elements.
147         Any operation done on one will affect the other.
148     ))
149     $(TR $(TD $(LREF repeat))
150         $(TD Creates a range that consists of a single element repeated $(I n)
151         times, or an infinite range repeating that element indefinitely.
152     ))
153     $(TR $(TD $(LREF retro))
154         $(TD Iterates a bidirectional range backwards.
155     ))
156     $(TR $(TD $(LREF roundRobin))
157         $(TD Given $(I n) ranges, creates a new range that return the $(I n)
158         first elements of each range, in turn, then the second element of each
159         range, and so on, in a round-robin fashion.
160     ))
161     $(TR $(TD $(LREF sequence))
162         $(TD Similar to `recurrence`, except that a random-access range is
163         created.
164     ))
165     $(TR $(TD $(D $(LREF slide)))
166         $(TD Creates a range that returns a fixed-size sliding window
167         over the original range. Unlike chunks,
168         it advances a configurable number of items at a time,
169         not one chunk at a time.
170     ))
171     $(TR $(TD $(LREF stride))
172         $(TD Iterates a range with stride $(I n).
173     ))
174     $(TR $(TD $(LREF tail))
175         $(TD Return a range advanced to within `n` elements of the end of
176         the given range.
177     ))
178     $(TR $(TD $(LREF take))
179         $(TD Creates a sub-range consisting of only up to the first $(I n)
180         elements of the given range.
181     ))
182     $(TR $(TD $(LREF takeExactly))
183         $(TD Like `take`, but assumes the given range actually has $(I n)
184         elements, and therefore also defines the `length` property.
185     ))
186     $(TR $(TD $(LREF takeNone))
187         $(TD Creates a random-access range consisting of zero elements of the
188         given range.
189     ))
190     $(TR $(TD $(LREF takeOne))
191         $(TD Creates a random-access range consisting of exactly the first
192         element of the given range.
193     ))
194     $(TR $(TD $(LREF tee))
195         $(TD Creates a range that wraps a given range, forwarding along
196         its elements while also calling a provided function with each element.
197     ))
198     $(TR $(TD $(LREF transposed))
199         $(TD Transposes a range of ranges.
200     ))
201     $(TR $(TD $(LREF transversal))
202         $(TD Creates a range that iterates over the $(I n)'th elements of the
203         given random-access ranges.
204     ))
205     $(TR $(TD $(LREF zip))
206         $(TD Given $(I n) ranges, creates a range that successively returns a
207         tuple of all the first elements, a tuple of all the second elements,
208         etc.
209     ))
210 ))
211 
212 Sortedness:
213 
214 Ranges whose elements are sorted afford better efficiency with certain
215 operations. For this, the $(LREF assumeSorted) function can be used to
216 construct a $(LREF SortedRange) from a pre-sorted range. The $(REF
217 sort, std, algorithm, sorting) function also conveniently
218 returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional
219 range operations that take advantage of the fact that the range is sorted.
220 
221 Source: $(PHOBOSSRC std/range/package.d)
222 
223 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
224 
225 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha,
226          $(HTTP jmdavisprog.com, Jonathan M Davis), and Jack Stouffer. Credit
227          for some of the ideas in building this module goes to
228          $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
229  */
230 module std.range;
231 
232 public import std.array;
233 public import std.range.interfaces;
234 public import std.range.primitives;
235 public import std.typecons : Flag, Yes, No, Rebindable, rebindable;
236 
237 import std.internal.attributes : betterC;
238 import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap;
239 import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral,
240     isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf;
241 
242 
243 /**
244 Iterates a bidirectional range backwards. The original range can be
245 accessed by using the `source` property. Applying retro twice to
246 the same range yields the original range.
247 
248 Params:
249     r = the bidirectional range to iterate backwards
250 
251 Returns:
252     A bidirectional range with length if `r` also provides a length. Or,
253     if `r` is a random access range, then the return value will be random
254     access as well.
255 See_Also:
256     $(REF reverse, std,algorithm,mutation) for mutating the source range directly.
257  */
258 auto retro(Range)(Range r)
259 if (isBidirectionalRange!(Unqual!Range))
260 {
261     // Check for retro(retro(r)) and just return r in that case
262     static if (is(typeof(retro(r.source)) == Range))
263     {
264         return r.source;
265     }
266     else
267     {
268         static struct Result()
269         {
270             private alias R = Unqual!Range;
271 
272             // User code can get and set source, too
273             R source;
274 
275             static if (hasLength!R)
276             {
277                 size_t retroIndex(size_t n)
278                 {
279                     return source.length - n - 1;
280                 }
281             }
282 
283         public:
284             alias Source = R;
285 
286             @property bool empty() { return source.empty; }
287             @property auto save()
288             {
289                 return Result(source.save);
290             }
291             @property auto ref front() { return source.back; }
292             void popFront() { source.popBack(); }
293             @property auto ref back() { return source.front; }
294             void popBack() { source.popFront(); }
295 
296             static if (is(typeof(source.moveBack())))
297             {
298                 ElementType!R moveFront()
299                 {
300                     return source.moveBack();
301                 }
302             }
303 
304             static if (is(typeof(source.moveFront())))
305             {
306                 ElementType!R moveBack()
307                 {
308                     return source.moveFront();
309                 }
310             }
311 
312             static if (hasAssignableElements!R)
313             {
314                 @property void front(ElementType!R val)
315                 {
316                     import std.algorithm.mutation : move;
317 
318                     source.back = move(val);
319                 }
320 
321                 @property void back(ElementType!R val)
322                 {
323                     import std.algorithm.mutation : move;
324 
325                     source.front = move(val);
326                 }
327             }
328 
329             static if (isRandomAccessRange!(R) && hasLength!(R))
330             {
331                 auto ref opIndex(size_t n) { return source[retroIndex(n)]; }
332 
333                 static if (hasAssignableElements!R)
334                 {
335                     void opIndexAssign(ElementType!R val, size_t n)
336                     {
337                         import std.algorithm.mutation : move;
338 
339                         source[retroIndex(n)] = move(val);
340                     }
341                 }
342 
343                 static if (is(typeof(source.moveAt(0))))
344                 {
345                     ElementType!R moveAt(size_t index)
346                     {
347                         return source.moveAt(retroIndex(index));
348                     }
349                 }
350 
351                 static if (hasSlicing!R)
352                     typeof(this) opSlice(size_t a, size_t b)
353                     {
354                         return typeof(this)(source[source.length - b .. source.length - a]);
355                     }
356             }
357 
358             mixin ImplementLength!source;
359         }
360 
361         return Result!()(r);
362     }
363 }
364 
365 
366 ///
367 pure @safe nothrow @nogc unittest
368 {
369     import std.algorithm.comparison : equal;
370     int[5] a = [ 1, 2, 3, 4, 5 ];
371     int[5] b = [ 5, 4, 3, 2, 1 ];
372     assert(equal(retro(a[]), b[]));
373     assert(retro(a[]).source is a[]);
374     assert(retro(retro(a[])) is a[]);
375 }
376 
377 pure @safe nothrow unittest
378 {
379     import std.algorithm.comparison : equal;
380     static assert(isBidirectionalRange!(typeof(retro("hello"))));
381     int[] a;
382     static assert(is(typeof(a) == typeof(retro(retro(a)))));
383     assert(retro(retro(a)) is a);
384     static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
385     void test(int[] input, int[] witness)
386     {
387         auto r = retro(input);
388         assert(r.front == witness.front);
389         assert(r.back == witness.back);
390         assert(equal(r, witness));
391     }
392     test([ 1 ], [ 1 ]);
393     test([ 1, 2 ], [ 2, 1 ]);
394     test([ 1, 2, 3 ], [ 3, 2, 1 ]);
395     test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
396     test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
397     test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
398 
399     immutable foo = [1,2,3].idup;
400     auto r = retro(foo);
401     assert(equal(r, [3, 2, 1]));
402 }
403 
404 pure @safe nothrow unittest
405 {
406     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
407         ReturnBy;
408 
409     foreach (DummyType; AllDummyRanges)
410     {
411         static if (!isBidirectionalRange!DummyType)
412         {
413             static assert(!__traits(compiles, Retro!DummyType));
414         }
415         else
416         {
417             DummyType dummyRange;
418             dummyRange.reinit();
419 
420             auto myRetro = retro(dummyRange);
421             static assert(propagatesRangeType!(typeof(myRetro), DummyType));
422             assert(myRetro.front == 10);
423             assert(myRetro.back == 1);
424             assert(myRetro.moveFront() == 10);
425             assert(myRetro.moveBack() == 1);
426 
427             static if (isRandomAccessRange!DummyType && hasLength!DummyType)
428             {
429                 assert(myRetro[0] == myRetro.front);
430                 assert(myRetro.moveAt(2) == 8);
431 
432                 static if (DummyType.r == ReturnBy.Reference)
433                 {
434                     {
435                         myRetro[9]++;
436                         scope(exit) myRetro[9]--;
437                         assert(dummyRange[0] == 2);
438                         myRetro.front++;
439                         scope(exit) myRetro.front--;
440                         assert(myRetro.front == 11);
441                         myRetro.back++;
442                         scope(exit) myRetro.back--;
443                         assert(myRetro.back == 3);
444                     }
445 
446                     {
447                         myRetro.front = 0xFF;
448                         scope(exit) myRetro.front = 10;
449                         assert(dummyRange.back == 0xFF);
450 
451                         myRetro.back = 0xBB;
452                         scope(exit) myRetro.back = 1;
453                         assert(dummyRange.front == 0xBB);
454 
455                         myRetro[1] = 11;
456                         scope(exit) myRetro[1] = 8;
457                         assert(dummyRange[8] == 11);
458                     }
459                 }
460             }
461         }
462     }
463 }
464 
465 pure @safe nothrow @nogc unittest
466 {
467     import std.algorithm.comparison : equal;
468     auto LL = iota(1L, 4L);
469     auto r = retro(LL);
470     long[3] excepted = [3, 2, 1];
471     assert(equal(r, excepted[]));
472 }
473 
474 // https://issues.dlang.org/show_bug.cgi?id=12662
475 pure @safe nothrow @nogc unittest
476 {
477     int[3] src = [1,2,3];
478     int[] data = src[];
479     foreach_reverse (x; data) {}
480     foreach (x; data.retro) {}
481 }
482 
483 pure @safe nothrow unittest
484 {
485     import std.algorithm.comparison : equal;
486 
487     static struct S {
488         int v;
489         @disable this(this);
490     }
491 
492     immutable foo = [S(1), S(2), S(3)];
493     auto r = retro(foo);
494     assert(equal(r, [S(3), S(2), S(1)]));
495 }
496 
497 /**
498 Iterates range `r` with stride `n`. If the range is a
499 random-access range, moves by indexing into the range; otherwise,
500 moves by successive calls to `popFront`. Applying stride twice to
501 the same range results in a stride with a step that is the
502 product of the two applications. It is an error for `n` to be 0.
503 
504 Params:
505     r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over
506     n = the number of elements to skip over
507 
508 Returns:
509     At minimum, an input range. The resulting range will adopt the
510     range primitives of the underlying range as long as
511     $(REF hasLength, std,range,primitives) is `true`.
512  */
513 auto stride(Range)(Range r, size_t n)
514 if (isInputRange!(Unqual!Range))
515 in
516 {
517     assert(n != 0, "stride cannot have step zero.");
518 }
519 do
520 {
521     import std.algorithm.comparison : min;
522 
523     static if (is(typeof(stride(r.source, n)) == Range))
524     {
525         // stride(stride(r, n1), n2) is stride(r, n1 * n2)
526         return stride(r.source, r._n * n);
527     }
528     else
529     {
530         static struct Result
531         {
532             private alias R = Unqual!Range;
533             public R source;
534             private size_t _n;
535 
536             // Chop off the slack elements at the end
537             static if (hasLength!R &&
538                     (isRandomAccessRange!R && hasSlicing!R
539                             || isBidirectionalRange!R))
540                 private void eliminateSlackElements()
541                 {
542                     auto slack = source.length % _n;
543 
544                     if (slack)
545                     {
546                         slack--;
547                     }
548                     else if (!source.empty)
549                     {
550                         slack = min(_n, source.length) - 1;
551                     }
552                     else
553                     {
554                         slack = 0;
555                     }
556                     if (!slack) return;
557                     static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
558                     {
559                         source = source[0 .. source.length - slack];
560                     }
561                     else static if (isBidirectionalRange!R)
562                     {
563                         foreach (i; 0 .. slack)
564                         {
565                             source.popBack();
566                         }
567                     }
568                 }
569 
570             static if (isForwardRange!R)
571             {
572                 @property auto save()
573                 {
574                     return Result(source.save, _n);
575                 }
576             }
577 
578             static if (isInfinite!R)
579             {
580                 enum bool empty = false;
581             }
582             else
583             {
584                 @property bool empty()
585                 {
586                     return source.empty;
587                 }
588             }
589 
590             @property auto ref front()
591             {
592                 return source.front;
593             }
594 
595             static if (is(typeof(.moveFront(source))))
596             {
597                 ElementType!R moveFront()
598                 {
599                     return source.moveFront();
600                 }
601             }
602 
603             static if (hasAssignableElements!R)
604             {
605                 @property void front(ElementType!R val)
606                 {
607                     import std.algorithm.mutation : move;
608 
609                     source.front = move(val);
610                 }
611             }
612 
613             void popFront()
614             {
615                 source.popFrontN(_n);
616             }
617 
618             static if (isBidirectionalRange!R && hasLength!R)
619             {
620                 void popBack()
621                 {
622                     popBackN(source, _n);
623                 }
624 
625                 @property auto ref back()
626                 {
627                     eliminateSlackElements();
628                     return source.back;
629                 }
630 
631                 static if (is(typeof(.moveBack(source))))
632                 {
633                     ElementType!R moveBack()
634                     {
635                         eliminateSlackElements();
636                         return source.moveBack();
637                     }
638                 }
639 
640                 static if (hasAssignableElements!R)
641                 {
642                     @property void back(ElementType!R val)
643                     {
644                         eliminateSlackElements();
645                         source.back = val;
646                     }
647                 }
648             }
649 
650             static if (isRandomAccessRange!R && hasLength!R)
651             {
652                 auto ref opIndex(size_t n)
653                 {
654                     return source[_n * n];
655                 }
656 
657                 /**
658                    Forwards to $(D moveAt(source, n)).
659                 */
660                 static if (is(typeof(source.moveAt(0))))
661                 {
662                     ElementType!R moveAt(size_t n)
663                     {
664                         return source.moveAt(_n * n);
665                     }
666                 }
667 
668                 static if (hasAssignableElements!R)
669                 {
670                     void opIndexAssign(ElementType!R val, size_t n)
671                     {
672                         source[_n * n] = val;
673                     }
674                 }
675             }
676 
677             static if (hasSlicing!R && hasLength!R)
678                 typeof(this) opSlice(size_t lower, size_t upper)
679                 {
680                     assert(upper >= lower && upper <= length,
681                         "Attempt to get out-of-bounds slice of `stride` range");
682                     immutable translatedUpper = (upper == 0) ? 0 :
683                         (upper * _n - (_n - 1));
684                     immutable translatedLower = min(lower * _n, translatedUpper);
685 
686                     assert(translatedLower <= translatedUpper,
687                         "Overflow when calculating slice of `stride` range");
688 
689                     return typeof(this)(source[translatedLower .. translatedUpper], _n);
690                 }
691 
692             static if (hasLength!R)
693             {
694                 @property auto length()
695                 {
696                     return (source.length + _n - 1) / _n;
697                 }
698 
699                 alias opDollar = length;
700             }
701         }
702         return Result(r, n);
703     }
704 }
705 
706 ///
707 pure @safe nothrow unittest
708 {
709     import std.algorithm.comparison : equal;
710 
711     int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
712     assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
713     assert(stride(stride(a, 2), 3) == stride(a, 6));
714 }
715 
716 pure @safe nothrow @nogc unittest
717 {
718     import std.algorithm.comparison : equal;
719 
720     int[4] testArr = [1,2,3,4];
721     static immutable result = [1, 3];
722     assert(equal(testArr[].stride(2), result));
723 }
724 
725 debug pure nothrow @system unittest
726 {//check the contract
727     int[4] testArr = [1,2,3,4];
728     bool passed = false;
729     scope (success) assert(passed);
730     import core.exception : AssertError;
731     //std.exception.assertThrown won't do because it can't infer nothrow
732     // https://issues.dlang.org/show_bug.cgi?id=12647
733     try
734     {
735         auto unused = testArr[].stride(0);
736     }
737     catch (AssertError unused)
738     {
739         passed = true;
740     }
741 }
742 
743 pure @safe nothrow unittest
744 {
745     import std.algorithm.comparison : equal;
746     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
747         ReturnBy;
748 
749     static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
750     void test(size_t n, int[] input, int[] witness)
751     {
752         assert(equal(stride(input, n), witness));
753     }
754     test(1, [], []);
755     int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
756     assert(stride(stride(arr, 2), 3) is stride(arr, 6));
757     test(1, arr, arr);
758     test(2, arr, [1, 3, 5, 7, 9]);
759     test(3, arr, [1, 4, 7, 10]);
760     test(4, arr, [1, 5, 9]);
761 
762     // Test slicing.
763     auto s1 = stride(arr, 1);
764     assert(equal(s1[1 .. 4], [2, 3, 4]));
765     assert(s1[1 .. 4].length == 3);
766     assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
767     assert(s1[1 .. 5].length == 4);
768     assert(s1[0 .. 0].empty);
769     assert(s1[3 .. 3].empty);
770     // assert(s1[$ .. $].empty);
771     assert(s1[s1.opDollar .. s1.opDollar].empty);
772 
773     auto s2 = stride(arr, 2);
774     assert(equal(s2[0 .. 2], [1,3]));
775     assert(s2[0 .. 2].length == 2);
776     assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
777     assert(s2[1 .. 5].length == 4);
778     assert(s2[0 .. 0].empty);
779     assert(s2[3 .. 3].empty);
780     // assert(s2[$ .. $].empty);
781     assert(s2[s2.opDollar .. s2.opDollar].empty);
782 
783     // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035
784     auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
785     auto col = stride(m, 4);
786     assert(equal(col, [1, 1, 1]));
787     assert(equal(retro(col), [1, 1, 1]));
788 
789     immutable int[] immi = [ 1, 2, 3 ];
790     static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
791 
792     // Check for infiniteness propagation.
793     static assert(isInfinite!(typeof(stride(repeat(1), 3))));
794 
795     foreach (DummyType; AllDummyRanges)
796     {
797         DummyType dummyRange;
798         dummyRange.reinit();
799 
800         auto myStride = stride(dummyRange, 4);
801 
802         // Should fail if no length and bidirectional b/c there's no way
803         // to know how much slack we have.
804         static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
805         {
806             static assert(propagatesRangeType!(typeof(myStride), DummyType));
807         }
808         assert(myStride.front == 1);
809         assert(myStride.moveFront() == 1);
810         assert(equal(myStride, [1, 5, 9]));
811 
812         static if (hasLength!DummyType)
813         {
814             assert(myStride.length == 3);
815         }
816 
817         static if (isBidirectionalRange!DummyType && hasLength!DummyType)
818         {
819             assert(myStride.back == 9);
820             assert(myStride.moveBack() == 9);
821         }
822 
823         static if (isRandomAccessRange!DummyType && hasLength!DummyType)
824         {
825             assert(myStride[0] == 1);
826             assert(myStride[1] == 5);
827             assert(myStride.moveAt(1) == 5);
828             assert(myStride[2] == 9);
829 
830             static assert(hasSlicing!(typeof(myStride)));
831         }
832 
833         static if (DummyType.r == ReturnBy.Reference)
834         {
835             // Make sure reference is propagated.
836 
837             {
838                 myStride.front++;
839                 scope(exit) myStride.front--;
840                 assert(dummyRange.front == 2);
841             }
842             {
843                 myStride.front = 4;
844                 scope(exit) myStride.front = 1;
845                 assert(dummyRange.front == 4);
846             }
847 
848             static if (isBidirectionalRange!DummyType && hasLength!DummyType)
849             {
850                 {
851                     myStride.back++;
852                     scope(exit) myStride.back--;
853                     assert(myStride.back == 10);
854                 }
855                 {
856                     myStride.back = 111;
857                     scope(exit) myStride.back = 9;
858                     assert(myStride.back == 111);
859                 }
860 
861                 static if (isRandomAccessRange!DummyType)
862                 {
863                     {
864                         myStride[1]++;
865                         scope(exit) myStride[1]--;
866                         assert(dummyRange[4] == 6);
867                     }
868                     {
869                         myStride[1] = 55;
870                         scope(exit) myStride[1] = 5;
871                         assert(dummyRange[4] == 55);
872                     }
873                 }
874             }
875         }
876     }
877 }
878 
879 pure @safe nothrow unittest
880 {
881     import std.algorithm.comparison : equal;
882 
883     auto LL = iota(1L, 10L);
884     auto s = stride(LL, 3);
885     assert(equal(s, [1L, 4L, 7L]));
886 }
887 
888 pure @safe nothrow unittest
889 {
890     import std.algorithm.comparison : equal;
891 
892     static struct S {
893         int v;
894         @disable this(this);
895     }
896 
897     immutable foo = [S(1), S(2), S(3), S(4), S(5)];
898     auto r = stride(foo, 3);
899     assert(equal(r, [S(1), S(4)]));
900 }
901 
902 /**
903 Spans multiple ranges in sequence. The function `chain` takes any
904 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
905 ranges may be different, but they must have the same element type. The
906 result is a range that offers the `front`, `popFront`, and $(D
907 empty) primitives. If all input ranges offer random access and $(D
908 length), `Chain` offers them as well.
909 
910 Note that repeated random access of the resulting range is likely
911 to perform somewhat badly since lengths of the ranges in the chain have to be
912 added up for each random access operation. Random access to elements of
913 the first remaining range is still efficient.
914 
915 If only one range is offered to `Chain` or `chain`, the $(D
916 Chain) type exits the picture by aliasing itself directly to that
917 range's type.
918 
919 Params:
920     rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together
921 
922 Returns:
923     An input range at minimum. If all of the ranges in `rs` provide
924     a range primitive, the returned range will also provide that range
925     primitive.
926 
927 See_Also: $(LREF only) to chain values to a range
928  */
929 auto chain(Ranges...)(Ranges rs)
930 if (Ranges.length > 0 &&
931     allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
932     !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
933 {
934     static if (Ranges.length == 1)
935     {
936         return rs[0];
937     }
938     else
939     {
940         static struct Result
941         {
942         private:
943             alias R = staticMap!(Unqual, Ranges);
944             alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
945             template sameET(A)
946             {
947                 enum sameET = is(.ElementType!A == RvalueElementType);
948             }
949 
950             enum bool allSameType = allSatisfy!(sameET, R),
951                 bidirectional = allSatisfy!(isBidirectionalRange, R),
952                 mobileElements = allSatisfy!(hasMobileElements, R),
953                 assignableElements = allSameType
954                     && allSatisfy!(hasAssignableElements, R);
955 
956             alias ElementType = RvalueElementType;
957 
958             static if (allSameType && allSatisfy!(hasLvalueElements, R))
959             {
960                 static ref RvalueElementType fixRef(ref RvalueElementType val)
961                 {
962                     return val;
963                 }
964             }
965             else
966             {
967                 static RvalueElementType fixRef(RvalueElementType val)
968                 {
969                     return val;
970                 }
971             }
972 
973             R source;
974             size_t frontIndex;
975             // Always points to index one past the last non-empty range,
976             // because otherwise decrementing while pointing to first range
977             // would overflow to size_t.max.
978             static if (bidirectional) size_t backIndex;
979             else enum backIndex = source.length;
980 
981             this(typeof(Result.tupleof) fields)
982             {
983                 this.tupleof = fields;
984             }
985 
986         public:
987             this(R input)
988             {
989                 frontIndex = source.length;
990                 static if (bidirectional) backIndex = 0;
991 
992                 foreach (i, ref v; input) source[i] = v;
993 
994                 // We do this separately to avoid invoking `empty` needlessly.
995                 // While not recommended, a range may depend on side effects of
996                 // `empty` call.
997                 foreach (i, ref v; input) if (!v.empty)
998                 {
999                     frontIndex = i;
1000                     static if (bidirectional) backIndex = i+1;
1001                     break;
1002                 }
1003 
1004                 // backIndex is already set in the first loop to
1005                 // as frontIndex+1, so we'll use that if we don't find a
1006                 // non-empty range here.
1007                 static if (bidirectional)
1008                     static foreach_reverse (i; 1 .. R.length + 1)
1009                 {
1010                     if (i <= frontIndex + 1) return;
1011                     if (!input[i-1].empty)
1012                     {
1013                         backIndex = i;
1014                         return;
1015                     }
1016                 }
1017             }
1018 
1019             import std.meta : anySatisfy;
1020 
1021             static if (anySatisfy!(isInfinite, R))
1022             {
1023                 // Propagate infiniteness.
1024                 enum bool empty = false;
1025             }
1026             else
1027             {
1028                 @property bool empty() => frontIndex >= backIndex;
1029             }
1030 
1031             static if (allSatisfy!(isForwardRange, R))
1032             {
1033                 @property auto save()
1034                 {
1035                     auto saveI(size_t i)() => source[i].save;
1036 
1037                     // TODO: this has the constructor needlessly refind
1038                     // frontIndex and backIndex. It'd be better to just copy
1039                     // those from `.this`.
1040                     auto saveResult =
1041                         Result(staticMap!(saveI, aliasSeqOf!(R.length.iota)));
1042 
1043                     return saveResult;
1044                 }
1045             }
1046 
1047             void popFront()
1048             {
1049                 sw1: switch (frontIndex)
1050                 {
1051                     static foreach (i; 0 .. R.length)
1052                     {
1053                     case i:
1054                         source[i].popFront();
1055                         break sw1;
1056                     }
1057 
1058                 case R.length:
1059                     assert(0, "Attempt to `popFront` of empty `chain` range");
1060 
1061                 default:
1062                     assert(0, "Internal library error. Please report it.");
1063                 }
1064 
1065                 sw2: switch (frontIndex)
1066                 {
1067                     static foreach (i; 0 .. R.length)
1068                     {
1069                     case i:
1070                         if (source[i].empty)
1071                         {
1072                             frontIndex++;
1073                             goto case;
1074                         }
1075                         else break sw2;
1076                     }
1077 
1078                 // Only possible to reach from goto of previous case.
1079                 case R.length:
1080                     break;
1081 
1082                 default:
1083                     assert(0, "Internal library error. Please report it.");
1084                 }
1085             }
1086 
1087             @property auto ref front()
1088             {
1089                 switch (frontIndex)
1090                 {
1091                     static foreach (i; 0 .. R.length)
1092                     {
1093                     case i:
1094                         return fixRef(source[i].front);
1095                     }
1096 
1097                 case R.length:
1098                     assert(0, "Attempt to get `front` of empty `chain` range");
1099 
1100                 default:
1101                     assert(0, "Internal library error. Please report it.");
1102                 }
1103             }
1104 
1105             static if (assignableElements)
1106             {
1107                 // @@@BUG@@@
1108                 //@property void front(T)(T v) if (is(T : RvalueElementType))
1109 
1110                 @property void front(RvalueElementType v)
1111                 {
1112                     import std.algorithm.mutation : move;
1113 
1114                     sw: switch (frontIndex)
1115                     {
1116                         static foreach (i; 0 .. R.length)
1117                         {
1118                         case i:
1119                             source[i].front = move(v);
1120                             break sw;
1121                         }
1122 
1123                     case R.length:
1124                         assert(0, "Attempt to set `front` of empty `chain` range");
1125 
1126                     default:
1127                         assert(0, "Internal library error. Please report it.");
1128                     }
1129                 }
1130             }
1131 
1132             static if (mobileElements)
1133             {
1134                 RvalueElementType moveFront()
1135                 {
1136                     switch (frontIndex)
1137                     {
1138                         static foreach (i; 0 .. R.length)
1139                         {
1140                         case i:
1141                             return source[i].moveFront();
1142                         }
1143 
1144                     case R.length:
1145                         assert(0, "Attempt to `moveFront` of empty `chain` range");
1146 
1147                     default:
1148                         assert(0, "Internal library error. Please report it.");
1149                     }
1150                 }
1151             }
1152 
1153             static if (bidirectional)
1154             {
1155                 @property auto ref back()
1156                 {
1157                     switch (backIndex)
1158                     {
1159                         static foreach_reverse (i; 1 .. R.length + 1)
1160                         {
1161                         case i:
1162                             return fixRef(source[i-1].back);
1163                         }
1164 
1165                     case 0:
1166                         assert(0, "Attempt to get `back` of empty `chain` range");
1167 
1168                     default:
1169                         assert(0, "Internal library error. Please report it.");
1170                     }
1171                 }
1172 
1173                 void popBack()
1174                 {
1175                     sw1: switch (backIndex)
1176                     {
1177                         static foreach_reverse (i; 1 .. R.length + 1)
1178                         {
1179                         case i:
1180                             source[i-1].popBack();
1181                             break sw1;
1182                         }
1183 
1184                     case 0:
1185                         assert(0, "Attempt to `popFront` of empty `chain` range");
1186 
1187                     default:
1188                         assert(0, "Internal library error. Please report it.");
1189                     }
1190 
1191                     sw2: switch (backIndex)
1192                     {
1193                         static foreach_reverse (i; 1 .. R.length + 1)
1194                         {
1195                         case i:
1196                             if (source[i-1].empty)
1197                             {
1198                                 backIndex--;
1199                                 goto case;
1200                             }
1201                             else break sw2;
1202                         }
1203 
1204                     // Only possible to reach from goto of previous case.
1205                     case 0:
1206                         break;
1207 
1208                     default:
1209                         assert(0, "Internal library error. Please report it.");
1210                     }
1211                 }
1212 
1213                 static if (mobileElements)
1214                 {
1215                     RvalueElementType moveBack()
1216                     {
1217                         switch (backIndex)
1218                         {
1219                             static foreach_reverse (i; 1 .. R.length + 1)
1220                             {
1221                             case i:
1222                                 return source[i-1].moveBack();
1223                             }
1224 
1225                         case 0:
1226                             assert(0, "Attempt to `moveBack` of empty `chain` range");
1227 
1228                         default:
1229                             assert(0, "Internal library error. Please report it.");
1230                         }
1231                     }
1232                 }
1233 
1234                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1235                 {
1236                     @property void back(RvalueElementType v)
1237                     {
1238                         import std.algorithm.mutation : move;
1239 
1240                         sw: switch (backIndex)
1241                         {
1242                             static foreach_reverse (i; 1 .. R.length + 1)
1243                             {
1244                             case i:
1245                                 source[i-1].back = move(v);
1246                                 break sw;
1247                             }
1248 
1249                         case 0:
1250                             assert(0, "Attempt to set `back` of empty `chain` range");
1251 
1252                         default:
1253                             assert(0, "Internal library error. Please report it.");
1254                         }
1255                     }
1256                 }
1257             }
1258 
1259             static if (allSatisfy!(hasLength, R))
1260             {
1261                 @property size_t length()
1262                 {
1263                     size_t result = 0;
1264                     sw: switch (frontIndex)
1265                     {
1266                         static foreach (i; 0 .. R.length)
1267                         {
1268                         case i:
1269                             result += source[i].length;
1270                             if (backIndex == i+1) break sw;
1271                             else goto case;
1272                         }
1273 
1274                     case R.length:
1275                         break;
1276 
1277                     default:
1278                         assert(0, "Internal library error. Please report it.");
1279                     }
1280 
1281                     return result;
1282                 }
1283 
1284                 alias opDollar = length;
1285             }
1286 
1287             static if (allSatisfy!(isRandomAccessRange, R))
1288             {
1289                 auto ref opIndex(size_t index)
1290                 {
1291                     switch (frontIndex)
1292                     {
1293                         static foreach (i; 0 .. R.length)
1294                         {
1295                         case i:
1296                             static if (!isInfinite!(R[i]))
1297                             {
1298                                 immutable length = source[i].length;
1299                                 if (index >= length)
1300                                 {
1301                                     index -= length;
1302                                     goto case;
1303                                 }
1304                             }
1305 
1306                             return fixRef(source[i][index]);
1307                         }
1308 
1309                     case R.length:
1310                         assert(0, "Attempt to access out-of-bounds index of `chain` range");
1311 
1312                     default:
1313                         assert(0, "Internal library error. Please report it.");
1314                     }
1315                 }
1316 
1317                 static if (mobileElements)
1318                 {
1319                     RvalueElementType moveAt(size_t index)
1320                     {
1321                         switch (frontIndex)
1322                         {
1323                             static foreach (i; 0 .. R.length)
1324                             {
1325                             case i:
1326                                 static if (!isInfinite!(R[i]))
1327                                 {
1328                                     immutable length = source[i].length;
1329                                     if (index >= length)
1330                                     {
1331                                         index -= length;
1332                                         goto case;
1333                                     }
1334                                 }
1335 
1336                                 return source[i].moveAt(index);
1337                             }
1338 
1339                         case R.length:
1340                             assert(0, "Attempt to move out-of-bounds index of `chain` range");
1341 
1342                         default:
1343                             assert(0, "Internal library error. Please report it.");
1344                         }
1345                     }
1346                 }
1347 
1348                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1349                     void opIndexAssign(ElementType v, size_t index)
1350                     {
1351                         import std.algorithm.mutation : move;
1352 
1353                         sw: switch (frontIndex)
1354                         {
1355                             static foreach (i; 0 .. R.length)
1356                             {
1357                             case i:
1358                                 static if (!isInfinite!(R[i]))
1359                                 {
1360                                     immutable length = source[i].length;
1361                                     if (index >= length)
1362                                     {
1363                                         index -= length;
1364                                         goto case;
1365                                     }
1366                                 }
1367 
1368                                 source[i][index] = move(v);
1369                                 break sw;
1370                             }
1371 
1372                         case R.length:
1373                             assert(0, "Attempt to write out-of-bounds index of `chain` range");
1374 
1375                         default:
1376                             assert(0, "Internal library error. Please report it.");
1377                         }
1378                     }
1379             }
1380 
1381             static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
1382                 auto opSlice(size_t begin, size_t end) return scope
1383                 {
1384                     // force staticMap type conversion to Rebindable
1385                     static struct ResultRanges
1386                     {
1387                         staticMap!(Rebindable, typeof(source)) fields;
1388                     }
1389                     auto sourceI(size_t i)() => rebindable(this.source[i]);
1390                     auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields;
1391                     size_t resultFrontIndex = this.frontIndex;
1392                     static if (bidirectional)
1393                         size_t resultBackIndex = this.backIndex;
1394 
1395                     sw: switch (frontIndex)
1396                     {
1397                         static foreach (i; 0 .. R.length)
1398                         {
1399                         case i:
1400                             immutable len = resultRanges[i].length;
1401                             if (len <= begin)
1402                             {
1403                                 resultRanges[i] = resultRanges[i]
1404                                     [len .. len];
1405                                 begin -= len;
1406                                 resultFrontIndex++;
1407                                 goto case;
1408                             }
1409                             else
1410                             {
1411                                 resultRanges[i] = resultRanges[i]
1412                                     [begin .. len];
1413                                 break sw;
1414                             }
1415                         }
1416 
1417                     case R.length:
1418                         assert(begin == 0,
1419                             "Attempt to access out-of-bounds slice of `chain` range");
1420                         break;
1421 
1422                     default:
1423                         assert(0, "Internal library error. Please report it.");
1424                     }
1425 
1426                     // Overflow intentional if end index too big.
1427                     // This will trigger the bounds check failure below.
1428                     auto cut = length - end;
1429 
1430                     sw2: switch (backIndex)
1431                     {
1432                         static foreach_reverse (i; 1 .. R.length + 1)
1433                         {
1434                         case i:
1435                             immutable len = resultRanges[i-1].length;
1436                             if (len <= cut)
1437                             {
1438                                 resultRanges[i-1] = resultRanges[i-1]
1439                                     [0 .. 0];
1440                                 cut -= len;
1441                                 resultBackIndex--;
1442                                 goto case;
1443                             }
1444                             else
1445                             {
1446                                 resultRanges[i-1] = resultRanges[i-1]
1447                                     [0 .. len - cut];
1448                                 break sw2;
1449                             }
1450                         }
1451 
1452                     case 0:
1453                         assert(cut == 0, end > length?
1454                             "Attempt to access out-of-bounds slice of `chain` range":
1455                             "Attempt to access negative length slice of `chain` range");
1456                         break sw2;
1457 
1458                     default:
1459                         assert(0, "Internal library error. Please report it.");
1460                     }
1461 
1462                     static if (bidirectional)
1463                         return Result(resultRanges, resultFrontIndex, resultBackIndex);
1464                     else
1465                         return Result(resultRanges, resultFrontIndex);
1466                 }
1467         }
1468         return Result(rs);
1469     }
1470 }
1471 
1472 ///
1473 pure @safe nothrow unittest
1474 {
1475     import std.algorithm.comparison : equal;
1476 
1477     int[] arr1 = [ 1, 2, 3, 4 ];
1478     int[] arr2 = [ 5, 6 ];
1479     int[] arr3 = [ 7 ];
1480     auto s = chain(arr1, arr2, arr3);
1481     assert(s.length == 7);
1482     assert(s[5] == 6);
1483     assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1484 }
1485 
1486 /**
1487  * Range primitives are carried over to the returned range if
1488  * all of the ranges provide them
1489  */
1490 pure @safe nothrow unittest
1491 {
1492     import std.algorithm.comparison : equal;
1493     import std.algorithm.sorting : sort;
1494 
1495     int[] arr1 = [5, 2, 8];
1496     int[] arr2 = [3, 7, 9];
1497     int[] arr3 = [1, 4, 6];
1498 
1499     // in-place sorting across all of the arrays
1500     auto s = arr1.chain(arr2, arr3).sort;
1501 
1502     assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1503     assert(arr1.equal([1, 2, 3]));
1504     assert(arr2.equal([4, 5, 6]));
1505     assert(arr3.equal([7, 8, 9]));
1506 }
1507 
1508 /**
1509 Due to safe type promotion in D, chaining together different
1510 character ranges results in a `uint` range.
1511 
1512 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf),
1513 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges
1514 to get the type you need.
1515  */
1516 pure @safe nothrow unittest
1517 {
1518     import std.utf : byChar, byCodeUnit;
1519 
1520     auto s1 = "string one";
1521     auto s2 = "string two";
1522     // s1 and s2 front is dchar because of auto-decoding
1523     static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
1524 
1525     auto r1 = s1.chain(s2);
1526     // chains of ranges of the same character type give that same type
1527     static assert(is(typeof(r1.front) == dchar));
1528 
1529     auto s3 = "string three".byCodeUnit;
1530     static assert(is(typeof(s3.front) == immutable char));
1531     auto r2 = s1.chain(s3);
1532     // chaining ranges of mixed character types gives `dchar`
1533     static assert(is(typeof(r2.front) == dchar));
1534 
1535     // use byChar on character ranges to correctly convert them to UTF-8
1536     auto r3 = s1.byChar.chain(s3);
1537     static assert(is(typeof(r3.front) == immutable char));
1538 }
1539 
1540 pure @safe nothrow unittest
1541 {
1542     import std.algorithm.comparison : equal;
1543     import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1544                                           propagatesRangeType;
1545 
1546     {
1547         int[] arr1 = [ 1, 2, 3, 4 ];
1548         int[] arr2 = [ 5, 6 ];
1549         int[] arr3 = [ 7 ];
1550         int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1551         auto s1 = chain(arr1);
1552         static assert(isRandomAccessRange!(typeof(s1)));
1553         auto s2 = chain(arr1, arr2);
1554         static assert(isBidirectionalRange!(typeof(s2)));
1555         static assert(isRandomAccessRange!(typeof(s2)));
1556         s2.front = 1;
1557         auto s = chain(arr1, arr2, arr3);
1558         assert(s[5] == 6);
1559         assert(equal(s, witness));
1560         assert(s[4 .. 6].equal(arr2));
1561         assert(s[2 .. 5].equal([3, 4, 5]));
1562         assert(s[0 .. 0].empty);
1563         assert(s[7 .. $].empty);
1564         assert(s[5] == 6);
1565     }
1566     {
1567         int[] arr1 = [ 1, 2, 3, 4 ];
1568         int[] witness = [ 1, 2, 3, 4 ];
1569         assert(equal(chain(arr1), witness));
1570     }
1571     {
1572         uint[] foo = [1,2,3,4,5];
1573         uint[] bar = [1,2,3,4,5];
1574         auto c = chain(foo, bar);
1575         c[3] = 42;
1576         assert(c[3] == 42);
1577         assert(c.moveFront() == 1);
1578         assert(c.moveBack() == 5);
1579         assert(c.moveAt(4) == 5);
1580         assert(c.moveAt(5) == 1);
1581     }
1582 
1583 
1584     // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed.
1585     // elements are mutable.
1586     assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1587 
1588     // Test the case where infinite ranges are present.
1589     auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1590     assert(inf[0] == 0);
1591     assert(inf[3] == 4);
1592     assert(inf[6] == 4);
1593     assert(inf[7] == 5);
1594     static assert(isInfinite!(typeof(inf)));
1595 
1596     immutable int[] immi = [ 1, 2, 3 ];
1597     immutable float[] immf = [ 1, 2, 3 ];
1598     static assert(is(typeof(chain(immi, immf))));
1599 
1600     // Check that chain at least instantiates and compiles with every possible
1601     // pair of DummyRange types, in either order.
1602 
1603     foreach (DummyType1; AllDummyRanges)
1604     (){ // workaround slow optimizations for large functions
1605         // https://issues.dlang.org/show_bug.cgi?id=2396
1606         DummyType1 dummy1;
1607         foreach (DummyType2; AllDummyRanges)
1608         {
1609             DummyType2 dummy2;
1610             auto myChain = chain(dummy1, dummy2);
1611 
1612             static assert(
1613                 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1614             );
1615 
1616             assert(myChain.front == 1);
1617             foreach (i; 0 .. dummyLength)
1618             {
1619                 myChain.popFront();
1620             }
1621             assert(myChain.front == 1);
1622 
1623             static if (isBidirectionalRange!DummyType1 &&
1624                       isBidirectionalRange!DummyType2) {
1625                 assert(myChain.back == 10);
1626             }
1627 
1628             static if (isRandomAccessRange!DummyType1 &&
1629                       isRandomAccessRange!DummyType2) {
1630                 assert(myChain[0] == 1);
1631             }
1632 
1633             static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1634             {
1635                 static assert(hasLvalueElements!(typeof(myChain)));
1636             }
1637             else
1638             {
1639                 static assert(!hasLvalueElements!(typeof(myChain)));
1640             }
1641         }
1642     }();
1643 }
1644 
1645 pure @safe nothrow @nogc unittest
1646 {
1647     class Foo{}
1648     immutable(Foo)[] a;
1649     immutable(Foo)[] b;
1650     assert(chain(a, b).empty);
1651 }
1652 
1653 // https://issues.dlang.org/show_bug.cgi?id=18657
1654 pure @safe unittest
1655 {
1656     import std.algorithm.comparison : equal;
1657     string s = "foo";
1658     auto r = refRange(&s).chain("bar");
1659     assert(equal(r.save, "foobar"));
1660     assert(equal(r, "foobar"));
1661 }
1662 
1663 // https://issues.dlang.org/show_bug.cgi?id=23844
1664 pure @safe unittest
1665 {
1666     struct S
1667     {
1668         immutable int value;
1669     }
1670 
1671     auto range = chain(only(S(5)), only(S(6)));
1672     assert(range.array == [S(5), S(6)]);
1673 }
1674 
1675 /// https://issues.dlang.org/show_bug.cgi?id=24064
1676 pure @safe nothrow unittest
1677 {
1678     import std.algorithm.comparison : equal;
1679     import std.typecons : Nullable;
1680 
1681     immutable Nullable!string foo = "b";
1682     string[] bar = ["a"];
1683     assert(chain(bar, foo).equal(["a", "b"]));
1684 }
1685 
1686 pure @safe nothrow @nogc unittest
1687 {
1688     // support non-copyable items
1689 
1690     static struct S {
1691         int v;
1692         @disable this(this);
1693     }
1694 
1695     S[2] s0, s1;
1696     foreach (ref el; chain(s0[], s1[]))
1697     {
1698         int n = el.v;
1699     }
1700 
1701     S[] s2, s3;
1702     foreach (ref el; chain(s2, s3))
1703     {
1704         int n = el.v;
1705     }
1706 }
1707 
1708 /**
1709 Choose one of two ranges at runtime depending on a Boolean condition.
1710 
1711 The ranges may be different, but they must have compatible element types (i.e.
1712 `CommonType` must exist for the two element types). The result is a range
1713 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D
1714 R1) is a random-access range and `R2` is a forward range).
1715 
1716 Params:
1717     condition = which range to choose: `r1` if `true`, `r2` otherwise
1718     r1 = the "true" range
1719     r2 = the "false" range
1720 
1721 Returns:
1722     A range type dependent on `R1` and `R2`.
1723  */
1724 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
1725 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1726     !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1727 {
1728     size_t choice = condition? 0: 1;
1729     return ChooseResult!(R1, R2)(choice, r1, r2);
1730 }
1731 
1732 ///
1733 @safe nothrow pure @nogc unittest
1734 {
1735     import std.algorithm.comparison : equal;
1736     import std.algorithm.iteration : filter, map;
1737 
1738     auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
1739     auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
1740 
1741     // choose() is primarily useful when you need to select one of two ranges
1742     // with different types at runtime.
1743     static assert(!is(typeof(data1) == typeof(data2)));
1744 
1745     auto chooseRange(bool pickFirst)
1746     {
1747         // The returned range is a common wrapper type that can be used for
1748         // returning or storing either range without running into a type error.
1749         return choose(pickFirst, data1, data2);
1750 
1751         // Simply returning the chosen range without using choose() does not
1752         // work, because map() and filter() return different types.
1753         //return pickFirst ? data1 : data2; // does not compile
1754     }
1755 
1756     auto result = chooseRange(true);
1757     assert(result.equal(only(1, 2, 4)));
1758 
1759     result = chooseRange(false);
1760     assert(result.equal(only(6, 7, 8, 9)));
1761 }
1762 
1763 
1764 private struct ChooseResult(Ranges...)
1765 {
1766     import std.meta : aliasSeqOf, ApplyLeft;
1767     import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor,
1768         lvalueOf;
1769 
1770     private union
1771     {
1772         Ranges rs;
1773     }
1774     private size_t chosenI;
1775 
1776     private static auto ref actOnChosen(alias foo, ExtraArgs ...)
1777         (ref ChooseResult r, auto ref ExtraArgs extraArgs)
1778     {
1779         ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1780 
1781         switch (r.chosenI)
1782         {
1783             static foreach (candI; 0 .. rs.length)
1784             {
1785                 case candI: return foo(getI!candI(r), extraArgs);
1786             }
1787 
1788             default: assert(false);
1789         }
1790     }
1791 
1792     // @trusted because of assignment of r which overlap each other
1793     this(size_t chosen, return scope Ranges rs) @trusted
1794     {
1795         import core.lifetime : emplace;
1796 
1797         // This should be the only place chosenI is ever assigned
1798         // independently
1799         this.chosenI = chosen;
1800 
1801         // Otherwise the compiler will complain about skipping these fields
1802         static foreach (i; 0 .. rs.length)
1803         {
1804             this.rs[i] = Ranges[i].init;
1805         }
1806 
1807         // The relevant field needs to be initialized last so it will overwrite
1808         // the other initializations and not the other way around.
1809         sw: switch (chosenI)
1810         {
1811             static foreach (i; 0 .. rs.length)
1812             {
1813                 case i:
1814                 emplace(&this.rs[i], rs[i]);
1815                 break sw;
1816             }
1817 
1818             default: assert(false);
1819         }
1820     }
1821 
1822     // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/)
1823     // without this overload the regular constructor would invert the meaning of
1824     // the boolean
1825     static if (rs.length == 2)
1826     pragma(inline, true)
1827     deprecated("Call with size_t (0 = first), or use the choose function")
1828     this(bool firstChosen, Ranges rs)
1829     {
1830         import core.lifetime : move;
1831         this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move);
1832     }
1833 
1834     void opAssign(ChooseResult r)
1835     {
1836         ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1837 
1838         static if (anySatisfy!(hasElaborateDestructor, Ranges))
1839             if (chosenI != r.chosenI)
1840         {
1841             // destroy the current item
1842             actOnChosen!((ref r) => destroy(r))(this);
1843         }
1844         chosenI = r.chosenI;
1845 
1846         sw: switch (chosenI)
1847         {
1848             static foreach (candI; 0 .. rs.length)
1849             {
1850                 case candI: getI!candI(this) = getI!candI(r);
1851                 break sw;
1852             }
1853 
1854             default: assert(false);
1855         }
1856     }
1857 
1858     // Carefully defined postblit to postblit the appropriate range
1859     static if (anySatisfy!(hasElaborateCopyConstructor, Ranges))
1860     this(this)
1861     {
1862         actOnChosen!((ref r) {
1863                 static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit();
1864             })(this);
1865     }
1866 
1867     static if (anySatisfy!(hasElaborateDestructor, Ranges))
1868     ~this()
1869     {
1870         actOnChosen!((ref r) => destroy(r))(this);
1871     }
1872 
1873     // Propagate infiniteness.
1874     static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false;
1875     else @property bool empty()
1876     {
1877         return actOnChosen!(r => r.empty)(this);
1878     }
1879 
1880     @property auto ref front()
1881     {
1882         static auto ref getFront(R)(ref R r) { return r.front; }
1883         return actOnChosen!getFront(this);
1884     }
1885 
1886     void popFront()
1887     {
1888         return actOnChosen!((ref r) { r.popFront; })(this);
1889     }
1890 
1891     static if (allSatisfy!(isForwardRange, Ranges))
1892     @property auto save() // return scope inferred
1893     {
1894         auto saveOrInit(size_t i)()
1895         {
1896             ref getI() @trusted { return rs[i]; }
1897             if (i == chosenI) return getI().save;
1898             else return Ranges[i].init;
1899         }
1900 
1901         return typeof(this)(chosenI, staticMap!(saveOrInit,
1902             aliasSeqOf!(rs.length.iota)));
1903     }
1904 
1905     template front(T)
1906     {
1907         private enum overloadValidFor(alias r) = is(typeof(r.front = T.init));
1908 
1909         static if (allSatisfy!(overloadValidFor, rs))
1910         void front(T v)
1911         {
1912             actOnChosen!((ref r, T v) { r.front = v; })(this, v);
1913         }
1914     }
1915 
1916     static if (allSatisfy!(hasMobileElements, Ranges))
1917     auto moveFront()
1918     {
1919         return actOnChosen!((ref r) => r.moveFront)(this);
1920     }
1921 
1922     static if (allSatisfy!(isBidirectionalRange, Ranges))
1923     {
1924         @property auto ref back()
1925         {
1926             static auto ref getBack(R)(ref R r) { return r.back; }
1927             return actOnChosen!getBack(this);
1928         }
1929 
1930         void popBack()
1931         {
1932             actOnChosen!((ref r) { r.popBack; })(this);
1933         }
1934 
1935         static if (allSatisfy!(hasMobileElements, Ranges))
1936         auto moveBack()
1937         {
1938             return actOnChosen!((ref r) => r.moveBack)(this);
1939         }
1940 
1941         template back(T)
1942         {
1943             private enum overloadValidFor(alias r) = is(typeof(r.back = T.init));
1944 
1945             static if (allSatisfy!(overloadValidFor, rs))
1946             void back(T v)
1947             {
1948                 actOnChosen!((ref r, T v) { r.back = v; })(this, v);
1949             }
1950         }
1951     }
1952 
1953     static if (allSatisfy!(hasLength, Ranges))
1954     {
1955         @property size_t length()
1956         {
1957             return actOnChosen!(r => r.length)(this);
1958         }
1959         alias opDollar = length;
1960     }
1961 
1962     static if (allSatisfy!(isRandomAccessRange, Ranges))
1963     {
1964         auto ref opIndex(size_t index)
1965         {
1966             static auto ref get(R)(ref R r, size_t index) { return r[index]; }
1967             return actOnChosen!get(this, index);
1968         }
1969 
1970         static if (allSatisfy!(hasMobileElements, Ranges))
1971             auto moveAt(size_t index)
1972             {
1973                 return actOnChosen!((ref r, size_t index) => r.moveAt(index))
1974                     (this, index);
1975             }
1976 
1977         private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init));
1978 
1979         template opIndexAssign(T)
1980         if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges))
1981         {
1982             void opIndexAssign(T v, size_t index)
1983             {
1984                 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
1985                     (this, index, v);
1986             }
1987         }
1988     }
1989 
1990     static if (allSatisfy!(hasSlicing, Ranges))
1991     auto opSlice(size_t begin, size_t end)
1992     {
1993         alias Slice(R) = typeof(R.init[0 .. 1]);
1994         alias Slices = staticMap!(Slice, Ranges);
1995 
1996         auto sliceOrInit(size_t i)()
1997         {
1998             ref getI() @trusted { return rs[i]; }
1999             return i == chosenI? getI()[begin .. end]: Slices[i].init;
2000         }
2001 
2002         return chooseAmong(chosenI, staticMap!(sliceOrInit,
2003             aliasSeqOf!(rs.length.iota)));
2004     }
2005 }
2006 
2007 // https://issues.dlang.org/show_bug.cgi?id=18657
2008 pure @safe unittest
2009 {
2010     import std.algorithm.comparison : equal;
2011     string s = "foo";
2012     auto r = choose(true, refRange(&s), "bar");
2013     assert(equal(r.save, "foo"));
2014     assert(equal(r, "foo"));
2015 }
2016 
2017 @safe unittest
2018 {
2019     static void* p;
2020     static struct R
2021     {
2022         void* q;
2023         int front;
2024         bool empty;
2025         void popFront() {}
2026         // `p = q;` is only there to prevent inference of `scope return`.
2027         @property @safe R save() { p = q; return this; }
2028 
2029     }
2030     R r;
2031     choose(true, r, r).save;
2032 }
2033 
2034 // Make sure ChooseResult.save doesn't trust @system user code.
2035 @system unittest // copy is @system
2036 {
2037     static struct R
2038     {
2039         int front;
2040         bool empty;
2041         void popFront() {}
2042         this(this) @system {}
2043         @property R save() { return R(front, empty); }
2044     }
2045     choose(true, R(), R()).save;
2046     choose(true, [0], R()).save;
2047     choose(true, R(), [0]).save;
2048 }
2049 
2050 @safe unittest // copy is @system
2051 {
2052     static struct R
2053     {
2054         int front;
2055         bool empty;
2056         void popFront() {}
2057         this(this) @system {}
2058         @property R save() { return R(front, empty); }
2059     }
2060     static assert(!__traits(compiles, choose(true, R(), R()).save));
2061     static assert(!__traits(compiles, choose(true, [0], R()).save));
2062     static assert(!__traits(compiles, choose(true, R(), [0]).save));
2063 }
2064 
2065 @system unittest // .save is @system
2066 {
2067     static struct R
2068     {
2069         int front;
2070         bool empty;
2071         void popFront() {}
2072         @property R save() @system { return this; }
2073     }
2074     choose(true, R(), R()).save;
2075     choose(true, [0], R()).save;
2076     choose(true, R(), [0]).save;
2077 }
2078 
2079 @safe unittest // .save is @system
2080 {
2081     static struct R
2082     {
2083         int front;
2084         bool empty;
2085         void popFront() {}
2086         @property R save() @system { return this; }
2087     }
2088     static assert(!__traits(compiles, choose(true, R(), R()).save));
2089     static assert(!__traits(compiles, choose(true, [0], R()).save));
2090     static assert(!__traits(compiles, choose(true, R(), [0]).save));
2091 }
2092 
2093 //https://issues.dlang.org/show_bug.cgi?id=19738
2094 @safe nothrow pure @nogc unittest
2095 {
2096     static struct EvilRange
2097     {
2098         enum empty = true;
2099         int front;
2100         void popFront() @safe {}
2101         auto opAssign(const ref EvilRange other)
2102         {
2103             *(cast(uint*) 0xcafebabe) = 0xdeadbeef;
2104             return this;
2105         }
2106     }
2107 
2108     static assert(!__traits(compiles, () @safe
2109     {
2110         auto c1 = choose(true, EvilRange(), EvilRange());
2111         auto c2 = c1;
2112         c1 = c2;
2113     }));
2114 }
2115 
2116 
2117 // https://issues.dlang.org/show_bug.cgi?id=20495
2118 @safe unittest
2119 {
2120     static struct KillableRange
2121     {
2122         int *item;
2123         ref int front() { return *item; }
2124         bool empty() { return *item > 10; }
2125         void popFront() { ++(*item); }
2126         this(this)
2127         {
2128             assert(item is null || cast(size_t) item > 1000);
2129             item = new int(*item);
2130         }
2131         KillableRange save() { return this; }
2132     }
2133 
2134     auto kr = KillableRange(new int(1));
2135     int[] x = [1,2,3,4,5]; // length is first
2136 
2137     auto chosen = choose(true, x, kr);
2138     auto chosen2 = chosen.save;
2139 }
2140 
2141 pure @safe nothrow unittest
2142 {
2143     static struct S {
2144         int v;
2145         @disable this(this);
2146     }
2147 
2148     auto a = [S(1), S(2), S(3)];
2149     auto b = [S(4), S(5), S(6)];
2150 
2151     auto chosen = choose(true, a, b);
2152     assert(chosen.front.v == 1);
2153 
2154     auto chosen2 = choose(false, a, b);
2155     assert(chosen2.front.v == 4);
2156 }
2157 
2158 /**
2159 Choose one of multiple ranges at runtime.
2160 
2161 The ranges may be different, but they must have compatible element types. The
2162 result is a range that offers the weakest capabilities of all `Ranges`.
2163 
2164 Params:
2165     index = which range to choose, must be less than the number of ranges
2166     rs = two or more ranges
2167 
2168 Returns:
2169     The indexed range. If rs consists of only one range, the return type is an
2170     alias of that range's type.
2171  */
2172 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
2173 if (Ranges.length >= 2
2174         && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
2175         && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
2176 {
2177         return ChooseResult!Ranges(index, rs);
2178 }
2179 
2180 ///
2181 @safe nothrow pure @nogc unittest
2182 {
2183     auto test()
2184     {
2185         import std.algorithm.comparison : equal;
2186 
2187         int[4] sarr1 = [1, 2, 3, 4];
2188         int[2] sarr2 = [5, 6];
2189         int[1] sarr3 = [7];
2190         auto arr1 = sarr1[];
2191         auto arr2 = sarr2[];
2192         auto arr3 = sarr3[];
2193 
2194         {
2195             auto s = chooseAmong(0, arr1, arr2, arr3);
2196             auto t = s.save;
2197             assert(s.length == 4);
2198             assert(s[2] == 3);
2199             s.popFront();
2200             assert(equal(t, only(1, 2, 3, 4)));
2201         }
2202         {
2203             auto s = chooseAmong(1, arr1, arr2, arr3);
2204             assert(s.length == 2);
2205             s.front = 8;
2206             assert(equal(s, only(8, 6)));
2207         }
2208         {
2209             auto s = chooseAmong(1, arr1, arr2, arr3);
2210             assert(s.length == 2);
2211             s[1] = 9;
2212             assert(equal(s, only(8, 9)));
2213         }
2214         {
2215             auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
2216             assert(s.length == 2);
2217             assert(equal(s, only(2, 3)));
2218         }
2219         {
2220             auto s = chooseAmong(0, arr1, arr2, arr3);
2221             assert(s.length == 4);
2222             assert(s.back == 4);
2223             s.popBack();
2224             s.back = 5;
2225             assert(equal(s, only(1, 2, 5)));
2226             s.back = 3;
2227             assert(equal(s, only(1, 2, 3)));
2228         }
2229         {
2230             uint[5] foo = [1, 2, 3, 4, 5];
2231             uint[5] bar = [6, 7, 8, 9, 10];
2232             auto c = chooseAmong(1, foo[], bar[]);
2233             assert(c[3] == 9);
2234             c[3] = 42;
2235             assert(c[3] == 42);
2236             assert(c.moveFront() == 6);
2237             assert(c.moveBack() == 10);
2238             assert(c.moveAt(4) == 10);
2239         }
2240         {
2241             import std.range : cycle;
2242             auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
2243             assert(isInfinite!(typeof(s)));
2244             assert(!s.empty);
2245             assert(s[100] == 8);
2246             assert(s[101] == 9);
2247             assert(s[0 .. 3].equal(only(8, 9, 8)));
2248         }
2249         return 0;
2250     }
2251     // works at runtime
2252     auto a = test();
2253     // and at compile time
2254     static b = test();
2255 }
2256 
2257 @safe nothrow pure @nogc unittest
2258 {
2259     int[3] a = [1, 2, 3];
2260     long[3] b = [4, 5, 6];
2261     auto c = chooseAmong(0, a[], b[]);
2262     c[0] = 42;
2263     assert(c[0] == 42);
2264 }
2265 
2266 @safe nothrow pure @nogc unittest
2267 {
2268     static struct RefAccessRange
2269     {
2270         int[] r;
2271         ref front() @property { return r[0]; }
2272         ref back() @property { return r[$ - 1]; }
2273         void popFront() { r = r[1 .. $]; }
2274         void popBack() { r = r[0 .. $ - 1]; }
2275         auto empty() @property { return r.empty; }
2276         ref opIndex(size_t i) { return r[i]; }
2277         auto length() @property { return r.length; }
2278         alias opDollar = length;
2279         auto save() { return this; }
2280     }
2281     static assert(isRandomAccessRange!RefAccessRange);
2282     static assert(isRandomAccessRange!RefAccessRange);
2283     int[4] a = [4, 3, 2, 1];
2284     int[2] b = [6, 5];
2285     auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[]));
2286 
2287     void refFunc(ref int a, int target) { assert(a == target); }
2288 
2289     refFunc(c[2], 2);
2290     refFunc(c.front, 4);
2291     refFunc(c.back, 1);
2292 }
2293 
2294 
2295 /**
2296 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`,
2297 then `r3.front`, after which it pops off one element from each and
2298 continues again from `r1`. For example, if two ranges are involved,
2299 it alternately yields elements off the two ranges. `roundRobin`
2300 stops after it has consumed all ranges (skipping over the ones that
2301 finish early).
2302  */
2303 auto roundRobin(Rs...)(Rs rs)
2304 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
2305 {
2306     struct Result
2307     {
2308         import std.conv : to;
2309 
2310         public Rs source;
2311         private size_t _current = size_t.max;
2312 
2313         @property bool empty()
2314         {
2315             foreach (i, Unused; Rs)
2316             {
2317                 if (!source[i].empty) return false;
2318             }
2319             return true;
2320         }
2321 
2322         @property auto ref front()
2323         {
2324             final switch (_current)
2325             {
2326                 foreach (i, R; Rs)
2327                 {
2328                     case i:
2329                         assert(
2330                             !source[i].empty,
2331                             "Attempting to fetch the front of an empty roundRobin"
2332                         );
2333                         return source[i].front;
2334                 }
2335             }
2336             assert(0);
2337         }
2338 
2339         void popFront()
2340         {
2341             final switch (_current)
2342             {
2343                 foreach (i, R; Rs)
2344                 {
2345                     case i:
2346                         source[i].popFront();
2347                         break;
2348                 }
2349             }
2350 
2351             auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
2352             final switch (next)
2353             {
2354                 foreach (i, R; Rs)
2355                 {
2356                     case i:
2357                         if (!source[i].empty)
2358                         {
2359                             _current = i;
2360                             return;
2361                         }
2362                         if (i == _current)
2363                         {
2364                             _current = _current.max;
2365                             return;
2366                         }
2367                         goto case (i + 1) % Rs.length;
2368                 }
2369             }
2370         }
2371 
2372         static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
2373             @property auto save()
2374             {
2375                 auto saveSource(size_t len)()
2376                 {
2377                     import std.typecons : tuple;
2378                     static assert(len > 0);
2379                     static if (len == 1)
2380                     {
2381                         return tuple(source[0].save);
2382                     }
2383                     else
2384                     {
2385                         return saveSource!(len - 1)() ~
2386                             tuple(source[len - 1].save);
2387                     }
2388                 }
2389                 return Result(saveSource!(Rs.length).expand, _current);
2390             }
2391 
2392         static if (allSatisfy!(hasLength, Rs))
2393         {
2394             @property size_t length()
2395             {
2396                 size_t result;
2397                 foreach (i, R; Rs)
2398                 {
2399                     result += source[i].length;
2400                 }
2401                 return result;
2402             }
2403 
2404             alias opDollar = length;
2405         }
2406     }
2407 
2408     return Result(rs, 0);
2409 }
2410 
2411 ///
2412 @safe unittest
2413 {
2414     import std.algorithm.comparison : equal;
2415 
2416     int[] a = [ 1, 2, 3 ];
2417     int[] b = [ 10, 20, 30, 40 ];
2418     auto r = roundRobin(a, b);
2419     assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
2420 }
2421 
2422 /**
2423  * roundRobin can be used to create "interleave" functionality which inserts
2424  * an element between each element in a range.
2425  */
2426 @safe unittest
2427 {
2428     import std.algorithm.comparison : equal;
2429 
2430     auto interleave(R, E)(R range, E element)
2431     if ((isInputRange!R && hasLength!R) || isForwardRange!R)
2432     {
2433         static if (hasLength!R)
2434             immutable len = range.length;
2435         else
2436             immutable len = range.save.walkLength;
2437 
2438         return roundRobin(
2439             range,
2440             element.repeat(len - 1)
2441         );
2442     }
2443 
2444     assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
2445 }
2446 
2447 pure @safe unittest
2448 {
2449     import std.algorithm.comparison : equal;
2450     string f = "foo", b = "bar";
2451     auto r = roundRobin(refRange(&f), refRange(&b));
2452     assert(equal(r.save, "fboaor"));
2453     assert(equal(r.save, "fboaor"));
2454 }
2455 pure @safe nothrow unittest
2456 {
2457     import std.algorithm.comparison : equal;
2458 
2459     static struct S {
2460         int v;
2461         @disable this(this);
2462     }
2463 
2464     S[] a = [ S(1), S(2) ];
2465     S[] b = [ S(10), S(20) ];
2466     auto r = roundRobin(a, b);
2467     assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
2468 }
2469 
2470 /**
2471 Iterates a random-access range starting from a given point and
2472 progressively extending left and right from that point. If no initial
2473 point is given, iteration starts from the middle of the
2474 range. Iteration spans the entire range.
2475 
2476 When `startingIndex` is 0 the range will be fully iterated in order
2477 and in reverse order when `r.length` is given.
2478 
2479 Params:
2480     r = a random access range with length and slicing
2481     startingIndex = the index to begin iteration from
2482 
2483 Returns:
2484     A forward range with length
2485  */
2486 auto radial(Range, I)(Range r, I startingIndex)
2487 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
2488 {
2489     if (startingIndex != r.length) ++startingIndex;
2490     return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
2491 }
2492 
2493 /// Ditto
2494 auto radial(R)(R r)
2495 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
2496 {
2497     return .radial(r, (r.length - !r.empty) / 2);
2498 }
2499 
2500 ///
2501 @safe unittest
2502 {
2503     import std.algorithm.comparison : equal;
2504     int[] a = [ 1, 2, 3, 4, 5 ];
2505     assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
2506     a = [ 1, 2, 3, 4 ];
2507     assert(equal(radial(a), [ 2, 3, 1, 4 ]));
2508 
2509     // If the left end is reached first, the remaining elements on the right
2510     // are concatenated in order:
2511     a = [ 0, 1, 2, 3, 4, 5 ];
2512     assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
2513 
2514     // If the right end is reached first, the remaining elements on the left
2515     // are concatenated in reverse order:
2516     assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
2517 }
2518 
2519 @safe unittest
2520 {
2521     import std.algorithm.comparison : equal;
2522     import std.conv : text;
2523     import std.exception : enforce;
2524     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2525 
2526     void test(int[] input, int[] witness)
2527     {
2528         enforce(equal(radial(input), witness),
2529                 text(radial(input), " vs. ", witness));
2530     }
2531     test([], []);
2532     test([ 1 ], [ 1 ]);
2533     test([ 1, 2 ], [ 1, 2 ]);
2534     test([ 1, 2, 3 ], [ 2, 3, 1 ]);
2535     test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
2536     test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
2537     test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
2538 
2539     int[] a = [ 1, 2, 3, 4, 5 ];
2540     assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
2541     assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
2542     assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
2543     static assert(isForwardRange!(typeof(radial(a, 1))));
2544 
2545     auto r = radial([1,2,3,4,5]);
2546     for (auto rr = r.save; !rr.empty; rr.popFront())
2547     {
2548         assert(rr.front == moveFront(rr));
2549     }
2550     r.front = 5;
2551     assert(r.front == 5);
2552 
2553     // Test instantiation without lvalue elements.
2554     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
2555     assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
2556 
2557     // immutable int[] immi = [ 1, 2 ];
2558     // static assert(is(typeof(radial(immi))));
2559 }
2560 
2561 @safe unittest
2562 {
2563     import std.algorithm.comparison : equal;
2564 
2565     auto LL = iota(1L, 6L);
2566     auto r = radial(LL);
2567     assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
2568 }
2569 
2570 /**
2571 Lazily takes only up to `n` elements of a range. This is
2572 particularly useful when using with infinite ranges.
2573 
2574 Unlike $(LREF takeExactly), `take` does not require that there
2575 are `n` or more elements in `input`. As a consequence, length
2576 information is not applied to the result unless `input` also has
2577 length information.
2578 
2579 Params:
2580     input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2581     to iterate over up to `n` times
2582     n = the number of elements to take
2583 
2584 Returns:
2585     At minimum, an input range. If the range offers random access
2586     and `length`, `take` offers them as well.
2587  */
2588 Take!R take(R)(R input, size_t n)
2589 if (isInputRange!(Unqual!R))
2590 {
2591     alias U = Unqual!R;
2592     static if (is(R T == Take!T))
2593     {
2594         import std.algorithm.comparison : min;
2595         return R(input.source, min(n, input._maxAvailable));
2596     }
2597     else static if (!isInfinite!U && hasSlicing!U)
2598     {
2599         import std.algorithm.comparison : min;
2600         return input[0 .. min(n, input.length)];
2601     }
2602     else
2603     {
2604         return Take!R(input, n);
2605     }
2606 }
2607 
2608 /// ditto
2609 struct Take(Range)
2610 if (isInputRange!(Unqual!Range) &&
2611     //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
2612     //take for slicing infinite ranges.
2613     !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
2614 {
2615     private alias R = Unqual!Range;
2616 
2617     /// User accessible in read and write
2618     public R source;
2619 
2620     private size_t _maxAvailable;
2621 
2622     alias Source = R;
2623 
2624     /// Range primitives
2625     @property bool empty()
2626     {
2627         return _maxAvailable == 0 || source.empty;
2628     }
2629 
2630     /// ditto
2631     @property auto ref front()
2632     {
2633         assert(!empty,
2634             "Attempting to fetch the front of an empty "
2635             ~ Take.stringof);
2636         return source.front;
2637     }
2638 
2639     /// ditto
2640     void popFront()
2641     {
2642         assert(!empty,
2643             "Attempting to popFront() past the end of a "
2644             ~ Take.stringof);
2645         source.popFront();
2646         --_maxAvailable;
2647     }
2648 
2649     static if (isForwardRange!R)
2650         /// ditto
2651         @property Take save()
2652         {
2653             return Take(source.save, _maxAvailable);
2654         }
2655 
2656     static if (hasAssignableElements!R)
2657         /// ditto
2658         @property void front(ElementType!R v)
2659         {
2660             import std.algorithm.mutation : move;
2661 
2662             assert(!empty,
2663                 "Attempting to assign to the front of an empty "
2664                 ~ Take.stringof);
2665             source.front = move(v);
2666         }
2667 
2668     static if (hasMobileElements!R)
2669     {
2670         /// ditto
2671         auto moveFront()
2672         {
2673             assert(!empty,
2674                 "Attempting to move the front of an empty "
2675                 ~ Take.stringof);
2676             return source.moveFront();
2677         }
2678     }
2679 
2680     static if (isInfinite!R)
2681     {
2682         /// ditto
2683         @property size_t length() const
2684         {
2685             return _maxAvailable;
2686         }
2687 
2688         /// ditto
2689         alias opDollar = length;
2690 
2691         //Note: Due to Take/hasSlicing circular dependency,
2692         //This needs to be a restrained template.
2693         /// ditto
2694         auto opSlice()(size_t i, size_t j)
2695         if (hasSlicing!R)
2696         {
2697             assert(i <= j, "Invalid slice bounds");
2698             assert(j <= length, "Attempting to slice past the end of a "
2699                 ~ Take.stringof);
2700             return source[i .. j];
2701         }
2702     }
2703     else static if (hasLength!R)
2704     {
2705         /// ditto
2706         @property size_t length()
2707         {
2708             import std.algorithm.comparison : min;
2709             return min(_maxAvailable, source.length);
2710         }
2711 
2712         alias opDollar = length;
2713     }
2714 
2715     static if (isRandomAccessRange!R)
2716     {
2717         /// ditto
2718         void popBack()
2719         {
2720             assert(!empty,
2721                 "Attempting to popBack() past the beginning of a "
2722                 ~ Take.stringof);
2723             --_maxAvailable;
2724         }
2725 
2726         /// ditto
2727         @property auto ref back()
2728         {
2729             assert(!empty,
2730                 "Attempting to fetch the back of an empty "
2731                 ~ Take.stringof);
2732             return source[this.length - 1];
2733         }
2734 
2735         /// ditto
2736         auto ref opIndex(size_t index)
2737         {
2738             assert(index < length,
2739                 "Attempting to index out of the bounds of a "
2740                 ~ Take.stringof);
2741             return source[index];
2742         }
2743 
2744         static if (hasAssignableElements!R)
2745         {
2746             /// ditto
2747             @property void back(ElementType!R v)
2748             {
2749                 // This has to return auto instead of void because of
2750                 // https://issues.dlang.org/show_bug.cgi?id=4706
2751                 assert(!empty,
2752                     "Attempting to assign to the back of an empty "
2753                     ~ Take.stringof);
2754                 source[this.length - 1] = v;
2755             }
2756 
2757             /// ditto
2758             void opIndexAssign(ElementType!R v, size_t index)
2759             {
2760                 assert(index < length,
2761                     "Attempting to index out of the bounds of a "
2762                     ~ Take.stringof);
2763                 source[index] = v;
2764             }
2765         }
2766 
2767         static if (hasMobileElements!R)
2768         {
2769             /// ditto
2770             auto moveBack()
2771             {
2772                 assert(!empty,
2773                     "Attempting to move the back of an empty "
2774                     ~ Take.stringof);
2775                 return source.moveAt(this.length - 1);
2776             }
2777 
2778             /// ditto
2779             auto moveAt(size_t index)
2780             {
2781                 assert(index < length,
2782                     "Attempting to index out of the bounds of a "
2783                     ~ Take.stringof);
2784                 return source.moveAt(index);
2785             }
2786         }
2787     }
2788 
2789     /**
2790     Access to maximal length of the range.
2791     Note: the actual length of the range depends on the underlying range.
2792     If it has fewer elements, it will stop before maxLength is reached.
2793     */
2794     @property size_t maxLength() const
2795     {
2796         return _maxAvailable;
2797     }
2798 }
2799 
2800 /// ditto
2801 template Take(R)
2802 if (isInputRange!(Unqual!R) &&
2803     ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2804 {
2805     alias Take = R;
2806 }
2807 
2808 ///
2809 pure @safe nothrow unittest
2810 {
2811     import std.algorithm.comparison : equal;
2812 
2813     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2814     auto s = take(arr1, 5);
2815     assert(s.length == 5);
2816     assert(s[4] == 5);
2817     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2818 }
2819 
2820 /**
2821  * If the range runs out before `n` elements, `take` simply returns the entire
2822  * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2823  * the range ends prematurely):
2824  */
2825 pure @safe nothrow unittest
2826 {
2827     import std.algorithm.comparison : equal;
2828 
2829     int[] arr2 = [ 1, 2, 3 ];
2830     auto t = take(arr2, 5);
2831     assert(t.length == 3);
2832     assert(equal(t, [ 1, 2, 3 ]));
2833 }
2834 
2835 pure @safe nothrow unittest
2836 {
2837     import std.algorithm.comparison : equal;
2838     import std.internal.test.dummyrange : AllDummyRanges;
2839 
2840     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2841     auto s = take(arr1, 5);
2842     assert(s.length == 5);
2843     assert(s[4] == 5);
2844     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2845     assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2846 
2847     // Test fix for bug 4464.
2848     static assert(is(typeof(s) == Take!(int[])));
2849     static assert(is(typeof(s) == int[]));
2850 
2851     // Test using narrow strings.
2852     import std.exception : assumeWontThrow;
2853 
2854     auto myStr = "This is a string.";
2855     auto takeMyStr = take(myStr, 7);
2856     assert(assumeWontThrow(equal(takeMyStr, "This is")));
2857     // Test fix for bug 5052.
2858     auto takeMyStrAgain = take(takeMyStr, 4);
2859     assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2860     static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
2861     takeMyStrAgain = take(takeMyStr, 10);
2862     assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
2863 
2864     foreach (DummyType; AllDummyRanges)
2865     {
2866         DummyType dummy;
2867         auto t = take(dummy, 5);
2868         alias T = typeof(t);
2869 
2870         static if (isRandomAccessRange!DummyType)
2871         {
2872             static assert(isRandomAccessRange!T);
2873             assert(t[4] == 5);
2874 
2875             assert(moveAt(t, 1) == t[1]);
2876             assert(t.back == moveBack(t));
2877         }
2878         else static if (isForwardRange!DummyType)
2879         {
2880             static assert(isForwardRange!T);
2881         }
2882 
2883         for (auto tt = t; !tt.empty; tt.popFront())
2884         {
2885             assert(tt.front == moveFront(tt));
2886         }
2887 
2888         // Bidirectional ranges can't be propagated properly if they don't
2889         // also have random access.
2890 
2891         assert(equal(t, [1,2,3,4,5]));
2892 
2893         //Test that take doesn't wrap the result of take.
2894         assert(take(t, 4) == take(dummy, 4));
2895     }
2896 
2897     immutable myRepeat = repeat(1);
2898     static assert(is(Take!(typeof(myRepeat))));
2899 }
2900 
2901 pure @safe nothrow @nogc unittest
2902 {
2903     //check for correct slicing of Take on an infinite range
2904     import std.algorithm.comparison : equal;
2905     foreach (start; 0 .. 4)
2906         foreach (stop; start .. 4)
2907             assert(iota(4).cycle.take(4)[start .. stop]
2908                 .equal(iota(start, stop)));
2909 }
2910 
2911 pure @safe nothrow @nogc unittest
2912 {
2913     // Check that one can declare variables of all Take types,
2914     // and that they match the return type of the corresponding
2915     // take().
2916     // See https://issues.dlang.org/show_bug.cgi?id=4464
2917     int[] r1;
2918     Take!(int[]) t1;
2919     t1 = take(r1, 1);
2920     assert(t1.empty);
2921 
2922     string r2;
2923     Take!string t2;
2924     t2 = take(r2, 1);
2925     assert(t2.empty);
2926 
2927     Take!(Take!string) t3;
2928     t3 = take(t2, 1);
2929     assert(t3.empty);
2930 }
2931 
2932 pure @safe nothrow @nogc unittest
2933 {
2934     alias R1 = typeof(repeat(1));
2935     alias R2 = typeof(cycle([1]));
2936     alias TR1 = Take!R1;
2937     alias TR2 = Take!R2;
2938     static assert(isBidirectionalRange!TR1);
2939     static assert(isBidirectionalRange!TR2);
2940 }
2941 
2942 // https://issues.dlang.org/show_bug.cgi?id=12731
2943 pure @safe nothrow @nogc unittest
2944 {
2945     auto a = repeat(1);
2946     auto s = a[1 .. 5];
2947     s = s[1 .. 3];
2948     assert(s.length == 2);
2949     assert(s[0] == 1);
2950     assert(s[1] == 1);
2951 }
2952 
2953 // https://issues.dlang.org/show_bug.cgi?id=13151
2954 pure @safe nothrow @nogc unittest
2955 {
2956     import std.algorithm.comparison : equal;
2957 
2958     auto r = take(repeat(1, 4), 3);
2959     assert(r.take(2).equal(repeat(1, 2)));
2960 }
2961 
2962 
2963 /**
2964 Similar to $(LREF take), but assumes that `range` has at least $(D
2965 n) elements. Consequently, the result of $(D takeExactly(range, n))
2966 always defines the `length` property (and initializes it to `n`)
2967 even when `range` itself does not define `length`.
2968 
2969 The result of `takeExactly` is identical to that of $(LREF take) in
2970 cases where the original range defines `length` or is infinite.
2971 
2972 Unlike $(LREF take), however, it is illegal to pass a range with less than
2973 `n` elements to `takeExactly`; this will cause an assertion failure.
2974  */
2975 auto takeExactly(R)(R range, size_t n)
2976 if (isInputRange!R)
2977 {
2978     static if (is(typeof(takeExactly(range._input, n)) == R))
2979     {
2980         assert(n <= range._n,
2981                "Attempted to take more than the length of the range with takeExactly.");
2982         // takeExactly(takeExactly(r, n1), n2) has the same type as
2983         // takeExactly(r, n1) and simply returns takeExactly(r, n2)
2984         range._n = n;
2985         return range;
2986     }
2987     //Also covers hasSlicing!R for finite ranges.
2988     else static if (hasLength!R)
2989     {
2990         assert(n <= range.length,
2991                "Attempted to take more than the length of the range with takeExactly.");
2992         return take(range, n);
2993     }
2994     else static if (isInfinite!R)
2995         return Take!R(range, n);
2996     else
2997     {
2998         static struct Result
2999         {
3000             R _input;
3001             private size_t _n;
3002 
3003             @property bool empty() const { return !_n; }
3004             @property auto ref front()
3005             {
3006                 assert(_n > 0, "front() on an empty " ~ Result.stringof);
3007                 return _input.front;
3008             }
3009             void popFront() { _input.popFront(); --_n; }
3010             @property size_t length() const { return _n; }
3011             alias opDollar = length;
3012 
3013             @property auto _takeExactly_Result_asTake()
3014             {
3015                 return take(_input, _n);
3016             }
3017 
3018             alias _takeExactly_Result_asTake this;
3019 
3020             static if (isForwardRange!R)
3021                 @property auto save()
3022                 {
3023                     return Result(_input.save, _n);
3024                 }
3025 
3026             static if (hasMobileElements!R)
3027             {
3028                 auto moveFront()
3029                 {
3030                     assert(!empty,
3031                         "Attempting to move the front of an empty "
3032                         ~ typeof(this).stringof);
3033                     return _input.moveFront();
3034                 }
3035             }
3036 
3037             static if (hasAssignableElements!R)
3038             {
3039                 @property auto ref front(ElementType!R v)
3040                 {
3041                     import std.algorithm.mutation : move;
3042 
3043                     assert(!empty,
3044                         "Attempting to assign to the front of an empty "
3045                         ~ typeof(this).stringof);
3046                     return _input.front = move(v);
3047                 }
3048             }
3049         }
3050 
3051         return Result(range, n);
3052     }
3053 }
3054 
3055 ///
3056 pure @safe nothrow unittest
3057 {
3058     import std.algorithm.comparison : equal;
3059 
3060     auto a = [ 1, 2, 3, 4, 5 ];
3061 
3062     auto b = takeExactly(a, 3);
3063     assert(equal(b, [1, 2, 3]));
3064     static assert(is(typeof(b.length) == size_t));
3065     assert(b.length == 3);
3066     assert(b.front == 1);
3067     assert(b.back == 3);
3068 }
3069 
3070 pure @safe nothrow unittest
3071 {
3072     import std.algorithm.comparison : equal;
3073     import std.algorithm.iteration : filter;
3074 
3075     auto a = [ 1, 2, 3, 4, 5 ];
3076     auto b = takeExactly(a, 3);
3077     assert(equal(b, [1, 2, 3]));
3078     auto c = takeExactly(b, 2);
3079     assert(equal(c, [1, 2]));
3080 
3081 
3082 
3083     auto d = filter!"a > 2"(a);
3084     auto e = takeExactly(d, 3);
3085     assert(equal(e, [3, 4, 5]));
3086     static assert(is(typeof(e.length) == size_t));
3087     assert(e.length == 3);
3088     assert(e.front == 3);
3089 
3090     assert(equal(takeExactly(e, 3), [3, 4, 5]));
3091 }
3092 
3093 pure @safe nothrow unittest
3094 {
3095     import std.algorithm.comparison : equal;
3096     import std.internal.test.dummyrange : AllDummyRanges;
3097 
3098     auto a = [ 1, 2, 3, 4, 5 ];
3099     //Test that take and takeExactly are the same for ranges which define length
3100     //but aren't sliceable.
3101     struct L
3102     {
3103         @property auto front() { return _arr[0]; }
3104         @property bool empty() { return _arr.empty; }
3105         void popFront() { _arr.popFront(); }
3106         @property size_t length() { return _arr.length; }
3107         int[] _arr;
3108     }
3109     static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
3110     assert(take(L(a), 3) == takeExactly(L(a), 3));
3111 
3112     //Test that take and takeExactly are the same for ranges which are sliceable.
3113     static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
3114     assert(take(a, 3) == takeExactly(a, 3));
3115 
3116     //Test that take and takeExactly are the same for infinite ranges.
3117     auto inf = repeat(1);
3118     static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
3119     assert(take(inf, 5) == takeExactly(inf, 5));
3120 
3121     //Test that take and takeExactly are _not_ the same for ranges which don't
3122     //define length.
3123     static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
3124 
3125     foreach (DummyType; AllDummyRanges)
3126     {
3127         {
3128             DummyType dummy;
3129             auto t = takeExactly(dummy, 5);
3130 
3131             //Test that takeExactly doesn't wrap the result of takeExactly.
3132             assert(takeExactly(t, 4) == takeExactly(dummy, 4));
3133         }
3134 
3135         static if (hasMobileElements!DummyType)
3136         {
3137             {
3138                 auto t = takeExactly(DummyType.init, 4);
3139                 assert(t.moveFront() == 1);
3140                 assert(equal(t, [1, 2, 3, 4]));
3141             }
3142         }
3143 
3144         static if (hasAssignableElements!DummyType)
3145         {
3146             {
3147                 auto t = takeExactly(DummyType.init, 4);
3148                 t.front = 9;
3149                 assert(equal(t, [9, 2, 3, 4]));
3150             }
3151         }
3152     }
3153 }
3154 
3155 pure @safe nothrow unittest
3156 {
3157     import std.algorithm.comparison : equal;
3158     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
3159 
3160     alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
3161     auto te = takeExactly(DummyType(), 5);
3162     Take!DummyType t = te;
3163     assert(equal(t, [1, 2, 3, 4, 5]));
3164     assert(equal(t, te));
3165 }
3166 
3167 // https://issues.dlang.org/show_bug.cgi?id=18092
3168 // can't combine take and takeExactly
3169 @safe unittest
3170 {
3171     import std.algorithm.comparison : equal;
3172     import std.internal.test.dummyrange : AllDummyRanges;
3173 
3174     static foreach (Range; AllDummyRanges)
3175     {{
3176         Range r;
3177         assert(r.take(6).takeExactly(2).equal([1, 2]));
3178         assert(r.takeExactly(6).takeExactly(2).equal([1, 2]));
3179         assert(r.takeExactly(6).take(2).equal([1, 2]));
3180     }}
3181 }
3182 
3183 /**
3184 Returns a range with at most one element; for example, $(D
3185 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
3186 42). Calling `popFront()` off that range renders it empty.
3187 
3188 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in
3189 certain interfaces it is important to know statically that the range may only
3190 have at most one element.
3191 
3192 The type returned by `takeOne` is a random-access range with length
3193 regardless of `R`'s capabilities, as long as it is a forward range.
3194 (another feature that distinguishes `takeOne` from `take`). If
3195 (D R) is an input range but not a forward range, return type is an input
3196 range with all random-access capabilities except save.
3197  */
3198 auto takeOne(R)(R source)
3199 if (isInputRange!R)
3200 {
3201     static if (hasSlicing!R)
3202     {
3203         return source[0 .. !source.empty];
3204     }
3205     else
3206     {
3207         static struct Result
3208         {
3209             private R _source;
3210             private bool _empty = true;
3211             @property bool empty() const { return _empty; }
3212             @property auto ref front()
3213             {
3214                 assert(!empty, "Attempting to fetch the front of an empty takeOne");
3215                 return _source.front;
3216             }
3217             void popFront()
3218             {
3219                 assert(!empty, "Attempting to popFront an empty takeOne");
3220                 _source.popFront();
3221                 _empty = true;
3222             }
3223             void popBack()
3224             {
3225                 assert(!empty, "Attempting to popBack an empty takeOne");
3226                 _source.popFront();
3227                 _empty = true;
3228             }
3229             static if (isForwardRange!(Unqual!R))
3230             {
3231                 @property auto save() { return Result(_source.save, empty); }
3232             }
3233             @property auto ref back()
3234             {
3235                 assert(!empty, "Attempting to fetch the back of an empty takeOne");
3236                 return _source.front;
3237             }
3238             @property size_t length() const { return !empty; }
3239             alias opDollar = length;
3240             auto ref opIndex(size_t n)
3241             {
3242                 assert(n < length, "Attempting to index a takeOne out of bounds");
3243                 return _source.front;
3244             }
3245             auto opSlice(size_t m, size_t n)
3246             {
3247                 assert(
3248                     m <= n,
3249                     "Attempting to slice a takeOne range with a larger first argument than the second."
3250                 );
3251                 assert(
3252                     n <= length,
3253                     "Attempting to slice using an out of bounds index on a takeOne range."
3254                     );
3255                 return n > m ? this : Result(_source, true);
3256             }
3257             // Non-standard property
3258             @property R source() { return _source; }
3259         }
3260 
3261         return Result(source, source.empty);
3262     }
3263 }
3264 
3265 ///
3266 pure @safe nothrow unittest
3267 {
3268     auto s = takeOne([42, 43, 44]);
3269     static assert(isRandomAccessRange!(typeof(s)));
3270     assert(s.length == 1);
3271     assert(!s.empty);
3272     assert(s.front == 42);
3273     s.front = 43;
3274     assert(s.front == 43);
3275     assert(s.back == 43);
3276     assert(s[0] == 43);
3277     s.popFront();
3278     assert(s.length == 0);
3279     assert(s.empty);
3280 }
3281 
3282 pure @safe nothrow @nogc unittest
3283 {
3284     struct NonForwardRange
3285     {
3286         enum empty = false;
3287         int front() { return 42; }
3288         void popFront() {}
3289     }
3290 
3291     static assert(!isForwardRange!NonForwardRange);
3292 
3293     auto s = takeOne(NonForwardRange());
3294     assert(s.length == 1);
3295     assert(!s.empty);
3296     assert(s.front == 42);
3297     assert(s.back == 42);
3298     assert(s[0] == 42);
3299 
3300     auto t = s[0 .. 0];
3301     assert(t.empty);
3302     assert(t.length == 0);
3303 
3304     auto u = s[1 .. 1];
3305     assert(u.empty);
3306     assert(u.length == 0);
3307 
3308     auto v = s[0 .. 1];
3309     s.popFront();
3310     assert(s.length == 0);
3311     assert(s.empty);
3312     assert(!v.empty);
3313     assert(v.front == 42);
3314     v.popBack();
3315     assert(v.empty);
3316     assert(v.length == 0);
3317 }
3318 
3319 pure @safe nothrow @nogc unittest
3320 {
3321     struct NonSlicingForwardRange
3322     {
3323         enum empty = false;
3324         int front() { return 42; }
3325         void popFront() {}
3326         @property auto save() { return this; }
3327     }
3328 
3329     static assert(isForwardRange!NonSlicingForwardRange);
3330     static assert(!hasSlicing!NonSlicingForwardRange);
3331 
3332     auto s = takeOne(NonSlicingForwardRange());
3333     assert(s.length == 1);
3334     assert(!s.empty);
3335     assert(s.front == 42);
3336     assert(s.back == 42);
3337     assert(s[0] == 42);
3338     auto t = s.save;
3339     s.popFront();
3340     assert(s.length == 0);
3341     assert(s.empty);
3342     assert(!t.empty);
3343     assert(t.front == 42);
3344     t.popBack();
3345     assert(t.empty);
3346     assert(t.length == 0);
3347 }
3348 
3349 // Test that asserts trigger correctly
3350 @system unittest
3351 {
3352     import std.exception : assertThrown;
3353     import core.exception : AssertError;
3354 
3355     struct NonForwardRange
3356     {
3357         enum empty = false;
3358         int front() { return 42; }
3359         void popFront() {}
3360     }
3361 
3362     auto s = takeOne(NonForwardRange());
3363 
3364     assertThrown!AssertError(s[1]);
3365     assertThrown!AssertError(s[0 .. 2]);
3366 
3367     size_t one = 1;     // Avoid style warnings triggered by literals
3368     size_t zero = 0;
3369     assertThrown!AssertError(s[one .. zero]);
3370 
3371     s.popFront;
3372     assert(s.empty);
3373     assertThrown!AssertError(s.front);
3374     assertThrown!AssertError(s.back);
3375     assertThrown!AssertError(s.popFront);
3376     assertThrown!AssertError(s.popBack);
3377 }
3378 
3379 // https://issues.dlang.org/show_bug.cgi?id=16999
3380 pure @safe unittest
3381 {
3382     auto myIota = new class
3383     {
3384         int front = 0;
3385         @safe void popFront(){front++;}
3386         enum empty = false;
3387     };
3388     auto iotaPart = myIota.takeOne;
3389     int sum;
3390     foreach (var; chain(iotaPart, iotaPart, iotaPart))
3391     {
3392         sum += var;
3393     }
3394     assert(sum == 3);
3395     assert(iotaPart.front == 3);
3396 }
3397 
3398 /++
3399     Returns an empty range which is statically known to be empty and is
3400     guaranteed to have `length` and be random access regardless of `R`'s
3401     capabilities.
3402   +/
3403 auto takeNone(R)()
3404 if (isInputRange!R)
3405 {
3406     return typeof(takeOne(R.init)).init;
3407 }
3408 
3409 ///
3410 pure @safe nothrow @nogc unittest
3411 {
3412     auto range = takeNone!(int[])();
3413     assert(range.length == 0);
3414     assert(range.empty);
3415 }
3416 
3417 pure @safe nothrow @nogc unittest
3418 {
3419     enum ctfe = takeNone!(int[])();
3420     static assert(ctfe.length == 0);
3421     static assert(ctfe.empty);
3422 }
3423 
3424 
3425 /++
3426     Creates an empty range from the given range in $(BIGOH 1). If it can, it
3427     will return the same range type. If not, it will return
3428     $(D takeExactly(range, 0)).
3429   +/
3430 auto takeNone(R)(R range)
3431 if (isInputRange!R)
3432 {
3433     import std.traits : isDynamicArray;
3434     //Makes it so that calls to takeNone which don't use UFCS still work with a
3435     //member version if it's defined.
3436     static if (is(typeof(R.takeNone)))
3437         auto retval = range.takeNone();
3438     // https://issues.dlang.org/show_bug.cgi?id=8339
3439     else static if (isDynamicArray!R)/+ ||
3440                    (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
3441     {
3442         auto retval = R.init;
3443     }
3444     //An infinite range sliced at [0 .. 0] would likely still not be empty...
3445     else static if (hasSlicing!R && !isInfinite!R)
3446         auto retval = range[0 .. 0];
3447     else
3448         auto retval = takeExactly(range, 0);
3449 
3450     // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being
3451     // done in an out block.
3452     assert(retval.empty);
3453     return retval;
3454 }
3455 
3456 ///
3457 pure @safe nothrow unittest
3458 {
3459     import std.algorithm.iteration : filter;
3460     assert(takeNone([42, 27, 19]).empty);
3461     assert(takeNone("dlang.org").empty);
3462     assert(takeNone(filter!"true"([42, 27, 19])).empty);
3463 }
3464 
3465 @safe unittest
3466 {
3467     import std.algorithm.iteration : filter;
3468     import std.meta : AliasSeq;
3469 
3470     struct Dummy
3471     {
3472         mixin template genInput()
3473         {
3474         @safe:
3475             @property bool empty() { return _arr.empty; }
3476             @property auto front() { return _arr.front; }
3477             void popFront() { _arr.popFront(); }
3478             static assert(isInputRange!(typeof(this)));
3479         }
3480     }
3481     alias genInput = Dummy.genInput;
3482 
3483     static struct NormalStruct
3484     {
3485         //Disabled to make sure that the takeExactly version is used.
3486         @disable this();
3487         this(int[] arr) { _arr = arr; }
3488         mixin genInput;
3489         int[] _arr;
3490     }
3491 
3492     static struct SliceStruct
3493     {
3494         @disable this();
3495         this(int[] arr) { _arr = arr; }
3496         mixin genInput;
3497         @property auto save() { return this; }
3498         auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
3499         @property size_t length() { return _arr.length; }
3500         int[] _arr;
3501     }
3502 
3503     static struct InitStruct
3504     {
3505         mixin genInput;
3506         int[] _arr;
3507     }
3508 
3509     static struct TakeNoneStruct
3510     {
3511         this(int[] arr) { _arr = arr; }
3512         @disable this();
3513         mixin genInput;
3514         auto takeNone() { return typeof(this)(null); }
3515         int[] _arr;
3516     }
3517 
3518     static class NormalClass
3519     {
3520         this(int[] arr) {_arr = arr;}
3521         mixin genInput;
3522         int[] _arr;
3523     }
3524 
3525     static class SliceClass
3526     {
3527     @safe:
3528         this(int[] arr) { _arr = arr; }
3529         mixin genInput;
3530         @property auto save() { return new typeof(this)(_arr); }
3531         auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
3532         @property size_t length() { return _arr.length; }
3533         int[] _arr;
3534     }
3535 
3536     static class TakeNoneClass
3537     {
3538     @safe:
3539         this(int[] arr) { _arr = arr; }
3540         mixin genInput;
3541         auto takeNone() { return new typeof(this)(null); }
3542         int[] _arr;
3543     }
3544 
3545     import std.format : format;
3546 
3547     static foreach (range; AliasSeq!([1, 2, 3, 4, 5],
3548                              "hello world",
3549                              "hello world"w,
3550                              "hello world"d,
3551                              SliceStruct([1, 2, 3]),
3552                              // https://issues.dlang.org/show_bug.cgi?id=8339
3553                              // forces this to be takeExactly `InitStruct([1, 2, 3]),
3554                              TakeNoneStruct([1, 2, 3])))
3555     {
3556         static assert(takeNone(range).empty, typeof(range).stringof);
3557         assert(takeNone(range).empty);
3558         static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
3559     }
3560 
3561     static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
3562                              InitStruct([1, 2, 3])))
3563     {
3564         static assert(takeNone(range).empty, typeof(range).stringof);
3565         assert(takeNone(range).empty);
3566         static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
3567     }
3568 
3569     //Don't work in CTFE.
3570     auto normal = new NormalClass([1, 2, 3]);
3571     assert(takeNone(normal).empty);
3572     static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
3573 
3574     auto slice = new SliceClass([1, 2, 3]);
3575     assert(takeNone(slice).empty);
3576     static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
3577 
3578     auto taken = new TakeNoneClass([1, 2, 3]);
3579     assert(takeNone(taken).empty);
3580     static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
3581 
3582     auto filtered = filter!"true"([1, 2, 3, 4, 5]);
3583     assert(takeNone(filtered).empty);
3584     // https://issues.dlang.org/show_bug.cgi?id=8339 and
3585     // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly
3586     //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
3587 }
3588 
3589 /++
3590  + Return a range advanced to within `_n` elements of the end of
3591  + `range`.
3592  +
3593  + Intended as the range equivalent of the Unix
3594  + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
3595  + of `range` is less than or equal to `_n`, `range` is returned
3596  + as-is.
3597  +
3598  + Completes in $(BIGOH 1) steps for ranges that support slicing and have
3599  + length. Completes in $(BIGOH range.length) time for all other ranges.
3600  +
3601  + Params:
3602  +    range = range to get _tail of
3603  +    n = maximum number of elements to include in _tail
3604  +
3605  + Returns:
3606  +    Returns the _tail of `range` augmented with length information
3607  +/
3608 auto tail(Range)(Range range, size_t n)
3609 if (isInputRange!Range && !isInfinite!Range &&
3610     (hasLength!Range || isForwardRange!Range))
3611 {
3612     static if (hasLength!Range)
3613     {
3614         immutable length = range.length;
3615         if (n >= length)
3616             return range.takeExactly(length);
3617         else
3618             return range.drop(length - n).takeExactly(n);
3619     }
3620     else
3621     {
3622         Range scout = range.save;
3623         foreach (immutable i; 0 .. n)
3624         {
3625             if (scout.empty)
3626                 return range.takeExactly(i);
3627             scout.popFront();
3628         }
3629 
3630         auto tail = range.save;
3631         while (!scout.empty)
3632         {
3633             assert(!tail.empty);
3634             scout.popFront();
3635             tail.popFront();
3636         }
3637 
3638         return tail.takeExactly(n);
3639     }
3640 }
3641 
3642 ///
3643 pure @safe nothrow unittest
3644 {
3645     // tail -c n
3646     assert([1, 2, 3].tail(1) == [3]);
3647     assert([1, 2, 3].tail(2) == [2, 3]);
3648     assert([1, 2, 3].tail(3) == [1, 2, 3]);
3649     assert([1, 2, 3].tail(4) == [1, 2, 3]);
3650     assert([1, 2, 3].tail(0).length == 0);
3651 
3652     // tail --lines=n
3653     import std.algorithm.comparison : equal;
3654     import std.algorithm.iteration : joiner;
3655     import std.exception : assumeWontThrow;
3656     import std.string : lineSplitter;
3657     assert("one\ntwo\nthree"
3658         .lineSplitter
3659         .tail(2)
3660         .joiner("\n")
3661         .equal("two\nthree")
3662         .assumeWontThrow);
3663 }
3664 
3665 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408
3666 pure nothrow @safe /+@nogc+/ unittest
3667 {
3668     import std.algorithm.comparison : equal;
3669     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
3670         RangeType, ReturnBy;
3671 
3672     static immutable cheatsheet = [6, 7, 8, 9, 10];
3673 
3674     foreach (R; AllDummyRanges)
3675     {
3676         static if (isInputRange!R && !isInfinite!R &&
3677                    (hasLength!R || isForwardRange!R))
3678         {
3679             assert(R.init.tail(5).equal(cheatsheet));
3680             static assert(R.init.tail(5).equal(cheatsheet));
3681 
3682             assert(R.init.tail(0).length == 0);
3683             assert(R.init.tail(10).equal(R.init));
3684             assert(R.init.tail(11).equal(R.init));
3685         }
3686     }
3687 
3688     // Infinite ranges are not supported
3689     static assert(!__traits(compiles, repeat(0).tail(0)));
3690 
3691     // Neither are non-forward ranges without length
3692     static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
3693         RangeType.Input).init.tail(5)));
3694 }
3695 
3696 pure @safe nothrow @nogc unittest
3697 {
3698     static immutable input = [1, 2, 3];
3699     static immutable expectedOutput = [2, 3];
3700     assert(input.tail(2) == expectedOutput);
3701 }
3702 
3703 /++
3704     Convenience function which calls
3705     $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`.
3706     `drop` makes it easier to pop elements from a range
3707     and then pass it to another function within a single expression,
3708     whereas `popFrontN` would require multiple statements.
3709 
3710     `dropBack` provides the same functionality but instead calls
3711     $(REF popBackN, std, range, primitives)`(range, n)`
3712 
3713     Note: `drop` and `dropBack` will only pop $(I up to)
3714     `n` elements but will stop if the range is empty first.
3715     In other languages this is sometimes called `skip`.
3716 
3717     Params:
3718         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3719         n = the number of elements to drop
3720 
3721     Returns:
3722         `range` with up to `n` elements dropped
3723 
3724     See_Also:
3725         $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives)
3726   +/
3727 R drop(R)(R range, size_t n)
3728 if (isInputRange!R)
3729 {
3730     range.popFrontN(n);
3731     return range;
3732 }
3733 
3734 ///
3735 @safe unittest
3736 {
3737     import std.algorithm.comparison : equal;
3738 
3739     assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
3740     assert("hello world".drop(6) == "world");
3741     assert("hello world".drop(50).empty);
3742     assert("hello world".take(6).drop(3).equal("lo "));
3743 }
3744 
3745 /// ditto
3746 R dropBack(R)(R range, size_t n)
3747 if (isBidirectionalRange!R)
3748 {
3749     range.popBackN(n);
3750     return range;
3751 }
3752 
3753 ///
3754 @safe unittest
3755 {
3756     import std.algorithm.comparison : equal;
3757 
3758     assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
3759     assert("hello world".dropBack(6) == "hello");
3760     assert("hello world".dropBack(50).empty);
3761     assert("hello world".drop(4).dropBack(4).equal("o w"));
3762 }
3763 
3764 @safe unittest
3765 {
3766     import std.algorithm.comparison : equal;
3767     import std.container.dlist : DList;
3768 
3769     //Remove all but the first two elements
3770     auto a = DList!int(0, 1, 9, 9, 9, 9);
3771     a.remove(a[].drop(2));
3772     assert(a[].equal(a[].take(2)));
3773 }
3774 
3775 @safe unittest
3776 {
3777     import std.algorithm.comparison : equal;
3778     import std.algorithm.iteration : filter;
3779 
3780     assert(drop("", 5).empty);
3781     assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3782 }
3783 
3784 @safe unittest
3785 {
3786     import std.algorithm.comparison : equal;
3787     import std.container.dlist : DList;
3788 
3789     //insert before the last two elements
3790     auto a = DList!int(0, 1, 2, 5, 6);
3791     a.insertAfter(a[].dropBack(2), [3, 4]);
3792     assert(a[].equal(iota(0, 7)));
3793 }
3794 
3795 /++
3796     Similar to $(LREF drop) and `dropBack` but they call
3797     $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)`
3798     instead.
3799 
3800     Note: Unlike `drop`, `dropExactly` will assume that the
3801     range holds at least `n` elements. This makes `dropExactly`
3802     faster than `drop`, but it also means that if `range` does
3803     not contain at least `n` elements, it will attempt to call `popFront`
3804     on an empty range, which is undefined behavior. So, only use
3805     `popFrontExactly` when it is guaranteed that `range` holds at least
3806     `n` elements.
3807 
3808     Params:
3809         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3810         n = the number of elements to drop
3811 
3812     Returns:
3813         `range` with `n` elements dropped
3814 
3815     See_Also:
3816         $(REF popFrontExcatly, std, range, primitives),
3817         $(REF popBackExcatly, std, range, primitives)
3818 +/
3819 R dropExactly(R)(R range, size_t n)
3820 if (isInputRange!R)
3821 {
3822     popFrontExactly(range, n);
3823     return range;
3824 }
3825 /// ditto
3826 R dropBackExactly(R)(R range, size_t n)
3827 if (isBidirectionalRange!R)
3828 {
3829     popBackExactly(range, n);
3830     return range;
3831 }
3832 
3833 ///
3834 @safe unittest
3835 {
3836     import std.algorithm.comparison : equal;
3837     import std.algorithm.iteration : filterBidirectional;
3838 
3839     auto a = [1, 2, 3];
3840     assert(a.dropExactly(2) == [3]);
3841     assert(a.dropBackExactly(2) == [1]);
3842 
3843     string s = "日本語";
3844     assert(s.dropExactly(2) == "語");
3845     assert(s.dropBackExactly(2) == "日");
3846 
3847     auto bd = filterBidirectional!"true"([1, 2, 3]);
3848     assert(bd.dropExactly(2).equal([3]));
3849     assert(bd.dropBackExactly(2).equal([1]));
3850 }
3851 
3852 /++
3853     Convenience function which calls
3854     `range.popFront()` and returns `range`. `dropOne`
3855     makes it easier to pop an element from a range
3856     and then pass it to another function within a single expression,
3857     whereas `popFront` would require multiple statements.
3858 
3859     `dropBackOne` provides the same functionality but instead calls
3860     `range.popBack()`.
3861 +/
3862 R dropOne(R)(R range)
3863 if (isInputRange!R)
3864 {
3865     range.popFront();
3866     return range;
3867 }
3868 /// ditto
3869 R dropBackOne(R)(R range)
3870 if (isBidirectionalRange!R)
3871 {
3872     range.popBack();
3873     return range;
3874 }
3875 
3876 ///
3877 pure @safe nothrow unittest
3878 {
3879     import std.algorithm.comparison : equal;
3880     import std.algorithm.iteration : filterBidirectional;
3881     import std.container.dlist : DList;
3882 
3883     auto dl = DList!int(9, 1, 2, 3, 9);
3884     assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
3885 
3886     auto a = [1, 2, 3];
3887     assert(a.dropOne() == [2, 3]);
3888     assert(a.dropBackOne() == [1, 2]);
3889 
3890     string s = "日本語";
3891     import std.exception : assumeWontThrow;
3892     assert(assumeWontThrow(s.dropOne() == "本語"));
3893     assert(assumeWontThrow(s.dropBackOne() == "日本"));
3894 
3895     auto bd = filterBidirectional!"true"([1, 2, 3]);
3896     assert(bd.dropOne().equal([2, 3]));
3897     assert(bd.dropBackOne().equal([1, 2]));
3898 }
3899 
3900 /**
3901 Create a range which repeats one value.
3902 
3903 Params:
3904     value = the _value to repeat
3905     n = the number of times to repeat `value`
3906 
3907 Returns:
3908     If `n` is not defined, an infinite random access range
3909     with slicing.
3910 
3911     If `n` is defined, a random access range with slicing.
3912 */
3913 struct Repeat(T)
3914 {
3915 private:
3916     import std.typecons : Rebindable2;
3917 
3918     // Store a rebindable T to make Repeat assignable.
3919     Rebindable2!T _value;
3920 
3921 public:
3922     /// Range primitives
3923     @property inout(T) front() inout { return _value.get; }
3924 
3925     /// ditto
3926     @property inout(T) back() inout { return _value.get; }
3927 
3928     /// ditto
3929     enum bool empty = false;
3930 
3931     /// ditto
3932     void popFront() {}
3933 
3934     /// ditto
3935     void popBack() {}
3936 
3937     /// ditto
3938     @property auto save() inout { return this; }
3939 
3940     /// ditto
3941     inout(T) opIndex(size_t) inout { return _value.get; }
3942 
3943     /// ditto
3944     auto opSlice(size_t i, size_t j)
3945     in
3946     {
3947         assert(
3948             i <= j,
3949             "Attempting to slice a Repeat with a larger first argument than the second."
3950         );
3951     }
3952     do
3953     {
3954         return this.takeExactly(j - i);
3955     }
3956     private static struct DollarToken {}
3957 
3958     /// ditto
3959     enum opDollar = DollarToken.init;
3960 
3961     /// ditto
3962     auto opSlice(size_t, DollarToken) inout { return this; }
3963 }
3964 
3965 /// Ditto
3966 Repeat!T repeat(T)(T value)
3967 {
3968     import std.typecons : Rebindable2;
3969 
3970     return Repeat!T(Rebindable2!T(value));
3971 }
3972 
3973 ///
3974 pure @safe nothrow unittest
3975 {
3976     import std.algorithm.comparison : equal;
3977 
3978     assert(5.repeat().take(4).equal([5, 5, 5, 5]));
3979 }
3980 
3981 pure @safe nothrow unittest
3982 {
3983     import std.algorithm.comparison : equal;
3984 
3985     auto  r = repeat(5);
3986     alias R = typeof(r);
3987     static assert(isBidirectionalRange!R);
3988     static assert(isForwardRange!R);
3989     static assert(isInfinite!R);
3990     static assert(hasSlicing!R);
3991 
3992     assert(r.back == 5);
3993     assert(r.front == 5);
3994     assert(r.take(4).equal([ 5, 5, 5, 5 ]));
3995     assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
3996 
3997     R r2 = r[5 .. $];
3998     assert(r2.back == 5);
3999     assert(r2.front == 5);
4000 }
4001 
4002 /// ditto
4003 Take!(Repeat!T) repeat(T)(T value, size_t n)
4004 {
4005     return take(repeat(value), n);
4006 }
4007 
4008 ///
4009 pure @safe nothrow unittest
4010 {
4011     import std.algorithm.comparison : equal;
4012 
4013     assert(5.repeat(4).equal([5, 5, 5, 5]));
4014 }
4015 
4016 // https://issues.dlang.org/show_bug.cgi?id=12007
4017 pure @safe nothrow unittest
4018 {
4019     static class C{}
4020     Repeat!(immutable int) ri;
4021     ri = ri.save;
4022     Repeat!(immutable C) rc;
4023     rc = rc.save;
4024 
4025     import std.algorithm.setops : cartesianProduct;
4026     import std.algorithm.comparison : equal;
4027     import std.typecons : tuple;
4028     immutable int[] A = [1,2,3];
4029     immutable int[] B = [4,5,6];
4030 
4031     assert(equal(cartesianProduct(A,B),
4032         [
4033             tuple(1, 4), tuple(1, 5), tuple(1, 6),
4034             tuple(2, 4), tuple(2, 5), tuple(2, 6),
4035             tuple(3, 4), tuple(3, 5), tuple(3, 6),
4036         ]));
4037 }
4038 
4039 /**
4040 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
4041 whose front is defined by successive calls to `fun()`.
4042 This is especially useful to call function with global side effects (random
4043 functions), or to create ranges expressed as a single delegate, rather than
4044 an entire `front`/`popFront`/`empty` structure.
4045 `fun` maybe be passed either a template alias parameter (existing
4046 function, delegate, struct type defining `static opCall`) or
4047 a run-time value argument (delegate, function object).
4048 The result range models an InputRange
4049 ($(REF isInputRange, std,range,primitives)).
4050 The resulting range will call `fun()` on construction, and every call to
4051 `popFront`, and the cached value will be returned when `front` is called.
4052 
4053 Returns: an `inputRange` where each element represents another call to fun.
4054 */
4055 auto generate(Fun)(Fun fun)
4056 if (isCallable!fun)
4057 {
4058     auto gen = Generator!(Fun)(fun);
4059     gen.popFront(); // prime the first element
4060     return gen;
4061 }
4062 
4063 /// ditto
4064 auto generate(alias fun)()
4065 if (isCallable!fun)
4066 {
4067     auto gen = Generator!(fun)();
4068     gen.popFront(); // prime the first element
4069     return gen;
4070 }
4071 
4072 ///
4073 @safe pure nothrow unittest
4074 {
4075     import std.algorithm.comparison : equal;
4076     import std.algorithm.iteration : map;
4077 
4078     int i = 1;
4079     auto powersOfTwo = generate!(() => i *= 2)().take(10);
4080     assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
4081 }
4082 
4083 ///
4084 @safe pure nothrow unittest
4085 {
4086     import std.algorithm.comparison : equal;
4087 
4088     //Returns a run-time delegate
4089     auto infiniteIota(T)(T low, T high)
4090     {
4091         T i = high;
4092         return (){if (i == high) i = low; return i++;};
4093     }
4094     //adapted as a range.
4095     assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
4096 }
4097 
4098 ///
4099 @safe unittest
4100 {
4101     import std.format : format;
4102     import std.random : uniform;
4103 
4104     auto r = generate!(() => uniform(0, 6)).take(10);
4105     format("%(%s %)", r);
4106 }
4107 
4108 private struct Generator(Fun...)
4109 {
4110     static assert(Fun.length == 1);
4111     static assert(isInputRange!Generator);
4112     import std.traits : FunctionAttribute, functionAttributes, ReturnType;
4113 
4114 private:
4115     static if (is(Fun[0]))
4116         Fun[0] fun;
4117     else
4118         alias fun = Fun[0];
4119 
4120     enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
4121 
4122     import std.traits : hasIndirections;
4123     static if (!hasIndirections!(ReturnType!fun))
4124         alias RetType = Unqual!(ReturnType!fun);
4125     else
4126         alias RetType = ReturnType!fun;
4127 
4128     static if (returnByRef_)
4129         RetType *elem_;
4130     else
4131         RetType elem_;
4132 public:
4133     /// Range primitives
4134     enum empty = false;
4135 
4136     static if (returnByRef_)
4137     {
4138         /// ditto
4139         ref front() @property
4140         {
4141             return *elem_;
4142         }
4143         /// ditto
4144         void popFront()
4145         {
4146             elem_ = &fun();
4147         }
4148     }
4149     else
4150     {
4151         /// ditto
4152         auto front() @property
4153         {
4154             return elem_;
4155         }
4156         /// ditto
4157         void popFront()
4158         {
4159             elem_ = fun();
4160         }
4161     }
4162 }
4163 
4164 @safe nothrow unittest
4165 {
4166     import std.algorithm.comparison : equal;
4167 
4168     struct StaticOpCall
4169     {
4170         static ubyte opCall() { return 5 ; }
4171     }
4172 
4173     assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
4174 }
4175 
4176 @safe pure unittest
4177 {
4178     import std.algorithm.comparison : equal;
4179 
4180     struct OpCall
4181     {
4182         ubyte opCall() @safe pure { return 5 ; }
4183     }
4184 
4185     OpCall op;
4186     assert(equal(generate(op).take(10), repeat(5).take(10)));
4187 }
4188 
4189 // verify ref mechanism works
4190 @system nothrow unittest
4191 {
4192     int[10] arr;
4193     int idx;
4194 
4195     ref int fun() {
4196         auto x = idx++;
4197         idx %= arr.length;
4198         return arr[x];
4199     }
4200     int y = 1;
4201     foreach (ref x; generate!(fun).take(20))
4202     {
4203         x += y++;
4204     }
4205     import std.algorithm.comparison : equal;
4206     assert(equal(arr[], iota(12, 32, 2)));
4207 }
4208 
4209 // assure front isn't the mechanism to make generate go to the next element.
4210 @safe unittest
4211 {
4212     int i;
4213     auto g = generate!(() => ++i);
4214     auto f = g.front;
4215     assert(f == g.front);
4216     g = g.drop(5); // reassign because generate caches
4217     assert(g.front == f + 5);
4218 }
4219 
4220 // https://issues.dlang.org/show_bug.cgi?id=23319
4221 @safe pure nothrow unittest
4222 {
4223     auto b = generate!(() => const(int)(42));
4224     assert(b.front == 42);
4225 }
4226 
4227 /**
4228 Repeats the given forward range ad infinitum. If the original range is
4229 infinite (fact that would make `Cycle` the identity application),
4230 `Cycle` detects that and aliases itself to the range type
4231 itself. That works for non-forward ranges too.
4232 If the original range has random access, `Cycle` offers
4233 random access and also offers a constructor taking an initial position
4234 `index`. `Cycle` works with static arrays in addition to ranges,
4235 mostly for performance reasons.
4236 
4237 Note: The input range must not be empty.
4238 
4239 Tip: This is a great way to implement simple circular buffers.
4240 */
4241 struct Cycle(R)
4242 if (isForwardRange!R && !isInfinite!R)
4243 {
4244     static if (isRandomAccessRange!R && hasLength!R)
4245     {
4246         private R _original;
4247         private size_t _index;
4248 
4249         /// Range primitives
4250         this(R input, size_t index = 0)
4251         {
4252             _original = input;
4253             _index = index % _original.length;
4254         }
4255 
4256         /// ditto
4257         @property auto ref front()
4258         {
4259             return _original[_index];
4260         }
4261 
4262         static if (is(typeof((cast(const R)_original)[_index])))
4263         {
4264             /// ditto
4265             @property auto ref front() const
4266             {
4267                 return _original[_index];
4268             }
4269         }
4270 
4271         static if (hasAssignableElements!R)
4272         {
4273             /// ditto
4274             @property void front(ElementType!R val)
4275             {
4276                 import std.algorithm.mutation : move;
4277 
4278                 _original[_index] = move(val);
4279             }
4280         }
4281 
4282         /// ditto
4283         enum bool empty = false;
4284 
4285         /// ditto
4286         void popFront()
4287         {
4288             ++_index;
4289             if (_index >= _original.length)
4290                 _index = 0;
4291         }
4292 
4293         /// ditto
4294         auto ref opIndex(size_t n)
4295         {
4296             return _original[(n + _index) % _original.length];
4297         }
4298 
4299         static if (is(typeof((cast(const R)_original)[_index])) &&
4300                    is(typeof((cast(const R)_original).length)))
4301         {
4302             /// ditto
4303             auto ref opIndex(size_t n) const
4304             {
4305                 return _original[(n + _index) % _original.length];
4306             }
4307         }
4308 
4309         static if (hasAssignableElements!R)
4310         {
4311             /// ditto
4312             void opIndexAssign(ElementType!R val, size_t n)
4313             {
4314                 _original[(n + _index) % _original.length] = val;
4315             }
4316         }
4317 
4318         /// ditto
4319         @property Cycle save()
4320         {
4321             //No need to call _original.save, because Cycle never actually modifies _original
4322             return Cycle(_original, _index);
4323         }
4324 
4325         private static struct DollarToken {}
4326 
4327         /// ditto
4328         enum opDollar = DollarToken.init;
4329 
4330         static if (hasSlicing!R)
4331         {
4332             /// ditto
4333             auto opSlice(size_t i, size_t j)
4334             in
4335             {
4336                 assert(i <= j);
4337             }
4338             do
4339             {
4340                 return this[i .. $].takeExactly(j - i);
4341             }
4342 
4343             /// ditto
4344             auto opSlice(size_t i, DollarToken)
4345             {
4346                 return typeof(this)(_original, _index + i);
4347             }
4348         }
4349     }
4350     else
4351     {
4352         private R _original;
4353         private R _current;
4354 
4355         /// ditto
4356         this(R input)
4357         {
4358             _original = input;
4359             _current = input.save;
4360         }
4361 
4362         private this(R original, R current)
4363         {
4364             _original = original;
4365             _current = current;
4366         }
4367 
4368         /// ditto
4369         @property auto ref front()
4370         {
4371             return _current.front;
4372         }
4373 
4374         static if (is(typeof((cast(const R)_current).front)))
4375         {
4376             /// ditto
4377             @property auto ref front() const
4378             {
4379                 return _current.front;
4380             }
4381         }
4382 
4383         static if (hasAssignableElements!R)
4384         {
4385             /// ditto
4386             @property auto front(ElementType!R val)
4387             {
4388                 import std.algorithm.mutation : move;
4389 
4390                 return _current.front = move(val);
4391             }
4392         }
4393 
4394         /// ditto
4395         enum bool empty = false;
4396 
4397         /// ditto
4398         void popFront()
4399         {
4400             _current.popFront();
4401             if (_current.empty)
4402                 _current = _original.save;
4403         }
4404 
4405         /// ditto
4406         @property Cycle save()
4407         {
4408             //No need to call _original.save, because Cycle never actually modifies _original
4409             return Cycle(_original, _current.save);
4410         }
4411     }
4412 }
4413 
4414 /// ditto
4415 template Cycle(R)
4416 if (isInfinite!R)
4417 {
4418     alias Cycle = R;
4419 }
4420 
4421 /// ditto
4422 struct Cycle(R)
4423 if (isStaticArray!R)
4424 {
4425     private alias ElementType = typeof(R.init[0]);
4426     private ElementType* _ptr;
4427     private size_t _index;
4428 
4429 nothrow:
4430 
4431     /// Range primitives
4432     this(ref R input, size_t index = 0) @system
4433     {
4434         _ptr = input.ptr;
4435         _index = index % R.length;
4436     }
4437 
4438     /// ditto
4439     @property ref inout(ElementType) front() inout @safe
4440     {
4441         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4442         {
4443             return p[idx];
4444         }
4445         return trustedPtrIdx(_ptr, _index);
4446     }
4447 
4448     /// ditto
4449     enum bool empty = false;
4450 
4451     /// ditto
4452     void popFront() @safe
4453     {
4454         ++_index;
4455         if (_index >= R.length)
4456             _index = 0;
4457     }
4458 
4459     /// ditto
4460     ref inout(ElementType) opIndex(size_t n) inout @safe
4461     {
4462         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4463         {
4464             return p[idx % R.length];
4465         }
4466         return trustedPtrIdx(_ptr, n + _index);
4467     }
4468 
4469     /// ditto
4470     @property inout(Cycle) save() inout @safe
4471     {
4472         return this;
4473     }
4474 
4475     private static struct DollarToken {}
4476     /// ditto
4477     enum opDollar = DollarToken.init;
4478 
4479     /// ditto
4480     auto opSlice(size_t i, size_t j) @safe
4481     in
4482     {
4483         assert(
4484             i <= j,
4485             "Attempting to slice a Repeat with a larger first argument than the second."
4486         );
4487     }
4488     do
4489     {
4490         return this[i .. $].takeExactly(j - i);
4491     }
4492 
4493     /// ditto
4494     inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
4495     {
4496         static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
4497         {
4498             return cast(inout) Cycle(*cast(R*)(p), idx);
4499         }
4500         return trustedCtor(_ptr, _index + i);
4501     }
4502 }
4503 
4504 /// Ditto
4505 auto cycle(R)(R input)
4506 if (isInputRange!R)
4507 {
4508     static assert(isForwardRange!R || isInfinite!R,
4509         "Cycle requires a forward range argument unless it's statically known"
4510          ~ " to be infinite");
4511     assert(!input.empty, "Attempting to pass an empty input to cycle");
4512     static if (isInfinite!R) return input;
4513     else return Cycle!R(input);
4514 }
4515 
4516 ///
4517 @safe unittest
4518 {
4519     import std.algorithm.comparison : equal;
4520     import std.range : cycle, take;
4521 
4522     // Here we create an infinitive cyclic sequence from [1, 2]
4523     // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
4524     // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
4525     // and compare them with the expected values for equality.
4526     assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
4527 }
4528 
4529 /// Ditto
4530 Cycle!R cycle(R)(R input, size_t index = 0)
4531 if (isRandomAccessRange!R && !isInfinite!R)
4532 {
4533     assert(!input.empty, "Attempting to pass an empty input to cycle");
4534     return Cycle!R(input, index);
4535 }
4536 
4537 /// Ditto
4538 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
4539 if (isStaticArray!R)
4540 {
4541     return Cycle!R(input, index);
4542 }
4543 
4544 @safe nothrow unittest
4545 {
4546     import std.algorithm.comparison : equal;
4547     import std.internal.test.dummyrange : AllDummyRanges;
4548 
4549     static assert(isForwardRange!(Cycle!(uint[])));
4550 
4551     // Make sure ref is getting propagated properly.
4552     int[] nums = [1,2,3];
4553     auto c2 = cycle(nums);
4554     c2[3]++;
4555     assert(nums[0] == 2);
4556 
4557     immutable int[] immarr = [1, 2, 3];
4558 
4559     foreach (DummyType; AllDummyRanges)
4560     {
4561         static if (isForwardRange!DummyType)
4562         {
4563             DummyType dummy;
4564             auto cy = cycle(dummy);
4565             static assert(isForwardRange!(typeof(cy)));
4566             auto t = take(cy, 20);
4567             assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
4568 
4569             const cRange = cy;
4570             assert(cRange.front == 1);
4571 
4572             static if (hasAssignableElements!DummyType)
4573             {
4574                 {
4575                     cy.front = 66;
4576                     scope(exit) cy.front = 1;
4577                     assert(dummy.front == 66);
4578                 }
4579 
4580                 static if (isRandomAccessRange!DummyType)
4581                 {
4582                     {
4583                         cy[10] = 66;
4584                         scope(exit) cy[10] = 1;
4585                         assert(dummy.front == 66);
4586                     }
4587 
4588                     assert(cRange[10] == 1);
4589                 }
4590             }
4591 
4592             static if (hasSlicing!DummyType)
4593             {
4594                 auto slice = cy[5 .. 15];
4595                 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
4596                 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
4597 
4598                 auto infSlice = cy[7 .. $];
4599                 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
4600                 static assert(isInfinite!(typeof(infSlice)));
4601             }
4602         }
4603     }
4604 }
4605 
4606 @system nothrow unittest // For static arrays.
4607 {
4608     import std.algorithm.comparison : equal;
4609 
4610     int[3] a = [ 1, 2, 3 ];
4611     static assert(isStaticArray!(typeof(a)));
4612     auto c = cycle(a);
4613     assert(a.ptr == c._ptr);
4614     assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
4615     static assert(isForwardRange!(typeof(c)));
4616 
4617     // Test qualifiers on slicing.
4618     alias C = typeof(c);
4619     static assert(is(typeof(c[1 .. $]) == C));
4620     const cConst = c;
4621     static assert(is(typeof(cConst[1 .. $]) == const(C)));
4622 }
4623 
4624 @safe nothrow unittest // For infinite ranges
4625 {
4626     struct InfRange
4627     {
4628         void popFront() { }
4629         @property int front() { return 0; }
4630         enum empty = false;
4631         auto save() { return this; }
4632     }
4633     struct NonForwardInfRange
4634     {
4635         void popFront() { }
4636         @property int front() { return 0; }
4637         enum empty = false;
4638     }
4639 
4640     InfRange i;
4641     NonForwardInfRange j;
4642     auto c = cycle(i);
4643     assert(c == i);
4644     //make sure it can alias out even non-forward infinite ranges
4645     static assert(is(typeof(j.cycle) == typeof(j)));
4646 }
4647 
4648 @safe unittest
4649 {
4650     import std.algorithm.comparison : equal;
4651 
4652     int[5] arr = [0, 1, 2, 3, 4];
4653     auto cleD = cycle(arr[]); //Dynamic
4654     assert(equal(cleD[5 .. 10], arr[]));
4655 
4656     //n is a multiple of 5 worth about 3/4 of size_t.max
4657     auto n = size_t.max/4 + size_t.max/2;
4658     n -= n % 5;
4659 
4660     //Test index overflow
4661     foreach (_ ; 0 .. 10)
4662     {
4663         cleD = cleD[n .. $];
4664         assert(equal(cleD[5 .. 10], arr[]));
4665     }
4666 }
4667 
4668 @system @nogc nothrow unittest
4669 {
4670     import std.algorithm.comparison : equal;
4671 
4672     int[5] arr = [0, 1, 2, 3, 4];
4673     auto cleS = cycle(arr);   //Static
4674     assert(equal(cleS[5 .. 10], arr[]));
4675 
4676     //n is a multiple of 5 worth about 3/4 of size_t.max
4677     auto n = size_t.max/4 + size_t.max/2;
4678     n -= n % 5;
4679 
4680     //Test index overflow
4681     foreach (_ ; 0 .. 10)
4682     {
4683         cleS = cleS[n .. $];
4684         assert(equal(cleS[5 .. 10], arr[]));
4685     }
4686 }
4687 
4688 @system unittest
4689 {
4690     import std.algorithm.comparison : equal;
4691 
4692     int[1] arr = [0];
4693     auto cleS = cycle(arr);
4694     cleS = cleS[10 .. $];
4695     assert(equal(cleS[5 .. 10], 0.repeat(5)));
4696     assert(cleS.front == 0);
4697 }
4698 
4699 // https://issues.dlang.org/show_bug.cgi?id=10845
4700 @system unittest
4701 {
4702     import std.algorithm.comparison : equal;
4703     import std.algorithm.iteration : filter;
4704 
4705     auto a = inputRangeObject(iota(3).filter!"true");
4706     assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
4707 }
4708 
4709 // https://issues.dlang.org/show_bug.cgi?id=12177
4710 @safe unittest
4711 {
4712     static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
4713 }
4714 
4715 // https://issues.dlang.org/show_bug.cgi?id=13390
4716 @system unittest
4717 {
4718     import core.exception : AssertError;
4719     import std.exception : assertThrown;
4720     assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
4721 }
4722 
4723 // https://issues.dlang.org/show_bug.cgi?id=18657
4724 pure @safe unittest
4725 {
4726     import std.algorithm.comparison : equal;
4727     string s = "foo";
4728     auto r = refRange(&s).cycle.take(4);
4729     assert(equal(r.save, "foof"));
4730     assert(equal(r.save, "foof"));
4731 }
4732 
4733 private alias lengthType(R) = typeof(R.init.length.init);
4734 
4735 /**
4736    Iterate several ranges in lockstep. The element type is a proxy tuple
4737    that allows accessing the current element in the `n`th range by
4738    using `e[n]`.
4739 
4740    `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
4741    bundle its elements and uses the `opApply` protocol.
4742    `lockstep` allows reference access to the elements in
4743    `foreach` iterations.
4744 
4745     Params:
4746         sp = controls what `zip` will do if the ranges are different lengths
4747         ranges = the ranges to zip together
4748     Returns:
4749         At minimum, an input range. `Zip` offers the lowest range facilities
4750         of all components, e.g. it offers random access iff all ranges offer
4751         random access, and also offers mutation and swapping if all ranges offer
4752         it. Due to this, `Zip` is extremely powerful because it allows manipulating
4753         several ranges in lockstep.
4754     Throws:
4755         An `Exception` if all of the ranges are not the same length and
4756         `sp` is set to `StoppingPolicy.requireSameLength`.
4757 
4758     Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for
4759     the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This
4760     limitation is not shared by the anonymous range returned by the `zip`
4761     function when not given an explicit `StoppingPolicy` as an argument.
4762 */
4763 struct Zip(Ranges...)
4764 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4765 {
4766     import std.format : format; //for generic mixins
4767     import std.typecons : Tuple;
4768 
4769     alias R = Ranges;
4770     private R ranges;
4771     alias ElementType = Tuple!(staticMap!(.ElementType, R));
4772     private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
4773 
4774 /**
4775    Builds an object. Usually this is invoked indirectly by using the
4776    $(LREF zip) function.
4777  */
4778     this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
4779     {
4780         ranges[] = rs[];
4781         stoppingPolicy = s;
4782     }
4783 
4784 /**
4785    Returns `true` if the range is at end. The test depends on the
4786    stopping policy.
4787 */
4788     static if (allSatisfy!(isInfinite, R))
4789     {
4790         // BUG:  Doesn't propagate infiniteness if only some ranges are infinite
4791         //       and s == StoppingPolicy.longest.  This isn't fixable in the
4792         //       current design since StoppingPolicy is known only at runtime.
4793         enum bool empty = false;
4794     }
4795     else
4796     {
4797         ///
4798         @property bool empty()
4799         {
4800             import std.exception : enforce;
4801             import std.meta : anySatisfy;
4802 
4803             final switch (stoppingPolicy)
4804             {
4805             case StoppingPolicy.shortest:
4806                 foreach (i, Unused; R)
4807                 {
4808                     if (ranges[i].empty) return true;
4809                 }
4810                 return false;
4811             case StoppingPolicy.longest:
4812                 static if (anySatisfy!(isInfinite, R))
4813                 {
4814                     return false;
4815                 }
4816                 else
4817                 {
4818                     foreach (i, Unused; R)
4819                     {
4820                         if (!ranges[i].empty) return false;
4821                     }
4822                     return true;
4823                 }
4824             case StoppingPolicy.requireSameLength:
4825                 foreach (i, Unused; R[1 .. $])
4826                 {
4827                     enforce(ranges[0].empty ==
4828                             ranges[i + 1].empty,
4829                             "Inequal-length ranges passed to Zip");
4830                 }
4831                 return ranges[0].empty;
4832             }
4833             assert(false);
4834         }
4835     }
4836 
4837     static if (allSatisfy!(isForwardRange, R))
4838     {
4839         ///
4840         @property Zip save()
4841         {
4842             //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
4843             return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4844         }
4845     }
4846 
4847     private .ElementType!(R[i]) tryGetInit(size_t i)()
4848     {
4849         alias E = .ElementType!(R[i]);
4850         static if (!is(typeof({static E i;})))
4851             throw new Exception("Range with non-default constructable elements exhausted.");
4852         else
4853             return E.init;
4854     }
4855 
4856 /**
4857    Returns the current iterated element.
4858 */
4859     @property ElementType front()
4860     {
4861         @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
4862         //ElementType(tryGetFront!0, tryGetFront!1, ...)
4863         return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
4864     }
4865 
4866 /**
4867    Sets the front of all iterated ranges.
4868 */
4869     static if (allSatisfy!(hasAssignableElements, R))
4870     {
4871         @property void front(ElementType v)
4872         {
4873             foreach (i, Unused; R)
4874             {
4875                 if (!ranges[i].empty)
4876                 {
4877                     ranges[i].front = v[i];
4878                 }
4879             }
4880         }
4881     }
4882 
4883 /**
4884    Moves out the front.
4885 */
4886     static if (allSatisfy!(hasMobileElements, R))
4887     {
4888         ElementType moveFront()
4889         {
4890             @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4891             //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
4892             return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
4893         }
4894     }
4895 
4896 /**
4897    Returns the rightmost element.
4898 */
4899     static if (allSatisfy!(isBidirectionalRange, R))
4900     {
4901         @property ElementType back()
4902         {
4903             //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4904 
4905             @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
4906             //ElementType(tryGetBack!0, tryGetBack!1, ...)
4907             return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
4908         }
4909 
4910 /**
4911    Moves out the back.
4912 */
4913         static if (allSatisfy!(hasMobileElements, R))
4914         {
4915             ElementType moveBack()
4916             {
4917                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4918 
4919                 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();}
4920                 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
4921                 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
4922             }
4923         }
4924 
4925 /**
4926    Returns the current iterated element.
4927 */
4928         static if (allSatisfy!(hasAssignableElements, R))
4929         {
4930             @property void back(ElementType v)
4931             {
4932                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
4933                 //Not sure the call is even legal for StoppingPolicy.longest
4934 
4935                 foreach (i, Unused; R)
4936                 {
4937                     if (!ranges[i].empty)
4938                     {
4939                         ranges[i].back = v[i];
4940                     }
4941                 }
4942             }
4943         }
4944     }
4945 
4946 /**
4947    Advances to the next element in all controlled ranges.
4948 */
4949     void popFront()
4950     {
4951         import std.exception : enforce;
4952 
4953         final switch (stoppingPolicy)
4954         {
4955         case StoppingPolicy.shortest:
4956             foreach (i, Unused; R)
4957             {
4958                 assert(!ranges[i].empty);
4959                 ranges[i].popFront();
4960             }
4961             break;
4962         case StoppingPolicy.longest:
4963             foreach (i, Unused; R)
4964             {
4965                 if (!ranges[i].empty) ranges[i].popFront();
4966             }
4967             break;
4968         case StoppingPolicy.requireSameLength:
4969             foreach (i, Unused; R)
4970             {
4971                 enforce(!ranges[i].empty, "Invalid Zip object");
4972                 ranges[i].popFront();
4973             }
4974             break;
4975         }
4976     }
4977 
4978 /**
4979    Calls `popBack` for all controlled ranges.
4980 */
4981     static if (allSatisfy!(isBidirectionalRange, R))
4982     {
4983         void popBack()
4984         {
4985             //TODO: Fixme! In case of jaggedness, this is wrong.
4986             import std.exception : enforce;
4987 
4988             final switch (stoppingPolicy)
4989             {
4990             case StoppingPolicy.shortest:
4991                 foreach (i, Unused; R)
4992                 {
4993                     assert(!ranges[i].empty);
4994                     ranges[i].popBack();
4995                 }
4996                 break;
4997             case StoppingPolicy.longest:
4998                 foreach (i, Unused; R)
4999                 {
5000                     if (!ranges[i].empty) ranges[i].popBack();
5001                 }
5002                 break;
5003             case StoppingPolicy.requireSameLength:
5004                 foreach (i, Unused; R)
5005                 {
5006                     enforce(!ranges[i].empty, "Invalid Zip object");
5007                     ranges[i].popBack();
5008                 }
5009                 break;
5010             }
5011         }
5012     }
5013 
5014 /**
5015    Returns the length of this range. Defined only if all ranges define
5016    `length`.
5017 */
5018     static if (allSatisfy!(hasLength, R))
5019     {
5020         @property auto length()
5021         {
5022             static if (Ranges.length == 1)
5023                 return ranges[0].length;
5024             else
5025             {
5026                 if (stoppingPolicy == StoppingPolicy.requireSameLength)
5027                     return ranges[0].length;
5028 
5029                 //[min|max](ranges[0].length, ranges[1].length, ...)
5030                 import std.algorithm.comparison : min, max;
5031                 if (stoppingPolicy == StoppingPolicy.shortest)
5032                     return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5033                 else
5034                     return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5035             }
5036         }
5037 
5038         alias opDollar = length;
5039     }
5040 
5041 /**
5042    Returns a slice of the range. Defined only if all range define
5043    slicing.
5044 */
5045     static if (allSatisfy!(hasSlicing, R))
5046     {
5047         auto opSlice(size_t from, size_t to)
5048         {
5049             //Slicing an infinite range yields the type Take!R
5050             //For finite ranges, the type Take!R aliases to R
5051             alias ZipResult = Zip!(staticMap!(Take, R));
5052 
5053             //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
5054             return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
5055         }
5056     }
5057 
5058 /**
5059    Returns the `n`th element in the composite range. Defined if all
5060    ranges offer random access.
5061 */
5062     static if (allSatisfy!(isRandomAccessRange, R))
5063     {
5064         ElementType opIndex(size_t n)
5065         {
5066             //TODO: Fixme! This may create an out of bounds access
5067             //for StoppingPolicy.longest
5068 
5069             //ElementType(ranges[0][n], ranges[1][n], ...)
5070             return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
5071         }
5072 
5073 /**
5074    Assigns to the `n`th element in the composite range. Defined if
5075    all ranges offer random access.
5076 */
5077         static if (allSatisfy!(hasAssignableElements, R))
5078         {
5079             void opIndexAssign(ElementType v, size_t n)
5080             {
5081                 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
5082                 foreach (i, Range; R)
5083                 {
5084                     ranges[i][n] = v[i];
5085                 }
5086             }
5087         }
5088 
5089 /**
5090    Destructively reads the `n`th element in the composite
5091    range. Defined if all ranges offer random access.
5092 */
5093         static if (allSatisfy!(hasMobileElements, R))
5094         {
5095             ElementType moveAt(size_t n)
5096             {
5097                 //TODO: Fixme! This may create an out of bounds access
5098                 //for StoppingPolicy.longest
5099 
5100                 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
5101                 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
5102             }
5103         }
5104     }
5105 }
5106 
5107 /// Ditto
5108 auto zip(Ranges...)(Ranges ranges)
5109 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5110 {
5111     import std.meta : anySatisfy, templateOr;
5112     static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1)
5113     {
5114         return ZipShortest!(Ranges)(ranges);
5115     }
5116     else static if (allSatisfy!(isBidirectionalRange, Ranges))
5117     {
5118         static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)
5119             && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges)
5120             && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges)))
5121         {
5122             // If all the ranges are bidirectional, if possible slice them to
5123             // the same length to simplify the implementation.
5124             static assert(anySatisfy!(hasLength, Ranges));
5125             static foreach (i, Range; Ranges)
5126                 static if (hasLength!Range)
5127                 {
5128                     static if (!is(typeof(minLen) == size_t))
5129                         size_t minLen = ranges[i].length;
5130                     else
5131                     {{
5132                         const x = ranges[i].length;
5133                         if (x < minLen) minLen = x;
5134                     }}
5135                 }
5136             import std.format : format;
5137             static if (!anySatisfy!(isInfinite, Ranges))
5138                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5139                     `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length)));
5140             else
5141                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5142                     `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length)));
5143         }
5144         else static if (allSatisfy!(isRandomAccessRange, Ranges))
5145         {
5146             // We can't slice but we can still use random access to ensure
5147             // "back" is retrieving the same index for each range.
5148             return ZipShortest!(Ranges)(ranges);
5149         }
5150         else
5151         {
5152             // If bidirectional range operations would not be supported by
5153             // ZipShortest that might have actually been a bug since Zip
5154             // supported `back` without verifying that each range had the
5155             // same length, but for the sake of backwards compatibility
5156             // use the old Zip to continue supporting them.
5157             return Zip!Ranges(ranges);
5158         }
5159     }
5160     else
5161     {
5162         return ZipShortest!(Ranges)(ranges);
5163     }
5164 }
5165 
5166 ///
5167 @nogc nothrow pure @safe unittest
5168 {
5169     import std.algorithm.comparison : equal;
5170     import std.algorithm.iteration : map;
5171 
5172     // pairwise sum
5173     auto arr = only(0, 1, 2);
5174     auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
5175     assert(part1.equal(only(1, 3)));
5176 }
5177 
5178 ///
5179 nothrow pure @safe unittest
5180 {
5181     import std.conv : to;
5182 
5183     int[] a = [ 1, 2, 3 ];
5184     string[] b = [ "a", "b", "c" ];
5185     string[] result;
5186 
5187     foreach (tup; zip(a, b))
5188     {
5189         result ~= tup[0].to!string ~ tup[1];
5190     }
5191 
5192     assert(result == [ "1a", "2b", "3c" ]);
5193 
5194     size_t idx = 0;
5195     // unpacking tuple elements with foreach
5196     foreach (e1, e2; zip(a, b))
5197     {
5198         assert(e1 == a[idx]);
5199         assert(e2 == b[idx]);
5200         ++idx;
5201     }
5202 }
5203 
5204 /// `zip` is powerful - the following code sorts two arrays in parallel:
5205 nothrow pure @safe unittest
5206 {
5207     import std.algorithm.sorting : sort;
5208 
5209     int[] a = [ 1, 2, 3 ];
5210     string[] b = [ "a", "c", "b" ];
5211     zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
5212 
5213     assert(a == [ 3, 2, 1 ]);
5214     // b is sorted according to a's sorting
5215     assert(b == [ "b", "c", "a" ]);
5216 }
5217 
5218 /// Ditto
5219 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
5220 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5221 {
5222     return Zip!Ranges(ranges, sp);
5223 }
5224 
5225 /**
5226    Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop.
5227    By default stop at the end of the shortest of all ranges.
5228 */
5229 enum StoppingPolicy
5230 {
5231     /// Stop when the shortest range is exhausted
5232     shortest,
5233     /// Stop when the longest range is exhausted
5234     longest,
5235     /// Require that all ranges are equal
5236     requireSameLength,
5237 }
5238 
5239 ///
5240 pure @safe unittest
5241 {
5242     import std.algorithm.comparison : equal;
5243     import std.exception : assertThrown;
5244     import std.range.primitives;
5245     import std.typecons : tuple;
5246 
5247     auto a = [1, 2, 3];
5248     auto b = [4, 5, 6, 7];
5249 
5250     auto shortest = zip(StoppingPolicy.shortest, a, b);
5251     assert(shortest.equal([
5252         tuple(1, 4),
5253         tuple(2, 5),
5254         tuple(3, 6)
5255     ]));
5256 
5257     auto longest = zip(StoppingPolicy.longest, a, b);
5258     assert(longest.equal([
5259         tuple(1, 4),
5260         tuple(2, 5),
5261         tuple(3, 6),
5262         tuple(0, 7)
5263     ]));
5264 
5265     auto same = zip(StoppingPolicy.requireSameLength, a, b);
5266     same.popFrontN(3);
5267     assertThrown!Exception(same.popFront);
5268 }
5269 
5270 /+
5271 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest`
5272 except it properly implements `back` and `popBack` in the
5273 case of uneven ranges or disables those operations when
5274 it is not possible to guarantee they are correct.
5275 +/
5276 package template ZipShortest(Ranges...)
5277 if (Ranges.length && __traits(compiles,
5278     {
5279         static assert(allSatisfy!(isInputRange, Ranges));
5280     }))
5281 {
5282     alias ZipShortest = .ZipShortest!(
5283         Ranges.length == 1 || allSatisfy!(isInfinite, Ranges)
5284             ? Yes.allKnownSameLength
5285             : No.allKnownSameLength,
5286         Ranges);
5287 }
5288 /+ non-public, ditto +/
5289 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...)
5290 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5291 {
5292     import std.format : format; //for generic mixins
5293     import std.meta : anySatisfy, templateOr;
5294     import std.typecons : Tuple;
5295 
5296     deprecated("Use of an undocumented alias R.")
5297     alias R = Ranges; // Unused here but defined in case library users rely on it.
5298     private Ranges ranges;
5299     alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
5300 
5301     /+
5302        Builds an object. Usually this is invoked indirectly by using the
5303        $(LREF zip) function.
5304     +/
5305     this(Ranges rs)
5306     {
5307         ranges[] = rs[];
5308     }
5309 
5310     /+
5311        Returns `true` if the range is at end.
5312     +/
5313     static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges)
5314         : allSatisfy!(isInfinite, Ranges))
5315     {
5316         enum bool empty = false;
5317     }
5318     else
5319     {
5320         @property bool empty()
5321         {
5322             static if (allKnownSameLength)
5323             {
5324                 return ranges[0].empty;
5325             }
5326             else
5327             {
5328                 static foreach (i; 0 .. Ranges.length)
5329                 {
5330                     if (ranges[i].empty)
5331                         return true;
5332                 }
5333                 return false;
5334             }
5335         }
5336     }
5337 
5338     /+
5339        Forward range primitive. Only present if each constituent range is a
5340        forward range.
5341     +/
5342     static if (allSatisfy!(isForwardRange, Ranges))
5343     @property typeof(this) save()
5344     {
5345         return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length)));
5346     }
5347 
5348     /+
5349        Returns the current iterated element.
5350     +/
5351     @property ElementType front()
5352     {
5353         return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length)));
5354     }
5355 
5356     /+
5357        Sets the front of all iterated ranges. Only present if each constituent
5358        range has assignable elements.
5359     +/
5360     static if (allSatisfy!(hasAssignableElements, Ranges))
5361     @property void front()(ElementType v)
5362     {
5363         static foreach (i; 0 .. Ranges.length)
5364             ranges[i].front = v[i];
5365     }
5366 
5367     /+
5368        Moves out the front. Present if each constituent range has mobile elements.
5369     +/
5370     static if (allSatisfy!(hasMobileElements, Ranges))
5371     ElementType moveFront()()
5372     {
5373         return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length)));
5374     }
5375 
5376     private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges)
5377         && (allKnownSameLength
5378             || allSatisfy!(isRandomAccessRange, Ranges)
5379             // Could also add the case where there is one non-infinite bidirectional
5380             // range that defines `length` and all others are infinite random access
5381             // ranges. Adding this would require appropriate branches in
5382             // back/moveBack/popBack.
5383             );
5384 
5385     /+
5386        Returns the rightmost element. Present if all constituent ranges are
5387        bidirectional and either there is a compile-time guarantee that all
5388        ranges have the same length (in `allKnownSameLength`) or all ranges
5389        provide random access to elements.
5390     +/
5391     static if (isBackWellDefined)
5392     @property ElementType back()
5393     {
5394         static if (allKnownSameLength)
5395         {
5396             return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length)));
5397         }
5398         else
5399         {
5400             const backIndex = length - 1;
5401             return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length)));
5402         }
5403     }
5404 
5405     /+
5406        Moves out the back. Present if `back` is defined and
5407        each constituent range has mobile elements.
5408     +/
5409     static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges))
5410     ElementType moveBack()()
5411     {
5412         static if (allKnownSameLength)
5413         {
5414             return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length)));
5415         }
5416         else
5417         {
5418             const backIndex = length - 1;
5419             return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length)));
5420         }
5421     }
5422 
5423     /+
5424        Sets the rightmost element. Only present if `back` is defined and
5425        each constituent range has assignable elements.
5426     +/
5427     static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges))
5428     @property void back()(ElementType v)
5429     {
5430         static if (allKnownSameLength)
5431         {
5432             static foreach (i; 0 .. Ranges.length)
5433                 ranges[i].back = v[i];
5434         }
5435         else
5436         {
5437             const backIndex = length - 1;
5438             static foreach (i; 0 .. Ranges.length)
5439                 ranges[i][backIndex] = v[i];
5440         }
5441     }
5442 
5443     /+
5444        Calls `popFront` on each constituent range.
5445     +/
5446     void popFront()
5447     {
5448         static foreach (i; 0 .. Ranges.length)
5449             ranges[i].popFront();
5450     }
5451 
5452     /+
5453        Pops the rightmost element. Present if `back` is defined.
5454     +/
5455     static if (isBackWellDefined)
5456     void popBack()
5457     {
5458         static if (allKnownSameLength)
5459         {
5460             static foreach (i; 0 .. Ranges.length)
5461                 ranges[i].popBack;
5462         }
5463         else
5464         {
5465             const len = length;
5466             static foreach (i; 0 .. Ranges.length)
5467                 static if (!isInfinite!(Ranges[i]))
5468                     if (ranges[i].length == len)
5469                         ranges[i].popBack();
5470         }
5471     }
5472 
5473     /+
5474        Returns the length of this range. Defined if at least one
5475        constituent range defines `length` and the other ranges all also
5476        define `length` or are infinite, or if at least one constituent
5477        range defines `length` and there is a compile-time guarantee that
5478        all ranges have the same length (in `allKnownSameLength`).
5479     +/
5480     static if (allKnownSameLength
5481         ? anySatisfy!(hasLength, Ranges)
5482         : (anySatisfy!(hasLength, Ranges)
5483             && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
5484     {
5485         @property size_t length()
5486         {
5487            static foreach (i, Range; Ranges)
5488            {
5489                 static if (hasLength!Range)
5490                 {
5491                     static if (!is(typeof(minLen) == size_t))
5492                         size_t minLen = ranges[i].length;
5493                     else static if (!allKnownSameLength)
5494                     {{
5495                         const x = ranges[i].length;
5496                         if (x < minLen) minLen = x;
5497                     }}
5498                 }
5499             }
5500             return minLen;
5501         }
5502 
5503         alias opDollar = length;
5504     }
5505 
5506     /+
5507        Returns a slice of the range. Defined if all constituent ranges
5508        support slicing.
5509     +/
5510     static if (allSatisfy!(hasSlicing, Ranges))
5511     {
5512         // Note: we will know that all elements of the resultant range
5513         // will have the same length but we cannot change `allKnownSameLength`
5514         // because the `hasSlicing` predicate tests that the result returned
5515         // by `opSlice` has the same type as the receiver.
5516         auto opSlice()(size_t from, size_t to)
5517         {
5518             //(ranges[0][from .. to], ranges[1][from .. to], ...)
5519             enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length));
5520             static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs)))
5521                 return mixin(`typeof(this)`~sliceArgs);
5522             else
5523                 // The type is different anyway so we might as well
5524                 // explicitly set allKnownSameLength.
5525                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`
5526                     ~sliceArgs);
5527         }
5528     }
5529 
5530     /+
5531        Returns the `n`th element in the composite range. Defined if all
5532        constituent ranges offer random access.
5533     +/
5534     static if (allSatisfy!(isRandomAccessRange, Ranges))
5535     ElementType opIndex()(size_t n)
5536     {
5537         return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length)));
5538     }
5539 
5540     /+
5541        Sets the `n`th element in the composite range. Defined if all
5542        constituent ranges offer random access and have assignable elements.
5543     +/
5544     static if (allSatisfy!(isRandomAccessRange, Ranges)
5545         && allSatisfy!(hasAssignableElements, Ranges))
5546     void opIndexAssign()(ElementType v, size_t n)
5547     {
5548         static foreach (i; 0 .. Ranges.length)
5549             ranges[i][n] = v[i];
5550     }
5551 
5552     /+
5553        Destructively reads the `n`th element in the composite
5554        range. Defined if all constituent ranges offer random
5555        access and have mobile elements.
5556     +/
5557     static if (allSatisfy!(isRandomAccessRange, Ranges)
5558         && allSatisfy!(hasMobileElements, Ranges))
5559     ElementType moveAt()(size_t n)
5560     {
5561         return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length)));
5562     }
5563 }
5564 
5565 pure @system unittest
5566 {
5567     import std.algorithm.comparison : equal;
5568     import std.algorithm.iteration : filter, map;
5569     import std.algorithm.mutation : swap;
5570     import std.algorithm.sorting : sort;
5571 
5572     import std.exception : assertThrown, assertNotThrown;
5573     import std.typecons : tuple;
5574 
5575     int[] a = [ 1, 2, 3 ];
5576     float[] b = [ 1.0, 2.0, 3.0 ];
5577     foreach (e; zip(a, b))
5578     {
5579         assert(e[0] == e[1]);
5580     }
5581 
5582     swap(a[0], a[1]);
5583     {
5584         auto z = zip(a, b);
5585     }
5586     //swap(z.front(), z.back());
5587     sort!("a[0] < b[0]")(zip(a, b));
5588     assert(a == [1, 2, 3]);
5589     assert(b == [2.0, 1.0, 3.0]);
5590 
5591     auto z = zip(StoppingPolicy.requireSameLength, a, b);
5592     assertNotThrown(z.popBack());
5593     assertNotThrown(z.popBack());
5594     assertNotThrown(z.popBack());
5595     assert(z.empty);
5596     assertThrown(z.popBack());
5597 
5598     a = [ 1, 2, 3 ];
5599     b = [ 1.0, 2.0, 3.0 ];
5600     sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
5601     assert(a == [3, 2, 1]);
5602     assert(b == [3.0, 2.0, 1.0]);
5603 
5604     a = [];
5605     b = [];
5606     assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
5607 
5608     // Test infiniteness propagation.
5609     static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
5610 
5611     // Test stopping policies with both value and reference.
5612     auto a1 = [1, 2];
5613     auto a2 = [1, 2, 3];
5614     auto stuff = tuple(tuple(a1, a2),
5615             tuple(filter!"a"(a1), filter!"a"(a2)));
5616 
5617     alias FOO = Zip!(immutable(int)[], immutable(float)[]);
5618 
5619     foreach (t; stuff.expand)
5620     {
5621         auto arr1 = t[0];
5622         auto arr2 = t[1];
5623         auto zShortest = zip(arr1, arr2);
5624         assert(equal(map!"a[0]"(zShortest), [1, 2]));
5625         assert(equal(map!"a[1]"(zShortest), [1, 2]));
5626 
5627         try {
5628             auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
5629             foreach (elem; zSame) {}
5630             assert(0);
5631         } catch (Throwable) { /* It's supposed to throw.*/ }
5632 
5633         auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
5634         assert(!zLongest.ranges[0].empty);
5635         assert(!zLongest.ranges[1].empty);
5636 
5637         zLongest.popFront();
5638         zLongest.popFront();
5639         assert(!zLongest.empty);
5640         assert(zLongest.ranges[0].empty);
5641         assert(!zLongest.ranges[1].empty);
5642 
5643         zLongest.popFront();
5644         assert(zLongest.empty);
5645     }
5646 
5647     // https://issues.dlang.org/show_bug.cgi?id=8900
5648     assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
5649     assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
5650 
5651     // https://issues.dlang.org/show_bug.cgi?id=18524
5652     // moveBack instead performs moveFront
5653     {
5654         auto r = zip([1,2,3]);
5655         assert(r.moveBack()[0] == 3);
5656         assert(r.moveFront()[0] == 1);
5657     }
5658 
5659     // Doesn't work yet.  Issues w/ emplace.
5660     // static assert(is(Zip!(immutable int[], immutable float[])));
5661 
5662 
5663     // These unittests pass, but make the compiler consume an absurd amount
5664     // of RAM and time.  Therefore, they should only be run if explicitly
5665     // uncommented when making changes to Zip.  Also, running them using
5666     // make -fwin32.mak unittest makes the compiler completely run out of RAM.
5667     // You need to test just this module.
5668     /+
5669      foreach (DummyType1; AllDummyRanges)
5670      {
5671          DummyType1 d1;
5672          foreach (DummyType2; AllDummyRanges)
5673          {
5674              DummyType2 d2;
5675              auto r = zip(d1, d2);
5676              assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
5677              assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
5678 
5679              static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
5680              {
5681                  static assert(isForwardRange!(typeof(r)));
5682              }
5683 
5684              static if (isBidirectionalRange!DummyType1 &&
5685                      isBidirectionalRange!DummyType2) {
5686                  static assert(isBidirectionalRange!(typeof(r)));
5687              }
5688              static if (isRandomAccessRange!DummyType1 &&
5689                      isRandomAccessRange!DummyType2) {
5690                  static assert(isRandomAccessRange!(typeof(r)));
5691              }
5692          }
5693      }
5694     +/
5695 }
5696 
5697 nothrow pure @safe unittest
5698 {
5699     import std.algorithm.sorting : sort;
5700 
5701     auto a = [5,4,3,2,1];
5702     auto b = [3,1,2,5,6];
5703     auto z = zip(a, b);
5704 
5705     sort!"a[0] < b[0]"(z);
5706 
5707     assert(a == [1, 2, 3, 4, 5]);
5708     assert(b == [6, 5, 2, 1, 3]);
5709 }
5710 
5711 nothrow pure @safe unittest
5712 {
5713     import std.algorithm.comparison : equal;
5714     import std.typecons : tuple;
5715 
5716     auto LL = iota(1L, 1000L);
5717     auto z = zip(LL, [4]);
5718 
5719     assert(equal(z, [tuple(1L,4)]));
5720 
5721     auto LL2 = iota(0L, 500L);
5722     auto z2 = zip([7], LL2);
5723     assert(equal(z2, [tuple(7, 0L)]));
5724 }
5725 
5726 // Test for https://issues.dlang.org/show_bug.cgi?id=11196
5727 @safe pure unittest
5728 {
5729     import std.exception : assertThrown;
5730 
5731     static struct S { @disable this(); }
5732     assert(zip((S[5]).init[]).length == 5);
5733     assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
5734     assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
5735 }
5736 
5737 // https://issues.dlang.org/show_bug.cgi?id=12007
5738 @nogc nothrow @safe pure unittest
5739 {
5740     static struct R
5741     {
5742         enum empty = false;
5743         void popFront(){}
5744         int front(){return 1;} @property
5745         R save(){return this;} @property
5746         void opAssign(R) @disable;
5747     }
5748     R r;
5749     auto z = zip(r, r);
5750     assert(z.save == z);
5751 }
5752 
5753 nothrow pure @system unittest
5754 {
5755     import std.typecons : tuple;
5756 
5757     auto r1 = [0,1,2];
5758     auto r2 = [1,2,3];
5759     auto z1 = zip(refRange(&r1), refRange(&r2));
5760     auto z2 = z1.save;
5761     z1.popFront();
5762     assert(z1.front == tuple(1,2));
5763     assert(z2.front == tuple(0,1));
5764 }
5765 
5766 @nogc nothrow pure @safe unittest
5767 {
5768     // Test zip's `back` and `length` with non-equal ranges.
5769     static struct NonSliceableRandomAccess
5770     {
5771         private int[] a;
5772         @property ref front()
5773         {
5774             return a.front;
5775         }
5776         @property ref back()
5777         {
5778             return a.back;
5779         }
5780         ref opIndex(size_t i)
5781         {
5782             return a[i];
5783         }
5784         void popFront()
5785         {
5786             a.popFront();
5787         }
5788         void popBack()
5789         {
5790             a.popBack();
5791         }
5792         auto moveFront()
5793         {
5794             return a.moveFront();
5795         }
5796         auto moveBack()
5797         {
5798             return a.moveBack();
5799         }
5800         auto moveAt(size_t i)
5801         {
5802             return a.moveAt(i);
5803         }
5804         bool empty() const
5805         {
5806             return a.empty;
5807         }
5808         size_t length() const
5809         {
5810             return a.length;
5811         }
5812         typeof(this) save()
5813         {
5814             return this;
5815         }
5816     }
5817     static assert(isRandomAccessRange!NonSliceableRandomAccess);
5818     static assert(!hasSlicing!NonSliceableRandomAccess);
5819     static foreach (iteration; 0 .. 2)
5820     {{
5821         int[5] data = [101, 102, 103, 201, 202];
5822         static if (iteration == 0)
5823         {
5824             auto r1 = NonSliceableRandomAccess(data[0 .. 3]);
5825             auto r2 = NonSliceableRandomAccess(data[3 .. 5]);
5826         }
5827         else
5828         {
5829             auto r1 = data[0 .. 3];
5830             auto r2 = data[3 .. 5];
5831         }
5832         auto z = zip(r1, r2);
5833         static assert(isRandomAccessRange!(typeof(z)));
5834         assert(z.length == 2);
5835         assert(z.back[0] == 102 && z.back[1] == 202);
5836         z.back = typeof(z.back)(-102, -202);// Assign to back.
5837         assert(z.back[0] == -102 && z.back[1] == -202);
5838         z.popBack();
5839         assert(z.length == 1);
5840         assert(z.back[0] == 101 && z.back[1] == 201);
5841         z.front = typeof(z.front)(-101, -201);
5842         assert(z.moveBack() == typeof(z.back)(-101, -201));
5843         z.popBack();
5844         assert(z.empty);
5845     }}
5846 }
5847 
5848 @nogc nothrow pure @safe unittest
5849 {
5850     // Test opSlice on infinite `zip`.
5851     auto z = zip(repeat(1), repeat(2));
5852     assert(hasSlicing!(typeof(z)));
5853     auto slice = z[10 .. 20];
5854     assert(slice.length == 10);
5855     static assert(!is(typeof(z) == typeof(slice)));
5856 }
5857 
5858 /*
5859     Generate lockstep's opApply function as a mixin string.
5860     If withIndex is true prepend a size_t index to the delegate.
5861 */
5862 private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
5863 {
5864     import std.format : format;
5865 
5866     string[] params;
5867     string[] emptyChecks;
5868     string[] dgArgs;
5869     string[] popFronts;
5870     string indexDef;
5871     string indexInc;
5872 
5873     if (withIndex)
5874     {
5875         params ~= "size_t";
5876         dgArgs ~= "index";
5877         if (reverse)
5878         {
5879             indexDef = q{
5880                 size_t index = ranges[0].length-1;
5881                 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
5882                         "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
5883 
5884                 foreach (range; ranges[1..$])
5885                     enforce(range.length == ranges[0].length);
5886                 };
5887             indexInc = "--index;";
5888         }
5889         else
5890         {
5891             indexDef = "size_t index = 0;";
5892             indexInc = "++index;";
5893         }
5894     }
5895 
5896     foreach (idx, Range; Ranges)
5897     {
5898         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
5899         emptyChecks ~= format("!ranges[%s].empty", idx);
5900         if (reverse)
5901         {
5902             dgArgs ~= format("ranges[%s].back", idx);
5903             popFronts ~= format("ranges[%s].popBack();", idx);
5904         }
5905         else
5906         {
5907             dgArgs ~= format("ranges[%s].front", idx);
5908             popFronts ~= format("ranges[%s].popFront();", idx);
5909         }
5910     }
5911 
5912     string name = reverse ? "opApplyReverse" : "opApply";
5913 
5914     return format(
5915     q{
5916         int %s(scope int delegate(%s) dg)
5917         {
5918             import std.exception : enforce;
5919 
5920             auto ranges = _ranges;
5921             int res;
5922             %s
5923 
5924             while (%s)
5925             {
5926                 res = dg(%s);
5927                 if (res) break;
5928                 %s
5929                 %s
5930             }
5931 
5932             if (_stoppingPolicy == StoppingPolicy.requireSameLength)
5933             {
5934                 foreach (range; ranges)
5935                     enforce(range.empty);
5936             }
5937             return res;
5938         }
5939     }, name, params.join(", "), indexDef,
5940        emptyChecks.join(" && "), dgArgs.join(", "),
5941        popFronts.join("\n                "),
5942        indexInc);
5943 }
5944 
5945 /**
5946    Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
5947    $(LREF zip) it allows reference access to its elements. If only a single
5948    range is passed in, the `Lockstep` aliases itself away.  If the
5949    ranges are of different lengths and `s` == `StoppingPolicy.shortest`
5950    stop after the shortest range is empty.  If the ranges are of different
5951    lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
5952    exception.  `s` may not be `StoppingPolicy.longest`, and passing this
5953    will throw an exception.
5954 
5955    Iterating over `Lockstep` in reverse and with an index is only possible
5956    when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
5957    indexes. If an attempt is made at iterating in reverse when `s` ==
5958    `StoppingPolicy.shortest`, an exception will be thrown.
5959 
5960    By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
5961 
5962    Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be
5963    inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to
5964    a different implementation.
5965 
5966    See_Also: $(LREF zip)
5967 
5968        `lockstep` is similar to $(LREF zip), but `zip` bundles its
5969        elements and returns a range.
5970        `lockstep` also supports reference access.
5971        Use `zip` if you want to pass the result to a range function.
5972 */
5973 struct Lockstep(Ranges...)
5974 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
5975 {
5976     ///
5977     this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
5978     {
5979         import std.exception : enforce;
5980 
5981         _ranges = ranges;
5982         enforce(sp != StoppingPolicy.longest,
5983                 "Can't use StoppingPolicy.Longest on Lockstep.");
5984         _stoppingPolicy = sp;
5985     }
5986 
5987     mixin(lockstepMixin!Ranges(false, false));
5988     mixin(lockstepMixin!Ranges(true, false));
5989     static if (allSatisfy!(isBidirectionalRange, Ranges))
5990     {
5991         mixin(lockstepMixin!Ranges(false, true));
5992         static if (allSatisfy!(hasLength, Ranges))
5993         {
5994             mixin(lockstepMixin!Ranges(true, true));
5995         }
5996         else
5997         {
5998             mixin(lockstepReverseFailMixin!Ranges(true));
5999         }
6000     }
6001     else
6002     {
6003         mixin(lockstepReverseFailMixin!Ranges(false));
6004         mixin(lockstepReverseFailMixin!Ranges(true));
6005     }
6006 
6007 private:
6008     alias R = Ranges;
6009     R _ranges;
6010     StoppingPolicy _stoppingPolicy;
6011 }
6012 
6013 /// Ditto
6014 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
6015 if (allSatisfy!(isInputRange, Ranges))
6016 {
6017     return Lockstep!(Ranges)(ranges);
6018 }
6019 /// Ditto
6020 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
6021 if (allSatisfy!(isInputRange, Ranges))
6022 {
6023     static if (Ranges.length > 1)
6024         return Lockstep!Ranges(ranges, s);
6025     else
6026         return ranges[0];
6027 }
6028 
6029 ///
6030 @system unittest
6031 {
6032    auto arr1 = [1,2,3,4,5,100];
6033    auto arr2 = [6,7,8,9,10];
6034 
6035    foreach (ref a, b; lockstep(arr1, arr2))
6036    {
6037        a += b;
6038    }
6039 
6040    assert(arr1 == [7,9,11,13,15,100]);
6041 
6042    /// Lockstep also supports iterating with an index variable:
6043    foreach (index, a, b; lockstep(arr1, arr2))
6044    {
6045        assert(arr1[index] == a);
6046        assert(arr2[index] == b);
6047    }
6048 }
6049 
6050 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
6051 @system unittest
6052 {
6053     auto arr1 = [0, 1, 2, 3];
6054     auto arr2 = [4, 5, 6, 7];
6055 
6056     size_t n = arr1.length -1;
6057     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
6058     {
6059         assert(n == index);
6060         assert(index == a);
6061         assert(arr1[index] == a);
6062         assert(arr2[index] == b);
6063         n--;
6064     }
6065 
6066     auto arr3 = [4, 5];
6067     n = 1;
6068     foreach_reverse (a, b; lockstep(arr1, arr3))
6069     {
6070         assert(a == arr1[$-n] && b == arr3[$-n]);
6071         n++;
6072     }
6073 }
6074 
6075 @system unittest
6076 {
6077     import std.algorithm.iteration : filter;
6078     import std.conv : to;
6079 
6080     // The filters are to make these the lowest common forward denominator ranges,
6081     // i.e. w/o ref return, random access, length, etc.
6082     auto foo = filter!"a"([1,2,3,4,5]);
6083     immutable bar = [6f,7f,8f,9f,10f].idup;
6084     auto l = lockstep(foo, bar);
6085 
6086     // Should work twice.  These are forward ranges with implicit save.
6087     foreach (i; 0 .. 2)
6088     {
6089         uint[] res1;
6090         float[] res2;
6091 
6092         foreach (a, ref b; l)
6093         {
6094             res1 ~= a;
6095             res2 ~= b;
6096         }
6097 
6098         assert(res1 == [1,2,3,4,5]);
6099         assert(res2 == [6,7,8,9,10]);
6100         assert(bar == [6f,7f,8f,9f,10f]);
6101     }
6102 
6103     // Doc example.
6104     auto arr1 = [1,2,3,4,5];
6105     auto arr2 = [6,7,8,9,10];
6106 
6107     foreach (ref a, ref b; lockstep(arr1, arr2))
6108     {
6109         a += b;
6110     }
6111 
6112     assert(arr1 == [7,9,11,13,15]);
6113 
6114     // Make sure StoppingPolicy.requireSameLength doesn't throw.
6115     auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6116 
6117     int k = 1;
6118     foreach (a, b; ls)
6119     {
6120         assert(a - b == k);
6121         ++k;
6122     }
6123 
6124     // Make sure StoppingPolicy.requireSameLength throws.
6125     arr2.popBack();
6126     ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6127 
6128     try {
6129         foreach (a, b; ls) {}
6130         assert(0);
6131     } catch (Exception) {}
6132 
6133     // Just make sure 1-range case instantiates. This hangs the compiler
6134     // when no explicit stopping policy is specified due to
6135     // https://issues.dlang.org/show_bug.cgi?id=4652
6136     auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
6137     foreach (i, a; stuff)
6138     {
6139         assert(stuff[i] == a);
6140     }
6141 
6142     // Test with indexing.
6143     uint[] res1;
6144     float[] res2;
6145     size_t[] indices;
6146     foreach (i, a, b; lockstep(foo, bar))
6147     {
6148         indices ~= i;
6149         res1 ~= a;
6150         res2 ~= b;
6151     }
6152 
6153     assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
6154     assert(res1 == [1,2,3,4,5]);
6155     assert(res2 == [6f,7f,8f,9f,10f]);
6156 
6157     // Make sure we've worked around the relevant compiler bugs and this at least
6158     // compiles w/ >2 ranges.
6159     lockstep(foo, foo, foo);
6160 
6161     // Make sure it works with const.
6162     const(int[])[] foo2 = [[1, 2, 3]];
6163     const(int[])[] bar2 = [[4, 5, 6]];
6164     auto c = chain(foo2, bar2);
6165 
6166     foreach (f, b; lockstep(c, c)) {}
6167 
6168     // Regression 10468
6169     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
6170 }
6171 
6172 @system unittest
6173 {
6174     struct RvalueRange
6175     {
6176         int[] impl;
6177         @property bool empty() { return impl.empty; }
6178         @property int front() { return impl[0]; } // N.B. non-ref
6179         void popFront() { impl.popFront(); }
6180     }
6181     auto data1 = [ 1, 2, 3, 4 ];
6182     auto data2 = [ 5, 6, 7, 8 ];
6183     auto r1 = RvalueRange(data1);
6184     auto r2 = data2;
6185     foreach (a, ref b; lockstep(r1, r2))
6186     {
6187         a++;
6188         b++;
6189     }
6190     assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
6191     assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
6192 
6193     // Since r1 is by-value only, the compiler should reject attempts to
6194     // foreach over it with ref.
6195     static assert(!__traits(compiles, {
6196         foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
6197     }));
6198 }
6199 
6200 private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
6201 {
6202     import std.format : format;
6203     string[] params;
6204     string message;
6205 
6206     if (withIndex)
6207     {
6208         message = "Indexed reverse iteration with lockstep is only supported"
6209         ~"if all ranges are bidirectional and have a length.\n";
6210     }
6211     else
6212     {
6213         message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
6214     }
6215 
6216     if (withIndex)
6217     {
6218         params ~= "size_t";
6219     }
6220 
6221     foreach (idx, Range; Ranges)
6222     {
6223         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6224     }
6225 
6226     return format(
6227     q{
6228         int opApplyReverse()(scope int delegate(%s) dg)
6229         {
6230             static assert(false, "%s");
6231         }
6232     }, params.join(", "), message);
6233 }
6234 
6235 // For generic programming, make sure Lockstep!(Range) is well defined for a
6236 // single range.
6237 template Lockstep(Range)
6238 {
6239     alias Lockstep = Range;
6240 }
6241 
6242 /**
6243 Creates a mathematical sequence given the initial values and a
6244 recurrence function that computes the next value from the existing
6245 values. The sequence comes in the form of an infinite forward
6246 range. The type `Recurrence` itself is seldom used directly; most
6247 often, recurrences are obtained by calling the function $(D
6248 recurrence).
6249 
6250 When calling `recurrence`, the function that computes the next
6251 value is specified as a template argument, and the initial values in
6252 the recurrence are passed as regular arguments. For example, in a
6253 Fibonacci sequence, there are two initial values (and therefore a
6254 state size of 2) because computing the next Fibonacci value needs the
6255 past two values.
6256 
6257 The signature of this function should be:
6258 ----
6259 auto fun(R)(R state, size_t n)
6260 ----
6261 where `n` will be the index of the current value, and `state` will be an
6262 opaque state vector that can be indexed with array-indexing notation
6263 `state[i]`, where valid values of `i` range from $(D (n - 1)) to
6264 $(D (n - State.length)).
6265 
6266 If the function is passed in string form, the state has name `"a"`
6267 and the zero-based index in the recurrence has name `"n"`. The
6268 given string must return the desired value for `a[n]` given
6269 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
6270 state size is dictated by the number of arguments passed to the call
6271 to `recurrence`. The `Recurrence` struct itself takes care of
6272 managing the recurrence's state and shifting it appropriately.
6273  */
6274 struct Recurrence(alias fun, StateType, size_t stateSize)
6275 {
6276     import std.functional : binaryFun;
6277 
6278     StateType[stateSize] _state;
6279     size_t _n;
6280 
6281     this(StateType[stateSize] initial) { _state = initial; }
6282 
6283     void popFront()
6284     {
6285         static auto trustedCycle(ref typeof(_state) s) @trusted
6286         {
6287             return cycle(s);
6288         }
6289         // The cast here is reasonable because fun may cause integer
6290         // promotion, but needs to return a StateType to make its operation
6291         // closed.  Therefore, we have no other choice.
6292         _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
6293             trustedCycle(_state), _n + stateSize);
6294         ++_n;
6295     }
6296 
6297     @property StateType front()
6298     {
6299         return _state[_n % stateSize];
6300     }
6301 
6302     @property typeof(this) save()
6303     {
6304         return this;
6305     }
6306 
6307     enum bool empty = false;
6308 }
6309 
6310 ///
6311 pure @safe nothrow unittest
6312 {
6313     import std.algorithm.comparison : equal;
6314 
6315     // The Fibonacci numbers, using function in string form:
6316     // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
6317     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6318     assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
6319 
6320     // The factorials, using function in lambda form:
6321     auto fac = recurrence!((a,n) => a[n-1] * n)(1);
6322     assert(take(fac, 10).equal([
6323         1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
6324     ]));
6325 
6326     // The triangular numbers, using function in explicit form:
6327     static size_t genTriangular(R)(R state, size_t n)
6328     {
6329         return state[n-1] + n;
6330     }
6331     auto tri = recurrence!genTriangular(0);
6332     assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
6333 }
6334 
6335 /// Ditto
6336 Recurrence!(fun, CommonType!(State), State.length)
6337 recurrence(alias fun, State...)(State initial)
6338 {
6339     CommonType!(State)[State.length] state;
6340     foreach (i, Unused; State)
6341     {
6342         state[i] = initial[i];
6343     }
6344     return typeof(return)(state);
6345 }
6346 
6347 pure @safe nothrow unittest
6348 {
6349     import std.algorithm.comparison : equal;
6350 
6351     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6352     static assert(isForwardRange!(typeof(fib)));
6353 
6354     int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
6355     assert(equal(take(fib, 10), witness));
6356     foreach (e; take(fib, 10)) {}
6357     auto fact = recurrence!("n * a[n-1]")(1);
6358     assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
6359                             2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
6360     auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
6361     foreach (e; take(piapprox, 20)) {}
6362     // Thanks to yebblies for this test and the associated fix
6363     auto r = recurrence!"a[n-2]"(1, 2);
6364     witness = [1, 2, 1, 2, 1];
6365     assert(equal(take(r, 5), witness));
6366 }
6367 
6368 /**
6369    `Sequence` is similar to `Recurrence` except that iteration is
6370    presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
6371    closed form). This means that the `n`th element in the series is
6372    computable directly from the initial values and `n` itself. This
6373    implies that the interface offered by `Sequence` is a random-access
6374    range, as opposed to the regular `Recurrence`, which only offers
6375    forward iteration.
6376 
6377    The state of the sequence is stored as a `Tuple` so it can be
6378    heterogeneous.
6379 */
6380 struct Sequence(alias fun, State)
6381 {
6382 private:
6383     import std.functional : binaryFun;
6384 
6385     alias compute = binaryFun!(fun, "a", "n");
6386     alias ElementType = typeof(compute(State.init, cast(size_t) 1));
6387     State _state;
6388     size_t _n;
6389 
6390     static struct DollarToken{}
6391 
6392 public:
6393     this(State initial, size_t n = 0)
6394     {
6395         _state = initial;
6396         _n = n;
6397     }
6398 
6399     @property ElementType front()
6400     {
6401         return compute(_state, _n);
6402     }
6403 
6404     void popFront()
6405     {
6406         ++_n;
6407     }
6408 
6409     enum opDollar = DollarToken();
6410 
6411     auto opSlice(size_t lower, size_t upper)
6412     in
6413     {
6414         assert(
6415             upper >= lower,
6416             "Attempting to slice a Sequence with a larger first argument than the second."
6417         );
6418     }
6419     do
6420     {
6421         return typeof(this)(_state, _n + lower).take(upper - lower);
6422     }
6423 
6424     auto opSlice(size_t lower, DollarToken)
6425     {
6426         return typeof(this)(_state, _n + lower);
6427     }
6428 
6429     ElementType opIndex(size_t n)
6430     {
6431         return compute(_state, n + _n);
6432     }
6433 
6434     enum bool empty = false;
6435 
6436     @property Sequence save() { return this; }
6437 }
6438 
6439 /// Ditto
6440 auto sequence(alias fun, State...)(State args)
6441 {
6442     import std.typecons : Tuple, tuple;
6443     alias Return = Sequence!(fun, Tuple!State);
6444     return Return(tuple(args));
6445 }
6446 
6447 /// Odd numbers, using function in string form:
6448 pure @safe nothrow @nogc unittest
6449 {
6450     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6451     assert(odds.front == 1);
6452     odds.popFront();
6453     assert(odds.front == 3);
6454     odds.popFront();
6455     assert(odds.front == 5);
6456 }
6457 
6458 /// Triangular numbers, using function in lambda form:
6459 pure @safe nothrow @nogc unittest
6460 {
6461     auto tri = sequence!((a,n) => n*(n+1)/2)();
6462 
6463     // Note random access
6464     assert(tri[0] == 0);
6465     assert(tri[3] == 6);
6466     assert(tri[1] == 1);
6467     assert(tri[4] == 10);
6468     assert(tri[2] == 3);
6469 }
6470 
6471 /// Fibonacci numbers, using function in explicit form:
6472 @safe nothrow @nogc unittest
6473 {
6474     import std.math.exponential : pow;
6475     import std.math.rounding : round;
6476     import std.math.algebraic : sqrt;
6477     static ulong computeFib(S)(S state, size_t n)
6478     {
6479         // Binet's formula
6480         return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6481                                  state[2]));
6482     }
6483     auto fib = sequence!computeFib(
6484         (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
6485         (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
6486         sqrt(5.0));
6487 
6488     // Note random access with [] operator
6489     assert(fib[1] == 1);
6490     assert(fib[4] == 5);
6491     assert(fib[3] == 3);
6492     assert(fib[2] == 2);
6493     assert(fib[9] == 55);
6494 }
6495 
6496 pure @safe nothrow @nogc unittest
6497 {
6498     import std.typecons : Tuple, tuple;
6499     auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6500     static assert(isForwardRange!(typeof(y)));
6501 
6502     //@@BUG
6503     //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6504     //foreach (e; take(y, 15))
6505     {}                                 //writeln(e);
6506 
6507     auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6508         tuple(1, 2));
6509     for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6510     {
6511         assert(odds.front == odds[0]);
6512         assert(odds[0] == currentOdd);
6513         odds.popFront();
6514     }
6515 }
6516 
6517 pure @safe nothrow @nogc unittest
6518 {
6519     import std.algorithm.comparison : equal;
6520 
6521     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6522     static assert(hasSlicing!(typeof(odds)));
6523 
6524     //Note: don't use drop or take as the target of an equal,
6525     //since they'll both just forward to opSlice, making the tests irrelevant
6526 
6527     // static slicing tests
6528     assert(equal(odds[0 .. 5], only(1,  3,  5,  7,  9)));
6529     assert(equal(odds[3 .. 7], only(7,  9, 11, 13)));
6530 
6531     // relative slicing test, testing slicing is NOT agnostic of state
6532     auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6533     assert(equal(odds_less5[0 ..  3], only(11, 13, 15)));
6534     assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6535 
6536     //Infinite slicing tests
6537     odds = odds[10 .. $];
6538     assert(equal(odds.take(3), only(21, 23, 25)));
6539 }
6540 
6541 // https://issues.dlang.org/show_bug.cgi?id=5036
6542 pure @safe nothrow unittest
6543 {
6544     auto s = sequence!((a, n) => new int)(0);
6545     assert(s.front != s.front);  // no caching
6546 }
6547 
6548 // iota
6549 /**
6550    Creates a range of values that span the given starting and stopping
6551    values.
6552 
6553    Params:
6554    begin = The starting value.
6555    end = The value that serves as the stopping criterion. This value is not
6556         included in the range.
6557    step = The value to add to the current value at each iteration.
6558 
6559    Returns:
6560    A range that goes through the numbers `begin`, $(D begin + step),
6561    $(D begin + 2 * step), `...`, up to and excluding `end`.
6562 
6563    The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6564    0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6565    is returned. If $(D step == 0) then $(D begin == end) is an error.
6566 
6567    For built-in types, the range returned is a random access range. For
6568    user-defined types that support `++`, the range is an input
6569    range.
6570 
6571    An integral iota also supports `in` operator from the right. It takes
6572    the stepping into account, the integral won't be considered
6573    contained if it falls between two consecutive values of the range.
6574    `contains` does the same as in, but from lefthand side.
6575 
6576     Example:
6577     ---
6578     void main()
6579     {
6580         import std.stdio;
6581 
6582         // The following groups all produce the same output of:
6583         // 0 1 2 3 4
6584 
6585         foreach (i; 0 .. 5)
6586             writef("%s ", i);
6587         writeln();
6588 
6589         import std.range : iota;
6590         foreach (i; iota(0, 5))
6591             writef("%s ", i);
6592         writeln();
6593 
6594         writefln("%(%s %|%)", iota(0, 5));
6595 
6596         import std.algorithm.iteration : map;
6597         import std.algorithm.mutation : copy;
6598         import std.format;
6599         iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6600         writeln();
6601     }
6602     ---
6603 */
6604 auto iota(B, E, S)(B begin, E end, S step)
6605 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6606         && isIntegral!S)
6607 {
6608     import std.conv : unsigned;
6609 
6610     alias Value = CommonType!(Unqual!B, Unqual!E);
6611     alias StepType = Unqual!S;
6612 
6613     assert(step != 0 || begin == end);
6614 
6615     static struct Result
6616     {
6617         private Value current, last;
6618         private StepType step; // by convention, 0 if range is empty
6619 
6620         this(Value current, Value pastLast, StepType step)
6621         {
6622             if (current < pastLast && step > 0)
6623             {
6624                 // Iterating upward
6625                 assert(unsigned((pastLast - current) / step) <= size_t.max);
6626                 // Cast below can't fail because current < pastLast
6627                 this.last = cast(Value) (pastLast - 1);
6628                 this.last -= unsigned(this.last - current) % step;
6629             }
6630             else if (current > pastLast && step < 0)
6631             {
6632                 // Iterating downward
6633                 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6634                 // Cast below can't fail because current > pastLast
6635                 this.last = cast(Value) (pastLast + 1);
6636                 this.last += unsigned(current - this.last) % (0 - step);
6637             }
6638             else
6639             {
6640                 // Initialize an empty range
6641                 this.step = 0;
6642                 return;
6643             }
6644             this.step = step;
6645             this.current = current;
6646         }
6647 
6648         @property bool empty() const { return step == 0; }
6649         @property inout(Value) front() inout { assert(!empty); return current; }
6650         void popFront()
6651         {
6652             assert(!empty);
6653             if (current == last) step = 0;
6654             else current += step;
6655         }
6656 
6657         @property inout(Value) back() inout
6658         {
6659             assert(!empty);
6660             return last;
6661         }
6662         void popBack()
6663         {
6664             assert(!empty);
6665             if (current == last) step = 0;
6666             else last -= step;
6667         }
6668 
6669         @property auto save() { return this; }
6670 
6671         inout(Value) opIndex(ulong n) inout
6672         {
6673             assert(n < this.length);
6674 
6675             // Just cast to Value here because doing so gives overflow behavior
6676             // consistent with calling popFront() n times.
6677             return cast(inout Value) (current + step * n);
6678         }
6679         auto opBinaryRight(string op)(Value val) const
6680         if (op == "in")
6681         {
6682             if (empty) return false;
6683             //cast to avoid becoming unsigned
6684             auto supposedIndex = cast(StepType)(val - current) / step;
6685             return supposedIndex < length && supposedIndex * step + current == val;
6686         }
6687         auto contains(Value x){return x in this;}
6688         inout(Result) opSlice() inout { return this; }
6689         inout(Result) opSlice(ulong lower, ulong upper) inout
6690         {
6691             assert(upper >= lower && upper <= this.length);
6692 
6693             return cast(inout Result) Result(
6694                 cast(Value)(current + lower * step),
6695                 cast(Value)(current + upper * step),
6696                 step);
6697         }
6698         @property size_t length() const
6699         {
6700             if (step > 0)
6701                 return 1 + cast(size_t) (unsigned(last - current) / step);
6702             if (step < 0)
6703                 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6704             return 0;
6705         }
6706 
6707         alias opDollar = length;
6708     }
6709 
6710     return Result(begin, end, step);
6711 }
6712 
6713 /// Ditto
6714 auto iota(B, E)(B begin, E end)
6715 if (isFloatingPoint!(CommonType!(B, E)))
6716 {
6717     return iota(begin, end, CommonType!(B, E)(1));
6718 }
6719 
6720 /// Ditto
6721 auto iota(B, E)(B begin, E end)
6722 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6723 {
6724     import std.conv : unsigned;
6725 
6726     alias Value = CommonType!(Unqual!B, Unqual!E);
6727 
6728     static struct Result
6729     {
6730         private Value current, pastLast;
6731 
6732         this(Value current, Value pastLast)
6733         {
6734             if (current < pastLast)
6735             {
6736                 assert(unsigned(pastLast - current) <= size_t.max,
6737                     "`iota` range is too long");
6738 
6739                 this.current = current;
6740                 this.pastLast = pastLast;
6741             }
6742             else
6743             {
6744                 // Initialize an empty range
6745                 this.current = this.pastLast = current;
6746             }
6747         }
6748 
6749         @property bool empty() const { return current == pastLast; }
6750         @property inout(Value) front() inout
6751         {
6752             assert(!empty, "Attempt to access `front` of empty `iota` range");
6753             return current;
6754         }
6755         void popFront()
6756         {
6757             assert(!empty, "Attempt to `popFront` of empty `iota` range");
6758             ++current;
6759         }
6760 
6761         @property inout(Value) back() inout
6762         {
6763             assert(!empty, "Attempt to access `back` of empty `iota` range");
6764             return cast(inout(Value))(pastLast - 1);
6765         }
6766         void popBack()
6767         {
6768             assert(!empty, "Attempt to `popBack` of empty `iota` range");
6769             --pastLast;
6770         }
6771 
6772         @property auto save() { return this; }
6773 
6774         inout(Value) opIndex(size_t n) inout
6775         {
6776             assert(n < this.length,
6777                 "Attempt to read out-of-bounds index of `iota` range");
6778 
6779             // Just cast to Value here because doing so gives overflow behavior
6780             // consistent with calling popFront() n times.
6781             return cast(inout Value) (current + n);
6782         }
6783         auto opBinaryRight(string op)(Value val) const
6784         if (op == "in")
6785         {
6786             return current <= val && val < pastLast;
6787         }
6788         auto contains(Value x){return x in this;}
6789         inout(Result) opSlice() inout { return this; }
6790         inout(Result) opSlice(ulong lower, ulong upper) inout
6791         {
6792             assert(upper >= lower && upper <= this.length,
6793                 "Attempt to get out-of-bounds slice of `iota` range");
6794 
6795             return cast(inout Result) Result(cast(Value)(current + lower),
6796                                             cast(Value)(pastLast - (length - upper)));
6797         }
6798         @property size_t length() const
6799         {
6800             return cast(size_t)(pastLast - current);
6801         }
6802 
6803         alias opDollar = length;
6804     }
6805 
6806     return Result(begin, end);
6807 }
6808 
6809 /// Ditto
6810 auto iota(E)(E end)
6811 if (is(typeof(iota(E(0), end))))
6812 {
6813     E begin = E(0);
6814     return iota(begin, end);
6815 }
6816 
6817 /// Ditto
6818 // Specialization for floating-point types
6819 auto iota(B, E, S)(B begin, E end, S step)
6820 if (isFloatingPoint!(CommonType!(B, E, S)))
6821 in
6822 {
6823     assert(step != 0, "iota: step must not be 0");
6824     assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
6825 }
6826 do
6827 {
6828     alias Value = Unqual!(CommonType!(B, E, S));
6829     static struct Result
6830     {
6831         private Value start, step;
6832         private size_t index, count;
6833 
6834         this(Value start, Value end, Value step)
6835         {
6836             import std.conv : to;
6837 
6838             this.start = start;
6839             this.step = step;
6840             immutable fcount = (end - start) / step;
6841             count = to!size_t(fcount);
6842             auto pastEnd = start + count * step;
6843             if (step > 0)
6844             {
6845                 if (pastEnd < end) ++count;
6846                 assert(start + count * step >= end);
6847             }
6848             else
6849             {
6850                 if (pastEnd > end) ++count;
6851                 assert(start + count * step <= end);
6852             }
6853         }
6854 
6855         @property bool empty() const { return index == count; }
6856         @property Value front() const { assert(!empty); return start + step * index; }
6857         void popFront()
6858         {
6859             assert(!empty);
6860             ++index;
6861         }
6862         @property Value back() const
6863         {
6864             assert(!empty);
6865             return start + step * (count - 1);
6866         }
6867         void popBack()
6868         {
6869             assert(!empty);
6870             --count;
6871         }
6872 
6873         @property auto save() { return this; }
6874 
6875         Value opIndex(size_t n) const
6876         {
6877             assert(n < count);
6878             return start + step * (n + index);
6879         }
6880         inout(Result) opSlice() inout
6881         {
6882             return this;
6883         }
6884         inout(Result) opSlice(size_t lower, size_t upper) inout
6885         {
6886             assert(upper >= lower && upper <= count);
6887 
6888             Result ret = this;
6889             ret.index += lower;
6890             ret.count = upper - lower + ret.index;
6891             return cast(inout Result) ret;
6892         }
6893         @property size_t length() const
6894         {
6895             return count - index;
6896         }
6897 
6898         alias opDollar = length;
6899     }
6900 
6901     return Result(begin, end, step);
6902 }
6903 
6904 ///
6905 pure @safe unittest
6906 {
6907     import std.algorithm.comparison : equal;
6908     import std.math.operations : isClose;
6909 
6910     auto r = iota(0, 10, 1);
6911     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6912     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6913     assert(3 in r);
6914     assert(r.contains(3)); //Same as above
6915     assert(!(10 in r));
6916     assert(!(-8 in r));
6917     r = iota(0, 11, 3);
6918     assert(equal(r, [0, 3, 6, 9]));
6919     assert(r[2] == 6);
6920     assert(!(2 in r));
6921     auto rf = iota(0.0, 0.5, 0.1);
6922     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
6923 }
6924 
6925 pure nothrow @nogc @safe unittest
6926 {
6927     import std.traits : Signed;
6928    //float overloads use std.conv.to so can't be @nogc or nothrow
6929     alias ssize_t = Signed!size_t;
6930     assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
6931     assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
6932     assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
6933     assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
6934     assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
6935 }
6936 
6937 debug @system unittest
6938 {//check the contracts
6939     import core.exception : AssertError;
6940     import std.exception : assertThrown;
6941     assertThrown!AssertError(iota(1,2,0));
6942     assertThrown!AssertError(iota(0f,1f,0f));
6943     assertThrown!AssertError(iota(1f,0f,0.1f));
6944     assertThrown!AssertError(iota(0f,1f,-0.1f));
6945 }
6946 
6947 pure @system nothrow unittest
6948 {
6949     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6950     auto r1 = iota(a.ptr, a.ptr + a.length, 1);
6951     assert(r1.front == a.ptr);
6952     assert(r1.back == a.ptr + a.length - 1);
6953     assert(&a[4] in r1);
6954 }
6955 
6956 pure @safe nothrow @nogc unittest
6957 {
6958     assert(iota(1UL, 0UL).length == 0);
6959     assert(iota(1UL, 0UL, 1).length == 0);
6960     assert(iota(0, 1, 1).length == 1);
6961     assert(iota(1, 0, -1).length == 1);
6962     assert(iota(0, 1, -1).length == 0);
6963     assert(iota(ulong.max, 0).length == 0);
6964 }
6965 
6966 pure @safe unittest
6967 {
6968     import std.algorithm.comparison : equal;
6969     import std.algorithm.searching : count;
6970     import std.math.operations : isClose, nextUp, nextDown;
6971     import std.meta : AliasSeq;
6972 
6973     static assert(is(ElementType!(typeof(iota(0f))) == float));
6974 
6975     static assert(hasLength!(typeof(iota(0, 2))));
6976     auto r = iota(0, 10, 1);
6977     assert(r[$ - 1] == 9);
6978     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
6979 
6980     auto rSlice = r[2 .. 8];
6981     assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
6982 
6983     rSlice.popFront();
6984     assert(rSlice[0] == rSlice.front);
6985     assert(rSlice.front == 3);
6986 
6987     rSlice.popBack();
6988     assert(rSlice[rSlice.length - 1] == rSlice.back);
6989     assert(rSlice.back == 6);
6990 
6991     rSlice = r[0 .. 4];
6992     assert(equal(rSlice, [0, 1, 2, 3]));
6993     assert(3 in rSlice);
6994     assert(!(4 in rSlice));
6995 
6996     auto rr = iota(10);
6997     assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
6998 
6999     r = iota(0, -10, -1);
7000     assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
7001     rSlice = r[3 .. 9];
7002     assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
7003 
7004     r = iota(0, -6, -3);
7005     assert(equal(r, [0, -3][]));
7006     rSlice = r[1 .. 2];
7007     assert(equal(rSlice, [-3]));
7008 
7009     r = iota(0, -7, -3);
7010     assert(equal(r, [0, -3, -6][]));
7011     assert(0 in r);
7012     assert(-6 in r);
7013     rSlice = r[1 .. 3];
7014     assert(equal(rSlice, [-3, -6]));
7015     assert(!(0 in rSlice));
7016     assert(!(-2 in rSlice));
7017     assert(!(-5 in rSlice));
7018     assert(!(3 in rSlice));
7019     assert(!(-9 in rSlice));
7020 
7021     r = iota(0, 11, 3);
7022     assert(equal(r, [0, 3, 6, 9][]));
7023     assert(r[2] == 6);
7024     rSlice = r[1 .. 3];
7025     assert(equal(rSlice, [3, 6]));
7026 
7027     auto rf = iota(0.0, 0.5, 0.1);
7028     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
7029     assert(rf.length == 5);
7030 
7031     rf.popFront();
7032     assert(rf.length == 4);
7033 
7034     auto rfSlice = rf[1 .. 4];
7035     assert(rfSlice.length == 3);
7036     assert(isClose(rfSlice, [0.2, 0.3, 0.4]));
7037 
7038     rfSlice.popFront();
7039     assert(isClose(rfSlice[0], 0.3));
7040 
7041     rf.popFront();
7042     assert(rf.length == 3);
7043 
7044     rfSlice = rf[1 .. 3];
7045     assert(rfSlice.length == 2);
7046     assert(isClose(rfSlice, [0.3, 0.4]));
7047     assert(isClose(rfSlice[0], 0.3));
7048 
7049     // With something just above 0.5
7050     rf = iota(0.0, nextUp(0.5), 0.1);
7051     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
7052     rf.popBack();
7053     assert(rf[rf.length - 1] == rf.back);
7054     assert(isClose(rf.back, 0.4));
7055     assert(rf.length == 5);
7056 
7057     // going down
7058     rf = iota(0.0, -0.5, -0.1);
7059     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
7060     rfSlice = rf[2 .. 5];
7061     assert(isClose(rfSlice, [-0.2, -0.3, -0.4]));
7062 
7063     rf = iota(0.0, nextDown(-0.5), -0.1);
7064     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
7065 
7066     // iota of longs
7067     auto rl = iota(5_000_000L);
7068     assert(rl.length == 5_000_000L);
7069     assert(0 in rl);
7070     assert(4_000_000L in rl);
7071     assert(!(-4_000_000L in rl));
7072     assert(!(5_000_000L in rl));
7073 
7074     // iota of longs with steps
7075     auto iota_of_longs_with_steps = iota(50L, 101L, 10);
7076     assert(iota_of_longs_with_steps.length == 6);
7077     assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
7078 
7079     // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
7080     // Actually trying to consume it is the only way to find something is wrong
7081     // because the public properties are all correct.
7082     auto iota_zero_unsigned = iota(0, 0u, 3);
7083     assert(count(iota_zero_unsigned) == 0);
7084 
7085     // https://issues.dlang.org/show_bug.cgi?id=7982
7086     // unsigned reverse iota can be buggy if `.length` doesn't
7087     // take them into account
7088     assert(iota(10u, 0u, -1).length == 10);
7089     assert(iota(10u, 0u, -2).length == 5);
7090     assert(iota(uint.max, uint.max-10, -1).length == 10);
7091     assert(iota(uint.max, uint.max-10, -2).length == 5);
7092     assert(iota(uint.max, 0u, -1).length == uint.max);
7093 
7094     assert(20 in iota(20u, 10u, -2));
7095     assert(16 in iota(20u, 10u, -2));
7096     assert(!(15 in iota(20u, 10u, -2)));
7097     assert(!(10 in iota(20u, 10u, -2)));
7098     assert(!(uint.max in iota(20u, 10u, -1)));
7099     assert(!(int.min in iota(20u, 10u, -1)));
7100     assert(!(int.max in iota(20u, 10u, -1)));
7101 
7102 
7103     // https://issues.dlang.org/show_bug.cgi?id=8920
7104     static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
7105         int, uint, long, ulong))
7106     {{
7107         Type val;
7108         foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
7109         assert(val == 10);
7110     }}
7111 }
7112 
7113 pure @safe nothrow unittest
7114 {
7115     import std.algorithm.mutation : copy;
7116     auto idx = new size_t[100];
7117     copy(iota(0, idx.length), idx);
7118 }
7119 
7120 @safe unittest
7121 {
7122     import std.meta : AliasSeq;
7123     static foreach (range; AliasSeq!(iota(2, 27, 4),
7124                              iota(3, 9),
7125                              iota(2.7, 12.3, .1),
7126                              iota(3.2, 9.7)))
7127     {{
7128         const cRange = range;
7129         const e = cRange.empty;
7130         const f = cRange.front;
7131         const b = cRange.back;
7132         const i = cRange[2];
7133         const s1 = cRange[];
7134         const s2 = cRange[0 .. 3];
7135         const l = cRange.length;
7136     }}
7137 }
7138 
7139 @system unittest
7140 {
7141     //The ptr stuff can't be done at compile time, so we unfortunately end
7142     //up with some code duplication here.
7143     auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
7144 
7145     {
7146         const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
7147         const e = cRange.empty;
7148         const f = cRange.front;
7149         const b = cRange.back;
7150         const i = cRange[2];
7151         const s1 = cRange[];
7152         const s2 = cRange[0 .. 3];
7153         const l = cRange.length;
7154     }
7155 
7156     {
7157         const cRange = iota(arr.ptr, arr.ptr + arr.length);
7158         const e = cRange.empty;
7159         const f = cRange.front;
7160         const b = cRange.back;
7161         const i = cRange[2];
7162         const s1 = cRange[];
7163         const s2 = cRange[0 .. 3];
7164         const l = cRange.length;
7165     }
7166 }
7167 
7168 @nogc nothrow pure @safe unittest
7169 {
7170     {
7171         ushort start = 0, end = 10, step = 2;
7172         foreach (i; iota(start, end, step))
7173             static assert(is(typeof(i) == ushort));
7174     }
7175     {
7176         ubyte start = 0, end = 255, step = 128;
7177         uint x;
7178         foreach (i; iota(start, end, step))
7179         {
7180             static assert(is(typeof(i) == ubyte));
7181             ++x;
7182         }
7183         assert(x == 2);
7184     }
7185 }
7186 
7187 /* Generic overload that handles arbitrary types that support arithmetic
7188  * operations.
7189  *
7190  * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
7191  * as they can be incremented with `++` and compared with `<` or `==`.
7192  */
7193 /// ditto
7194 auto iota(B, E)(B begin, E end)
7195 if (!isIntegral!(CommonType!(B, E)) &&
7196     !isFloatingPoint!(CommonType!(B, E)) &&
7197     !isPointer!(CommonType!(B, E)) &&
7198     is(typeof((ref B b) { ++b; })) &&
7199     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
7200 {
7201     static struct Result
7202     {
7203         B current;
7204         E end;
7205 
7206         @property bool empty()
7207         {
7208             static if (is(typeof(B.init < E.init)))
7209                 return !(current < end);
7210             else static if (is(typeof(B.init != E.init)))
7211                 return current == end;
7212             else
7213                 static assert(0);
7214         }
7215         @property auto front() { return current; }
7216         void popFront()
7217         {
7218             assert(!empty);
7219             ++current;
7220         }
7221         @property auto save() { return this; }
7222     }
7223     return Result(begin, end);
7224 }
7225 
7226 @safe unittest
7227 {
7228     import std.algorithm.comparison : equal;
7229 
7230     // Test iota() for a type that only supports ++ and != but does not have
7231     // '<'-ordering.
7232     struct Cyclic(int wrapAround)
7233     {
7234         int current;
7235 
7236         this(int start) { current = start % wrapAround; }
7237 
7238         bool opEquals(Cyclic c) const { return current == c.current; }
7239         bool opEquals(int i) const { return current == i; }
7240         void opUnary(string op)() if (op == "++")
7241         {
7242             current = (current + 1) % wrapAround;
7243         }
7244     }
7245     alias Cycle5 = Cyclic!5;
7246 
7247     // Easy case
7248     auto i1 = iota(Cycle5(1), Cycle5(4));
7249     assert(i1.equal([1, 2, 3]));
7250 
7251     // Wraparound case
7252     auto i2 = iota(Cycle5(3), Cycle5(2));
7253     assert(i2.equal([3, 4, 0, 1 ]));
7254 }
7255 
7256 // https://issues.dlang.org/show_bug.cgi?id=23453
7257 @safe unittest
7258 {
7259     auto r = iota('a', 'z');
7260     static assert(isForwardRange!(typeof(r)));
7261 }
7262 
7263 /**
7264    Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
7265    (below).
7266 */
7267 enum TransverseOptions
7268 {
7269 /**
7270    When transversed, the elements of a range of ranges are assumed to
7271    have different lengths (e.g. a jagged array).
7272 */
7273     assumeJagged,                      //default
7274     /**
7275        The transversal enforces that the elements of a range of ranges have
7276        all the same length (e.g. an array of arrays, all having the same
7277        length). Checking is done once upon construction of the transversal
7278        range.
7279     */
7280         enforceNotJagged,
7281     /**
7282        The transversal assumes, without verifying, that the elements of a
7283        range of ranges have all the same length. This option is useful if
7284        checking was already done from the outside of the range.
7285     */
7286         assumeNotJagged,
7287 }
7288 
7289 ///
7290 @safe pure unittest
7291 {
7292     import std.algorithm.comparison : equal;
7293     import std.exception : assertThrown;
7294 
7295     auto arr = [[1, 2], [3, 4, 5]];
7296 
7297     auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
7298     assert(r1.equal([1, 3]));
7299 
7300     // throws on construction
7301     assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
7302 
7303     auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
7304     assert(r2.equal([1, 3]));
7305 
7306     // either assuming or checking for equal lengths makes
7307     // the result a random access range
7308     assert(r2[0] == 1);
7309     static assert(!__traits(compiles, r1[0]));
7310 }
7311 
7312 /**
7313    Given a range of ranges, iterate transversally through the first
7314    elements of each of the enclosed ranges.
7315 */
7316 struct FrontTransversal(Ror,
7317         TransverseOptions opt = TransverseOptions.assumeJagged)
7318 {
7319     alias RangeOfRanges = Unqual!(Ror);
7320     alias RangeType     = .ElementType!RangeOfRanges;
7321     alias ElementType   = .ElementType!RangeType;
7322 
7323     private void prime()
7324     {
7325         static if (opt == TransverseOptions.assumeJagged)
7326         {
7327             while (!_input.empty && _input.front.empty)
7328             {
7329                 _input.popFront();
7330             }
7331             static if (isBidirectionalRange!RangeOfRanges)
7332             {
7333                 while (!_input.empty && _input.back.empty)
7334                 {
7335                     _input.popBack();
7336                 }
7337             }
7338         }
7339     }
7340 
7341 /**
7342    Construction from an input.
7343 */
7344     this(RangeOfRanges input)
7345     {
7346         _input = input;
7347         prime();
7348         static if (opt == TransverseOptions.enforceNotJagged)
7349             // (isRandomAccessRange!RangeOfRanges
7350             //     && hasLength!RangeType)
7351         {
7352             import std.exception : enforce;
7353 
7354             if (empty) return;
7355             immutable commonLength = _input.front.length;
7356             foreach (e; _input)
7357             {
7358                 enforce(e.length == commonLength);
7359             }
7360         }
7361     }
7362 
7363 /**
7364    Forward range primitives.
7365 */
7366     static if (isInfinite!RangeOfRanges)
7367     {
7368         enum bool empty = false;
7369     }
7370     else
7371     {
7372         @property bool empty()
7373         {
7374             static if (opt != TransverseOptions.assumeJagged)
7375             {
7376                 if (!_input.empty)
7377                     return _input.front.empty;
7378             }
7379 
7380             return _input.empty;
7381         }
7382     }
7383 
7384     /// Ditto
7385     @property auto ref front()
7386     {
7387         assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
7388         return _input.front.front;
7389     }
7390 
7391     /// Ditto
7392     static if (hasMobileElements!RangeType)
7393     {
7394         ElementType moveFront()
7395         {
7396             return _input.front.moveFront();
7397         }
7398     }
7399 
7400     static if (hasAssignableElements!RangeType)
7401     {
7402         @property void front(ElementType val)
7403         {
7404             import std.algorithm.mutation : move;
7405 
7406             _input.front.front = move(val);
7407         }
7408     }
7409 
7410     /// Ditto
7411     void popFront()
7412     {
7413         assert(!empty, "Attempting to popFront an empty FrontTransversal");
7414         _input.popFront();
7415         prime();
7416     }
7417 
7418 /**
7419    Duplicates this `frontTransversal`. Note that only the encapsulating
7420    range of range will be duplicated. Underlying ranges will not be
7421    duplicated.
7422 */
7423     static if (isForwardRange!RangeOfRanges)
7424     {
7425         @property FrontTransversal save()
7426         {
7427             return FrontTransversal(_input.save);
7428         }
7429     }
7430 
7431     static if (isBidirectionalRange!RangeOfRanges)
7432     {
7433 /**
7434    Bidirectional primitives. They are offered if $(D
7435    isBidirectionalRange!RangeOfRanges).
7436 */
7437         @property auto ref back()
7438         {
7439             assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7440             return _input.back.front;
7441         }
7442         /// Ditto
7443         void popBack()
7444         {
7445             assert(!empty, "Attempting to popBack an empty FrontTransversal");
7446             _input.popBack();
7447             prime();
7448         }
7449 
7450         /// Ditto
7451         static if (hasMobileElements!RangeType)
7452         {
7453             ElementType moveBack()
7454             {
7455                 return _input.back.moveFront();
7456             }
7457         }
7458 
7459         static if (hasAssignableElements!RangeType)
7460         {
7461             @property void back(ElementType val)
7462             {
7463                 import std.algorithm.mutation : move;
7464 
7465                 _input.back.front = move(val);
7466             }
7467         }
7468     }
7469 
7470     static if (isRandomAccessRange!RangeOfRanges &&
7471             (opt == TransverseOptions.assumeNotJagged ||
7472                     opt == TransverseOptions.enforceNotJagged))
7473     {
7474 /**
7475    Random-access primitive. It is offered if $(D
7476    isRandomAccessRange!RangeOfRanges && (opt ==
7477    TransverseOptions.assumeNotJagged || opt ==
7478    TransverseOptions.enforceNotJagged)).
7479 */
7480         auto ref opIndex(size_t n)
7481         {
7482             return _input[n].front;
7483         }
7484 
7485         /// Ditto
7486         static if (hasMobileElements!RangeType)
7487         {
7488             ElementType moveAt(size_t n)
7489             {
7490                 return _input[n].moveFront();
7491             }
7492         }
7493         /// Ditto
7494         static if (hasAssignableElements!RangeType)
7495         {
7496             void opIndexAssign(ElementType val, size_t n)
7497             {
7498                 import std.algorithm.mutation : move;
7499 
7500                 _input[n].front = move(val);
7501             }
7502         }
7503         mixin ImplementLength!_input;
7504 
7505 /**
7506    Slicing if offered if `RangeOfRanges` supports slicing and all the
7507    conditions for supporting indexing are met.
7508 */
7509         static if (hasSlicing!RangeOfRanges)
7510         {
7511             typeof(this) opSlice(size_t lower, size_t upper)
7512             {
7513                 return typeof(this)(_input[lower .. upper]);
7514             }
7515         }
7516     }
7517 
7518     auto opSlice() { return this; }
7519 
7520 private:
7521     RangeOfRanges _input;
7522 }
7523 
7524 /// Ditto
7525 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7526     TransverseOptions opt = TransverseOptions.assumeJagged,
7527     RangeOfRanges)
7528 (RangeOfRanges rr)
7529 {
7530     return typeof(return)(rr);
7531 }
7532 
7533 ///
7534 pure @safe nothrow unittest
7535 {
7536     import std.algorithm.comparison : equal;
7537     int[][] x = new int[][2];
7538     x[0] = [1, 2];
7539     x[1] = [3, 4];
7540     auto ror = frontTransversal(x);
7541     assert(equal(ror, [ 1, 3 ][]));
7542 }
7543 
7544 @safe unittest
7545 {
7546     import std.algorithm.comparison : equal;
7547     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7548 
7549     static assert(is(FrontTransversal!(immutable int[][])));
7550 
7551     foreach (DummyType; AllDummyRanges)
7552     {
7553         auto dummies =
7554             [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7555 
7556         foreach (i, ref elem; dummies)
7557         {
7558             // Just violate the DummyRange abstraction to get what I want.
7559             elem.arr = elem.arr[i..$ - (3 - i)];
7560         }
7561 
7562         auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7563         static if (isForwardRange!DummyType)
7564         {
7565             static assert(isForwardRange!(typeof(ft)));
7566         }
7567 
7568         assert(equal(ft, [1, 2, 3, 4]));
7569 
7570         // Test slicing.
7571         assert(equal(ft[0 .. 2], [1, 2]));
7572         assert(equal(ft[1 .. 3], [2, 3]));
7573 
7574         assert(ft.front == ft.moveFront());
7575         assert(ft.back == ft.moveBack());
7576         assert(ft.moveAt(1) == ft[1]);
7577 
7578 
7579         // Test infiniteness propagation.
7580         static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7581 
7582         static if (DummyType.r == ReturnBy.Reference)
7583         {
7584             {
7585                 ft.front++;
7586                 scope(exit) ft.front--;
7587                 assert(dummies.front.front == 2);
7588             }
7589 
7590             {
7591                 ft.front = 5;
7592                 scope(exit) ft.front = 1;
7593                 assert(dummies[0].front == 5);
7594             }
7595 
7596             {
7597                 ft.back = 88;
7598                 scope(exit) ft.back = 4;
7599                 assert(dummies.back.front == 88);
7600             }
7601 
7602             {
7603                 ft[1] = 99;
7604                 scope(exit) ft[1] = 2;
7605                 assert(dummies[1].front == 99);
7606             }
7607         }
7608     }
7609 }
7610 
7611 // https://issues.dlang.org/show_bug.cgi?id=16363
7612 pure @safe nothrow unittest
7613 {
7614     import std.algorithm.comparison : equal;
7615 
7616     int[][] darr = [[0, 1], [4, 5]];
7617     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7618 
7619     assert(equal(ft, [0, 4]));
7620     static assert(isRandomAccessRange!(typeof(ft)));
7621 }
7622 
7623 // https://issues.dlang.org/show_bug.cgi?id=16442
7624 pure @safe nothrow unittest
7625 {
7626     int[][] arr = [[], []];
7627 
7628     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7629     assert(ft.empty);
7630 }
7631 
7632 // ditto
7633 pure @safe unittest
7634 {
7635     int[][] arr = [[], []];
7636 
7637     auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7638     assert(ft.empty);
7639 }
7640 
7641 /**
7642     Given a range of ranges, iterate transversally through the
7643     `n`th element of each of the enclosed ranges. This function
7644     is similar to `unzip` in other languages.
7645 
7646     Params:
7647         opt = Controls the assumptions the function makes about the lengths
7648         of the ranges
7649         rr = An input range of random access ranges
7650     Returns:
7651         At minimum, an input range. Range primitives such as bidirectionality
7652         and random access are given if the element type of `rr` provides them.
7653 */
7654 struct Transversal(Ror,
7655         TransverseOptions opt = TransverseOptions.assumeJagged)
7656 {
7657     private alias RangeOfRanges = Unqual!Ror;
7658     private alias InnerRange = ElementType!RangeOfRanges;
7659     private alias E = ElementType!InnerRange;
7660 
7661     private void prime()
7662     {
7663         static if (opt == TransverseOptions.assumeJagged)
7664         {
7665             while (!_input.empty && _input.front.length <= _n)
7666             {
7667                 _input.popFront();
7668             }
7669             static if (isBidirectionalRange!RangeOfRanges)
7670             {
7671                 while (!_input.empty && _input.back.length <= _n)
7672                 {
7673                     _input.popBack();
7674                 }
7675             }
7676         }
7677     }
7678 
7679 /**
7680    Construction from an input and an index.
7681 */
7682     this(RangeOfRanges input, size_t n)
7683     {
7684         _input = input;
7685         _n = n;
7686         prime();
7687         static if (opt == TransverseOptions.enforceNotJagged)
7688         {
7689             import std.exception : enforce;
7690 
7691             if (empty) return;
7692             immutable commonLength = _input.front.length;
7693             foreach (e; _input)
7694             {
7695                 enforce(e.length == commonLength);
7696             }
7697         }
7698     }
7699 
7700 /**
7701    Forward range primitives.
7702 */
7703     static if (isInfinite!(RangeOfRanges))
7704     {
7705         enum bool empty = false;
7706     }
7707     else
7708     {
7709         @property bool empty()
7710         {
7711             return _input.empty;
7712         }
7713     }
7714 
7715     /// Ditto
7716     @property auto ref front()
7717     {
7718         assert(!empty, "Attempting to fetch the front of an empty Transversal");
7719         return _input.front[_n];
7720     }
7721 
7722     /// Ditto
7723     static if (hasMobileElements!InnerRange)
7724     {
7725         E moveFront()
7726         {
7727             return _input.front.moveAt(_n);
7728         }
7729     }
7730 
7731     /// Ditto
7732     static if (hasAssignableElements!InnerRange)
7733     {
7734         @property void front(E val)
7735         {
7736             _input.front[_n] = val;
7737         }
7738     }
7739 
7740 
7741     /// Ditto
7742     void popFront()
7743     {
7744         assert(!empty, "Attempting to popFront an empty Transversal");
7745         _input.popFront();
7746         prime();
7747     }
7748 
7749     /// Ditto
7750     static if (isForwardRange!RangeOfRanges)
7751     {
7752         @property typeof(this) save()
7753         {
7754             auto ret = this;
7755             ret._input = _input.save;
7756             return ret;
7757         }
7758     }
7759 
7760     static if (isBidirectionalRange!RangeOfRanges)
7761     {
7762 /**
7763    Bidirectional primitives. They are offered if $(D
7764    isBidirectionalRange!RangeOfRanges).
7765 */
7766         @property auto ref back()
7767         {
7768             assert(!empty, "Attempting to fetch the back of an empty Transversal");
7769             return _input.back[_n];
7770         }
7771 
7772         /// Ditto
7773         void popBack()
7774         {
7775             assert(!empty, "Attempting to popBack an empty Transversal");
7776             _input.popBack();
7777             prime();
7778         }
7779 
7780         /// Ditto
7781         static if (hasMobileElements!InnerRange)
7782         {
7783             E moveBack()
7784             {
7785                 return _input.back.moveAt(_n);
7786             }
7787         }
7788 
7789         /// Ditto
7790         static if (hasAssignableElements!InnerRange)
7791         {
7792             @property void back(E val)
7793             {
7794                 _input.back[_n] = val;
7795             }
7796         }
7797 
7798     }
7799 
7800     static if (isRandomAccessRange!RangeOfRanges &&
7801             (opt == TransverseOptions.assumeNotJagged ||
7802                     opt == TransverseOptions.enforceNotJagged))
7803     {
7804 /**
7805    Random-access primitive. It is offered if $(D
7806    isRandomAccessRange!RangeOfRanges && (opt ==
7807    TransverseOptions.assumeNotJagged || opt ==
7808    TransverseOptions.enforceNotJagged)).
7809 */
7810         auto ref opIndex(size_t n)
7811         {
7812             return _input[n][_n];
7813         }
7814 
7815         /// Ditto
7816         static if (hasMobileElements!InnerRange)
7817         {
7818             E moveAt(size_t n)
7819             {
7820                 return _input[n].moveAt(_n);
7821             }
7822         }
7823 
7824         /// Ditto
7825         static if (hasAssignableElements!InnerRange)
7826         {
7827             void opIndexAssign(E val, size_t n)
7828             {
7829                 _input[n][_n] = val;
7830             }
7831         }
7832 
7833         mixin ImplementLength!_input;
7834 
7835 /**
7836    Slicing if offered if `RangeOfRanges` supports slicing and all the
7837    conditions for supporting indexing are met.
7838 */
7839         static if (hasSlicing!RangeOfRanges)
7840         {
7841             typeof(this) opSlice(size_t lower, size_t upper)
7842             {
7843                 return typeof(this)(_input[lower .. upper], _n);
7844             }
7845         }
7846     }
7847 
7848     auto opSlice() { return this; }
7849 
7850 private:
7851     RangeOfRanges _input;
7852     size_t _n;
7853 }
7854 
7855 /// Ditto
7856 Transversal!(RangeOfRanges, opt) transversal
7857 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
7858 (RangeOfRanges rr, size_t n)
7859 {
7860     return typeof(return)(rr, n);
7861 }
7862 
7863 ///
7864 @safe unittest
7865 {
7866     import std.algorithm.comparison : equal;
7867     int[][] x = new int[][2];
7868     x[0] = [1, 2];
7869     x[1] = [3, 4];
7870     auto ror = transversal(x, 1);
7871     assert(equal(ror, [ 2, 4 ]));
7872 }
7873 
7874 /// The following code does a full unzip
7875 @safe unittest
7876 {
7877     import std.algorithm.comparison : equal;
7878     import std.algorithm.iteration : map;
7879     int[][] y = [[1, 2, 3], [4, 5, 6]];
7880     auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
7881     assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
7882 }
7883 
7884 @safe unittest
7885 {
7886     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
7887 
7888     int[][] x = new int[][2];
7889     x[0] = [ 1, 2 ];
7890     x[1] = [3, 4];
7891     auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
7892     auto witness = [ 2, 4 ];
7893     uint i;
7894     foreach (e; ror) assert(e == witness[i++]);
7895     assert(i == 2);
7896     assert(ror.length == 2);
7897 
7898     static assert(is(Transversal!(immutable int[][])));
7899 
7900     // Make sure ref, assign is being propagated.
7901     {
7902         ror.front++;
7903         scope(exit) ror.front--;
7904         assert(x[0][1] == 3);
7905     }
7906     {
7907         ror.front = 5;
7908         scope(exit) ror.front = 2;
7909         assert(x[0][1] == 5);
7910         assert(ror.moveFront() == 5);
7911     }
7912     {
7913         ror.back = 999;
7914         scope(exit) ror.back = 4;
7915         assert(x[1][1] == 999);
7916         assert(ror.moveBack() == 999);
7917     }
7918     {
7919         ror[0] = 999;
7920         scope(exit) ror[0] = 2;
7921         assert(x[0][1] == 999);
7922         assert(ror.moveAt(0) == 999);
7923     }
7924 
7925     // Test w/o ref return.
7926     alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
7927     auto drs = [D.init, D.init];
7928     foreach (num; 0 .. 10)
7929     {
7930         auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
7931         assert(t[0] == t[1]);
7932         assert(t[1] == num + 1);
7933     }
7934 
7935     static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
7936 
7937     // Test slicing.
7938     auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
7939     auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
7940     assert(mat1[0] == 6);
7941     assert(mat1[1] == 10);
7942 }
7943 
7944 struct Transposed(RangeOfRanges,
7945     TransverseOptions opt = TransverseOptions.assumeJagged)
7946 if (isForwardRange!RangeOfRanges &&
7947     isInputRange!(ElementType!RangeOfRanges) &&
7948     hasAssignableElements!RangeOfRanges)
7949 {
7950     this(RangeOfRanges input)
7951     {
7952         this._input = input;
7953         static if (opt == TransverseOptions.enforceNotJagged)
7954         {
7955             import std.exception : enforce;
7956 
7957             if (empty) return;
7958             immutable commonLength = _input.front.length;
7959             foreach (e; _input)
7960             {
7961                 enforce(e.length == commonLength);
7962             }
7963         }
7964     }
7965 
7966     @property auto front()
7967     {
7968         import std.algorithm.iteration : filter, map;
7969         return _input.save
7970                      .filter!(a => !a.empty)
7971                      .map!(a => a.front);
7972     }
7973 
7974     void popFront()
7975     {
7976         // Advance the position of each subrange.
7977         auto r = _input.save;
7978         while (!r.empty)
7979         {
7980             auto e = r.front;
7981             if (!e.empty)
7982             {
7983                 e.popFront();
7984                 r.front = e;
7985             }
7986 
7987             r.popFront();
7988         }
7989     }
7990 
7991     static if (isRandomAccessRange!(ElementType!RangeOfRanges))
7992     {
7993         auto ref opIndex(size_t n)
7994         {
7995             return transversal!opt(_input, n);
7996         }
7997     }
7998 
7999     @property bool empty()
8000     {
8001         if (_input.empty) return true;
8002         foreach (e; _input.save)
8003         {
8004             if (!e.empty) return false;
8005         }
8006         return true;
8007     }
8008 
8009     auto opSlice() { return this; }
8010 
8011 private:
8012     RangeOfRanges _input;
8013 }
8014 
8015 @safe unittest
8016 {
8017     // Boundary case: transpose of empty range should be empty
8018     int[][] ror = [];
8019     assert(transposed(ror).empty);
8020 }
8021 
8022 // https://issues.dlang.org/show_bug.cgi?id=9507
8023 @safe unittest
8024 {
8025     import std.algorithm.comparison : equal;
8026 
8027     auto r = [[1,2], [3], [4,5], [], [6]];
8028     assert(r.transposed.equal!equal([
8029         [1, 3, 4, 6],
8030         [2, 5]
8031     ]));
8032 }
8033 
8034 // https://issues.dlang.org/show_bug.cgi?id=17742
8035 @safe unittest
8036 {
8037     import std.algorithm.iteration : map;
8038     import std.algorithm.comparison : equal;
8039     auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
8040     assert(ror[3][2] == 6);
8041     auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
8042     assert(result[2][3] == 6);
8043 
8044     auto x = [[1,2,3],[4,5,6]];
8045     auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
8046     assert(y.front.equal([1,4]));
8047     assert(y[0].equal([1,4]));
8048     assert(y[0][0] == 1);
8049     assert(y[1].equal([2,5]));
8050     assert(y[1][1] == 5);
8051 
8052     auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
8053     assert(yy.front.equal([1,4]));
8054     assert(yy[0].equal([1,4]));
8055     assert(yy[0][0] == 1);
8056     assert(yy[1].equal([2,5]));
8057     assert(yy[1][1] == 5);
8058 
8059     auto z = x.transposed; // assumeJagged
8060     assert(z.front.equal([1,4]));
8061     assert(z[0].equal([1,4]));
8062     assert(!is(typeof(z[0][0])));
8063 }
8064 
8065 @safe unittest
8066 {
8067     import std.exception : assertThrown;
8068 
8069     auto r = [[1,2], [3], [4,5], [], [6]];
8070     assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
8071 }
8072 
8073 /**
8074 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
8075 contains the $(I i)'th elements of the original subranges.
8076 
8077 Params:
8078     opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
8079     rr = Range of ranges
8080  */
8081 Transposed!(RangeOfRanges, opt) transposed
8082 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8083 (RangeOfRanges rr)
8084 if (isForwardRange!RangeOfRanges &&
8085     isInputRange!(ElementType!RangeOfRanges) &&
8086     hasAssignableElements!RangeOfRanges)
8087 {
8088     return Transposed!(RangeOfRanges, opt)(rr);
8089 }
8090 
8091 ///
8092 @safe unittest
8093 {
8094     import std.algorithm.comparison : equal;
8095     int[][] ror = [
8096         [1, 2, 3],
8097         [4, 5, 6]
8098     ];
8099     auto xp = transposed(ror);
8100     assert(equal!"a.equal(b)"(xp, [
8101         [1, 4],
8102         [2, 5],
8103         [3, 6]
8104     ]));
8105 }
8106 
8107 ///
8108 @safe unittest
8109 {
8110     int[][] x = new int[][2];
8111     x[0] = [1, 2];
8112     x[1] = [3, 4];
8113     auto tr = transposed(x);
8114     int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
8115     uint i;
8116 
8117     foreach (e; tr)
8118     {
8119         assert(array(e) == witness[i++]);
8120     }
8121 }
8122 
8123 // https://issues.dlang.org/show_bug.cgi?id=8764
8124 @safe unittest
8125 {
8126     import std.algorithm.comparison : equal;
8127     ulong[] t0 = [ 123 ];
8128 
8129     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
8130     assert(!is(typeof(transposed(t0[].chunks(1)))));
8131     assert(is(typeof(transposed(t0[].chunks(1).array()))));
8132 
8133     auto t1 = transposed(t0[].chunks(1).array());
8134     assert(equal!"a.equal(b)"(t1, [[123]]));
8135 }
8136 
8137 /**
8138 This struct takes two ranges, `source` and `indices`, and creates a view
8139 of `source` as if its elements were reordered according to `indices`.
8140 `indices` may include only a subset of the elements of `source` and
8141 may also repeat elements.
8142 
8143 `Source` must be a random access range.  The returned range will be
8144 bidirectional or random-access if `Indices` is bidirectional or
8145 random-access, respectively.
8146 */
8147 struct Indexed(Source, Indices)
8148 if (isRandomAccessRange!Source && isInputRange!Indices &&
8149     is(typeof(Source.init[ElementType!(Indices).init])))
8150 {
8151     this(Source source, Indices indices)
8152     {
8153         this._source = source;
8154         this._indices = indices;
8155     }
8156 
8157     /// Range primitives
8158     @property auto ref front()
8159     {
8160         assert(!empty, "Attempting to fetch the front of an empty Indexed");
8161         return _source[_indices.front];
8162     }
8163 
8164     /// Ditto
8165     void popFront()
8166     {
8167         assert(!empty, "Attempting to popFront an empty Indexed");
8168         _indices.popFront();
8169     }
8170 
8171     static if (isInfinite!Indices)
8172     {
8173         enum bool empty = false;
8174     }
8175     else
8176     {
8177         /// Ditto
8178         @property bool empty()
8179         {
8180             return _indices.empty;
8181         }
8182     }
8183 
8184     static if (isForwardRange!Indices)
8185     {
8186         /// Ditto
8187         @property typeof(this) save()
8188         {
8189             // Don't need to save _source because it's never consumed.
8190             return typeof(this)(_source, _indices.save);
8191         }
8192     }
8193 
8194     /// Ditto
8195     static if (hasAssignableElements!Source)
8196     {
8197         @property auto ref front(ElementType!Source newVal)
8198         {
8199             assert(!empty);
8200             return _source[_indices.front] = newVal;
8201         }
8202     }
8203 
8204 
8205     static if (hasMobileElements!Source)
8206     {
8207         /// Ditto
8208         auto moveFront()
8209         {
8210             assert(!empty);
8211             return _source.moveAt(_indices.front);
8212         }
8213     }
8214 
8215     static if (isBidirectionalRange!Indices)
8216     {
8217         /// Ditto
8218         @property auto ref back()
8219         {
8220             assert(!empty, "Attempting to fetch the back of an empty Indexed");
8221             return _source[_indices.back];
8222         }
8223 
8224         /// Ditto
8225         void popBack()
8226         {
8227            assert(!empty, "Attempting to popBack an empty Indexed");
8228            _indices.popBack();
8229         }
8230 
8231         /// Ditto
8232         static if (hasAssignableElements!Source)
8233         {
8234             @property auto ref back(ElementType!Source newVal)
8235             {
8236                 assert(!empty);
8237                 return _source[_indices.back] = newVal;
8238             }
8239         }
8240 
8241 
8242         static if (hasMobileElements!Source)
8243         {
8244             /// Ditto
8245             auto moveBack()
8246             {
8247                 assert(!empty);
8248                 return _source.moveAt(_indices.back);
8249             }
8250         }
8251     }
8252 
8253     mixin ImplementLength!_indices;
8254 
8255     static if (isRandomAccessRange!Indices)
8256     {
8257         /// Ditto
8258         auto ref opIndex(size_t index)
8259         {
8260             return _source[_indices[index]];
8261         }
8262 
8263         static if (hasSlicing!Indices)
8264         {
8265             /// Ditto
8266             typeof(this) opSlice(size_t a, size_t b)
8267             {
8268                 return typeof(this)(_source, _indices[a .. b]);
8269             }
8270         }
8271 
8272 
8273         static if (hasAssignableElements!Source)
8274         {
8275             /// Ditto
8276             auto opIndexAssign(ElementType!Source newVal, size_t index)
8277             {
8278                 return _source[_indices[index]] = newVal;
8279             }
8280         }
8281 
8282 
8283         static if (hasMobileElements!Source)
8284         {
8285             /// Ditto
8286             auto moveAt(size_t index)
8287             {
8288                 return _source.moveAt(_indices[index]);
8289             }
8290         }
8291     }
8292 
8293     // All this stuff is useful if someone wants to index an Indexed
8294     // without adding a layer of indirection.
8295 
8296     /**
8297     Returns the source range.
8298     */
8299     @property Source source()
8300     {
8301         return _source;
8302     }
8303 
8304     /**
8305     Returns the indices range.
8306     */
8307      @property Indices indices()
8308     {
8309         return _indices;
8310     }
8311 
8312     static if (isRandomAccessRange!Indices)
8313     {
8314         /**
8315         Returns the physical index into the source range corresponding to a
8316         given logical index.  This is useful, for example, when indexing
8317         an `Indexed` without adding another layer of indirection.
8318         */
8319         size_t physicalIndex(size_t logicalIndex)
8320         {
8321             return _indices[logicalIndex];
8322         }
8323 
8324         ///
8325         @safe unittest
8326         {
8327             auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8328             assert(ind.physicalIndex(0) == 1);
8329         }
8330     }
8331 
8332 private:
8333     Source _source;
8334     Indices _indices;
8335 
8336 }
8337 
8338 /// Ditto
8339 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
8340 {
8341     return typeof(return)(source, indices);
8342 }
8343 
8344 ///
8345 @safe unittest
8346 {
8347     import std.algorithm.comparison : equal;
8348     auto source = [1, 2, 3, 4, 5];
8349     auto indices = [4, 3, 1, 2, 0, 4];
8350     auto ind = indexed(source, indices);
8351     assert(equal(ind, [5, 4, 2, 3, 1, 5]));
8352     assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
8353 }
8354 
8355 @safe unittest
8356 {
8357     {
8358         auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8359         assert(ind.physicalIndex(0) == 1);
8360     }
8361 
8362     auto source = [1, 2, 3, 4, 5];
8363     auto indices = [4, 3, 1, 2, 0, 4];
8364     auto ind = indexed(source, indices);
8365 
8366     // When elements of indices are duplicated and Source has lvalue elements,
8367     // these are aliased in ind.
8368     ind[0]++;
8369     assert(ind[0] == 6);
8370     assert(ind[5] == 6);
8371 }
8372 
8373 @safe unittest
8374 {
8375     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
8376         propagatesRangeType, RangeType;
8377 
8378     foreach (DummyType; AllDummyRanges)
8379     {
8380         auto d = DummyType.init;
8381         auto r = indexed([1, 2, 3, 4, 5], d);
8382         static assert(propagatesRangeType!(DummyType, typeof(r)));
8383         static assert(propagatesLength!(DummyType, typeof(r)));
8384     }
8385 }
8386 
8387 /**
8388 This range iterates over fixed-sized chunks of size `chunkSize` of a
8389 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8390 `chunkSize` must be greater than zero.
8391 
8392 If `!isInfinite!Source` and `source.walkLength` is not evenly
8393 divisible by `chunkSize`, the back element of this range will contain
8394 fewer than `chunkSize` elements.
8395 
8396 If `Source` is a forward range, the resulting range will be forward ranges as
8397 well. Otherwise, the resulting chunks will be input ranges consuming the same
8398 input: iterating over `front` will shrink the chunk such that subsequent
8399 invocations of `front` will no longer return the full chunk, and calling
8400 `popFront` on the outer range will invalidate any lingering references to
8401 previous values of `front`.
8402 
8403 Params:
8404     source = Range from which the chunks will be selected
8405     chunkSize = Chunk size
8406 
8407 See_Also: $(LREF slide)
8408 
8409 Returns: Range of chunks.
8410 */
8411 struct Chunks(Source)
8412 if (isInputRange!Source)
8413 {
8414     static if (isForwardRange!Source)
8415     {
8416         /// Standard constructor
8417         this(Source source, size_t chunkSize)
8418         {
8419             assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8420             _source = source;
8421             _chunkSize = chunkSize;
8422         }
8423 
8424         /// Input range primitives. Always present.
8425         @property auto front()
8426         {
8427             assert(!empty, "Attempting to fetch the front of an empty Chunks");
8428             return _source.save.take(_chunkSize);
8429         }
8430 
8431         /// Ditto
8432         void popFront()
8433         {
8434             assert(!empty, "Attempting to popFront and empty Chunks");
8435             _source.popFrontN(_chunkSize);
8436         }
8437 
8438         static if (!isInfinite!Source)
8439             /// Ditto
8440             @property bool empty()
8441             {
8442                 return _source.empty;
8443             }
8444         else
8445             // undocumented
8446             enum empty = false;
8447 
8448         /// Forward range primitives. Only present if `Source` is a forward range.
8449         @property typeof(this) save()
8450         {
8451             return typeof(this)(_source.save, _chunkSize);
8452         }
8453 
8454         static if (hasLength!Source)
8455         {
8456             /// Length. Only if `hasLength!Source` is `true`
8457             @property size_t length()
8458             {
8459                 // Note: _source.length + _chunkSize may actually overflow.
8460                 // We cast to ulong to mitigate the problem on x86 machines.
8461                 // For x64 machines, we just suppose we'll never overflow.
8462                 // The "safe" code would require either an extra branch, or a
8463                 //   modulo operation, which is too expensive for such a rare case
8464                 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8465             }
8466             //Note: No point in defining opDollar here without slicing.
8467             //opDollar is defined below in the hasSlicing!Source section
8468         }
8469 
8470         static if (hasSlicing!Source)
8471         {
8472             //Used for various purposes
8473             private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8474 
8475             /**
8476             Indexing and slicing operations. Provided only if
8477             `hasSlicing!Source` is `true`.
8478              */
8479             auto opIndex(size_t index)
8480             {
8481                 immutable start = index * _chunkSize;
8482                 immutable end   = start + _chunkSize;
8483 
8484                 static if (isInfinite!Source)
8485                     return _source[start .. end];
8486                 else
8487                 {
8488                     import std.algorithm.comparison : min;
8489                     immutable len = _source.length;
8490                     assert(start < len, "chunks index out of bounds");
8491                     return _source[start .. min(end, len)];
8492                 }
8493             }
8494 
8495             /// Ditto
8496             static if (hasLength!Source)
8497                 typeof(this) opSlice(size_t lower, size_t upper)
8498                 {
8499                     import std.algorithm.comparison : min;
8500                     assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8501                     immutable len = _source.length;
8502                     return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8503                 }
8504             else static if (hasSliceToEnd)
8505                 //For slicing an infinite chunk, we need to slice the source to the end.
8506                 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8507                 {
8508                     assert(lower <= upper, "chunks slicing index out of bounds");
8509                     return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8510                 }
8511 
8512             static if (isInfinite!Source)
8513             {
8514                 static if (hasSliceToEnd)
8515                 {
8516                     private static struct DollarToken{}
8517                     DollarToken opDollar()
8518                     {
8519                         return DollarToken();
8520                     }
8521                     //Slice to dollar
8522                     typeof(this) opSlice(size_t lower, DollarToken)
8523                     {
8524                         return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8525                     }
8526                 }
8527             }
8528             else
8529             {
8530                 //Dollar token carries a static type, with no extra information.
8531                 //It can lazily transform into _source.length on algorithmic
8532                 //operations such as : chunks[$/2, $-1];
8533                 private static struct DollarToken
8534                 {
8535                     Chunks!Source* mom;
8536                     @property size_t momLength()
8537                     {
8538                         return mom.length;
8539                     }
8540                     alias momLength this;
8541                 }
8542                 DollarToken opDollar()
8543                 {
8544                     return DollarToken(&this);
8545                 }
8546 
8547                 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8548                 //1. Evaluate chunks.length
8549                 //2. Multiply by _chunksSize
8550                 //3. To finally just compare it (with min) to the original length of source (!)
8551                 //These overloads avoid that.
8552                 typeof(this) opSlice(DollarToken, DollarToken)
8553                 {
8554                     static if (hasSliceToEnd)
8555                         return chunks(_source[$ .. $], _chunkSize);
8556                     else
8557                     {
8558                         immutable len = _source.length;
8559                         return chunks(_source[len .. len], _chunkSize);
8560                     }
8561                 }
8562                 typeof(this) opSlice(size_t lower, DollarToken)
8563                 {
8564                     import std.algorithm.comparison : min;
8565                     assert(lower <= length, "chunks slicing index out of bounds");
8566                     static if (hasSliceToEnd)
8567                         return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8568                     else
8569                     {
8570                         immutable len = _source.length;
8571                         return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8572                     }
8573                 }
8574                 typeof(this) opSlice(DollarToken, size_t upper)
8575                 {
8576                     assert(upper == length, "chunks slicing index out of bounds");
8577                     return this[$ .. $];
8578                 }
8579             }
8580         }
8581 
8582         //Bidirectional range primitives
8583         static if (hasSlicing!Source && hasLength!Source)
8584         {
8585             /**
8586             Bidirectional range primitives. Provided only if both
8587             `hasSlicing!Source` and `hasLength!Source` are `true`.
8588              */
8589             @property auto back()
8590             {
8591                 assert(!empty, "back called on empty chunks");
8592                 immutable len = _source.length;
8593                 immutable start = (len - 1) / _chunkSize * _chunkSize;
8594                 return _source[start .. len];
8595             }
8596 
8597             /// Ditto
8598             void popBack()
8599             {
8600                 assert(!empty, "popBack() called on empty chunks");
8601                 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8602                 _source = _source[0 .. end];
8603             }
8604         }
8605 
8606     private:
8607         Source _source;
8608         size_t _chunkSize;
8609     }
8610     else // is input range only
8611     {
8612         import std.typecons : RefCounted;
8613 
8614         static struct Chunk
8615         {
8616             private RefCounted!Impl impl;
8617 
8618             @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8619             @property auto front() { return impl.r.front; }
8620             void popFront()
8621             {
8622                 assert(impl.curSizeLeft > 0 && !impl.r.empty);
8623                 impl.curSizeLeft--;
8624                 impl.r.popFront();
8625             }
8626         }
8627 
8628         static struct Impl
8629         {
8630             private Source r;
8631             private size_t chunkSize;
8632             private size_t curSizeLeft;
8633         }
8634 
8635         private RefCounted!Impl impl;
8636 
8637         private this(Source r, size_t chunkSize)
8638         {
8639             impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8640         }
8641 
8642         @property bool empty() { return impl.chunkSize == 0; }
8643         @property Chunk front() return { return Chunk(impl); }
8644 
8645         void popFront()
8646         {
8647             impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8648             if (!impl.r.empty)
8649                 impl.curSizeLeft = impl.chunkSize;
8650             else
8651                 impl.chunkSize = 0;
8652         }
8653 
8654         static assert(isInputRange!(typeof(this)));
8655     }
8656 }
8657 
8658 /// Ditto
8659 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8660 if (isInputRange!Source)
8661 {
8662     return typeof(return)(source, chunkSize);
8663 }
8664 
8665 ///
8666 @safe unittest
8667 {
8668     import std.algorithm.comparison : equal;
8669     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8670     auto chunks = chunks(source, 4);
8671     assert(chunks[0] == [1, 2, 3, 4]);
8672     assert(chunks[1] == [5, 6, 7, 8]);
8673     assert(chunks[2] == [9, 10]);
8674     assert(chunks.back == chunks[2]);
8675     assert(chunks.front == chunks[0]);
8676     assert(chunks.length == 3);
8677     assert(equal(retro(array(chunks)), array(retro(chunks))));
8678 }
8679 
8680 /// Non-forward input ranges are supported, but with limited semantics.
8681 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8682 {
8683     import std.algorithm.comparison : equal;
8684 
8685     int i;
8686 
8687     // The generator doesn't save state, so it cannot be a forward range.
8688     auto inputRange = generate!(() => ++i).take(10);
8689 
8690     // We can still process it in chunks, but it will be single-pass only.
8691     auto chunked = inputRange.chunks(2);
8692 
8693     assert(chunked.front.equal([1, 2]));
8694     assert(chunked.front.empty); // Iterating the chunk has consumed it
8695     chunked.popFront;
8696     assert(chunked.front.equal([3, 4]));
8697 }
8698 
8699 @system /*@safe*/ unittest
8700 {
8701     import std.algorithm.comparison : equal;
8702     import std.internal.test.dummyrange : ReferenceInputRange;
8703 
8704     auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
8705     auto r = new ReferenceInputRange!int(data).chunks(3);
8706     assert(r.equal!equal([
8707         [ 1, 2, 3 ],
8708         [ 4, 5, 6 ],
8709         [ 7, 8, 9 ],
8710         [ 10 ]
8711     ]));
8712 
8713     auto data2 = [ 1, 2, 3, 4, 5, 6 ];
8714     auto r2 = new ReferenceInputRange!int(data2).chunks(3);
8715     assert(r2.equal!equal([
8716         [ 1, 2, 3 ],
8717         [ 4, 5, 6 ]
8718     ]));
8719 
8720     auto data3 = [ 1, 2, 3, 4, 5 ];
8721     auto r3 = new ReferenceInputRange!int(data3).chunks(2);
8722     assert(r3.front.equal([1, 2]));
8723     r3.popFront();
8724     assert(!r3.empty);
8725     r3.popFront();
8726     assert(r3.front.equal([5]));
8727 }
8728 
8729 @safe unittest
8730 {
8731     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8732     auto chunks = chunks(source, 4);
8733     auto chunks2 = chunks.save;
8734     chunks.popFront();
8735     assert(chunks[0] == [5, 6, 7, 8]);
8736     assert(chunks[1] == [9, 10]);
8737     chunks2.popBack();
8738     assert(chunks2[1] == [5, 6, 7, 8]);
8739     assert(chunks2.length == 2);
8740 
8741     static assert(isRandomAccessRange!(typeof(chunks)));
8742 }
8743 
8744 @safe unittest
8745 {
8746     import std.algorithm.comparison : equal;
8747 
8748     //Extra toying with slicing and indexing.
8749     auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
8750     auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
8751 
8752     assert(chunks1.length == 5);
8753     assert(chunks2.length == 5);
8754     assert(chunks1[4] == [4]);
8755     assert(chunks2[4] == [4, 4]);
8756     assert(chunks1.back == [4]);
8757     assert(chunks2.back == [4, 4]);
8758 
8759     assert(chunks1[0 .. 1].equal([[0, 0]]));
8760     assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
8761     assert(chunks1[4 .. 5].equal([[4]]));
8762     assert(chunks2[4 .. 5].equal([[4, 4]]));
8763 
8764     assert(chunks1[0 .. 0].equal((int[][]).init));
8765     assert(chunks1[5 .. 5].equal((int[][]).init));
8766     assert(chunks2[5 .. 5].equal((int[][]).init));
8767 
8768     //Fun with opDollar
8769     assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
8770     assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
8771     assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
8772     assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
8773     assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
8774     assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
8775 
8776     assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
8777 }
8778 
8779 @safe unittest
8780 {
8781     import std.algorithm.comparison : equal;
8782     import std.algorithm.iteration : filter;
8783 
8784     //ForwardRange
8785     auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
8786     assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
8787 
8788     //InfiniteRange w/o RA
8789     auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
8790     assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
8791 
8792     //InfiniteRange w/ RA and slicing
8793     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
8794     auto oddsByPairs = odds.chunks(2);
8795     assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
8796 
8797     //Requires phobos#991 for Sequence to have slice to end
8798     static assert(hasSlicing!(typeof(odds)));
8799     assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
8800     assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
8801 }
8802 
8803 
8804 
8805 /**
8806 This range splits a `source` range into `chunkCount` chunks of
8807 approximately equal length. `Source` must be a forward range with
8808 known length.
8809 
8810 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
8811 The returned range will contain zero or more $(D source.length /
8812 chunkCount + 1) elements followed by $(D source.length / chunkCount)
8813 elements. If $(D source.length < chunkCount), some chunks will be empty.
8814 
8815 `chunkCount` must not be zero, unless `source` is also empty.
8816 */
8817 struct EvenChunks(Source)
8818 if (isForwardRange!Source && hasLength!Source)
8819 {
8820     /// Standard constructor
8821     this(Source source, size_t chunkCount)
8822     {
8823         assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
8824         _source = source;
8825         _chunkCount = chunkCount;
8826     }
8827 
8828     /// Forward range primitives. Always present.
8829     @property auto front()
8830     {
8831         assert(!empty, "Attempting to fetch the front of an empty evenChunks");
8832         return _source.save.take(_chunkPos(1));
8833     }
8834 
8835     /// Ditto
8836     void popFront()
8837     {
8838         assert(!empty, "Attempting to popFront an empty evenChunks");
8839         _source.popFrontN(_chunkPos(1));
8840         _chunkCount--;
8841     }
8842 
8843     /// Ditto
8844     @property bool empty()
8845     {
8846         return _chunkCount == 0;
8847     }
8848 
8849     /// Ditto
8850     @property typeof(this) save()
8851     {
8852         return typeof(this)(_source.save, _chunkCount);
8853     }
8854 
8855     /// Length
8856     @property size_t length() const
8857     {
8858         return _chunkCount;
8859     }
8860     //Note: No point in defining opDollar here without slicing.
8861     //opDollar is defined below in the hasSlicing!Source section
8862 
8863     static if (hasSlicing!Source)
8864     {
8865         /**
8866         Indexing, slicing and bidirectional operations and range primitives.
8867         Provided only if `hasSlicing!Source` is `true`.
8868          */
8869         auto opIndex(size_t index)
8870         {
8871             assert(index < _chunkCount, "evenChunks index out of bounds");
8872             return _source[_chunkPos(index) .. _chunkPos(index+1)];
8873         }
8874 
8875         /// Ditto
8876         typeof(this) opSlice(size_t lower, size_t upper)
8877         {
8878             assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
8879             return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
8880         }
8881 
8882         /// Ditto
8883         @property auto back()
8884         {
8885             assert(!empty, "back called on empty evenChunks");
8886             return _source[_chunkPos(_chunkCount - 1) .. _source.length];
8887         }
8888 
8889         /// Ditto
8890         void popBack()
8891         {
8892             assert(!empty, "popBack() called on empty evenChunks");
8893             _source = _source[0 .. _chunkPos(_chunkCount - 1)];
8894             _chunkCount--;
8895         }
8896     }
8897 
8898 private:
8899     Source _source;
8900     size_t _chunkCount;
8901 
8902     size_t _chunkPos(size_t i)
8903     {
8904         /*
8905             _chunkCount = 5, _source.length = 13:
8906 
8907                chunk0
8908                  |   chunk3
8909                  |     |
8910                  v     v
8911                 +-+-+-+-+-+   ^
8912                 |0|3|.| | |   |
8913                 +-+-+-+-+-+   | div
8914                 |1|4|.| | |   |
8915                 +-+-+-+-+-+   v
8916                 |2|5|.|
8917                 +-+-+-+
8918 
8919                 <----->
8920                   mod
8921 
8922                 <--------->
8923                 _chunkCount
8924 
8925             One column is one chunk.
8926             popFront and popBack pop the left-most
8927             and right-most column, respectively.
8928         */
8929 
8930         auto div = _source.length / _chunkCount;
8931         auto mod = _source.length % _chunkCount;
8932         auto pos = i <= mod
8933             ? i   * (div+1)
8934             : mod * (div+1) + (i-mod) * div
8935         ;
8936         //auto len = i < mod
8937         //    ? div+1
8938         //    : div
8939         //;
8940         return pos;
8941     }
8942 }
8943 
8944 /// Ditto
8945 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
8946 if (isForwardRange!Source && hasLength!Source)
8947 {
8948     return typeof(return)(source, chunkCount);
8949 }
8950 
8951 ///
8952 @safe unittest
8953 {
8954     import std.algorithm.comparison : equal;
8955     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8956     auto chunks = evenChunks(source, 3);
8957     assert(chunks[0] == [1, 2, 3, 4]);
8958     assert(chunks[1] == [5, 6, 7]);
8959     assert(chunks[2] == [8, 9, 10]);
8960 }
8961 
8962 @safe unittest
8963 {
8964     import std.algorithm.comparison : equal;
8965 
8966     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8967     auto chunks = evenChunks(source, 3);
8968     assert(chunks.back == chunks[2]);
8969     assert(chunks.front == chunks[0]);
8970     assert(chunks.length == 3);
8971     assert(equal(retro(array(chunks)), array(retro(chunks))));
8972 
8973     auto chunks2 = chunks.save;
8974     chunks.popFront();
8975     assert(chunks[0] == [5, 6, 7]);
8976     assert(chunks[1] == [8, 9, 10]);
8977     chunks2.popBack();
8978     assert(chunks2[1] == [5, 6, 7]);
8979     assert(chunks2.length == 2);
8980 
8981     static assert(isRandomAccessRange!(typeof(chunks)));
8982 }
8983 
8984 @safe unittest
8985 {
8986     import std.algorithm.comparison : equal;
8987 
8988     int[] source = [];
8989     auto chunks = source.evenChunks(0);
8990     assert(chunks.length == 0);
8991     chunks = source.evenChunks(3);
8992     assert(equal(chunks, [[], [], []]));
8993     chunks = [1, 2, 3].evenChunks(5);
8994     assert(equal(chunks, [[1], [2], [3], [], []]));
8995 }
8996 
8997 /**
8998 A fixed-sized sliding window iteration
8999 of size `windowSize` over a `source` range by a custom `stepSize`.
9000 
9001 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
9002 and the `windowSize` must be greater than zero.
9003 
9004 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
9005 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
9006 
9007 Params:
9008     f = Whether the last element has fewer elements than `windowSize`
9009         it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
9010     source = Range from which the slide will be selected
9011     windowSize = Sliding window size
9012     stepSize = Steps between the windows (by default 1)
9013 
9014 Returns: Range of all sliding windows with propagated bi-directionality,
9015          forwarding, random access, and slicing.
9016 
9017 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
9018       is only available when $(REF hasSlicing, std,range,primitives)
9019       and $(REF hasLength, std,range,primitives) are true.
9020 
9021 See_Also: $(LREF chunks)
9022 */
9023 auto slide(Flag!"withPartial" f = Yes.withPartial,
9024             Source)(Source source, size_t windowSize, size_t stepSize = 1)
9025 if (isForwardRange!Source)
9026 {
9027     return Slides!(f, Source)(source, windowSize, stepSize);
9028 }
9029 
9030 /// Iterate over ranges with windows
9031 @safe pure nothrow unittest
9032 {
9033     import std.algorithm.comparison : equal;
9034 
9035     assert([0, 1, 2, 3].slide(2).equal!equal(
9036         [[0, 1], [1, 2], [2, 3]]
9037     ));
9038 
9039     assert(5.iota.slide(3).equal!equal(
9040         [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
9041     ));
9042 }
9043 
9044 /// set a custom stepsize (default 1)
9045 @safe pure nothrow unittest
9046 {
9047     import std.algorithm.comparison : equal;
9048 
9049     assert(6.iota.slide(1, 2).equal!equal(
9050         [[0], [2], [4]]
9051     ));
9052 
9053     assert(6.iota.slide(2, 4).equal!equal(
9054         [[0, 1], [4, 5]]
9055     ));
9056 
9057     assert(iota(7).slide(2, 2).equal!equal(
9058         [[0, 1], [2, 3], [4, 5], [6]]
9059     ));
9060 
9061     assert(iota(12).slide(2, 4).equal!equal(
9062         [[0, 1], [4, 5], [8, 9]]
9063     ));
9064 }
9065 
9066 /// Allow the last slide to have fewer elements than windowSize
9067 @safe pure nothrow unittest
9068 {
9069     import std.algorithm.comparison : equal;
9070 
9071     assert(3.iota.slide!(No.withPartial)(4).empty);
9072     assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
9073         [[0, 1, 2]]
9074     ));
9075 }
9076 
9077 /// Count all the possible substrings of length 2
9078 @safe pure nothrow unittest
9079 {
9080     import std.algorithm.iteration : each;
9081 
9082     int[dstring] d;
9083     "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
9084     assert(d == ["AG"d: 2, "GA"d: 2]);
9085 }
9086 
9087 /// withPartial only has an effect if last element in the range doesn't have the full size
9088 @safe pure nothrow unittest
9089 {
9090     import std.algorithm.comparison : equal;
9091 
9092     assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
9093     assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
9094     assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9095 
9096     assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9097     assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9098     assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9099 }
9100 
9101 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
9102 if (isForwardRange!Source)
9103 {
9104 private:
9105     Source source;
9106     size_t windowSize;
9107     size_t stepSize;
9108 
9109     static if (hasLength!Source)
9110     {
9111         enum needsEndTracker = false;
9112     }
9113     else
9114     {
9115         // If there's no information about the length, track needs to be kept manually
9116         Source nextSource;
9117         enum needsEndTracker = true;
9118     }
9119 
9120     bool _empty;
9121 
9122     static if (hasSlicing!Source)
9123         enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
9124 
9125     static if (withPartial)
9126         bool hasShownPartialBefore;
9127 
9128 public:
9129     /// Standard constructor
9130     this(Source source, size_t windowSize, size_t stepSize)
9131     {
9132         assert(windowSize > 0, "windowSize must be greater than zero");
9133         assert(stepSize > 0, "stepSize must be greater than zero");
9134         this.source = source;
9135         this.windowSize = windowSize;
9136         this.stepSize = stepSize;
9137 
9138         static if (needsEndTracker)
9139         {
9140             // `nextSource` is used to "look one step into the future" and check for the end
9141             // this means `nextSource` is advanced by `stepSize` on every `popFront`
9142             nextSource = source.save;
9143             auto poppedElems = nextSource.popFrontN(windowSize);
9144         }
9145 
9146         if (source.empty)
9147         {
9148             _empty = true;
9149             return;
9150         }
9151 
9152         static if (withPartial)
9153         {
9154             static if (needsEndTracker)
9155             {
9156                 if (nextSource.empty)
9157                     hasShownPartialBefore = true;
9158             }
9159             else
9160             {
9161                 if (source.length <= windowSize)
9162                     hasShownPartialBefore = true;
9163             }
9164         }
9165         else
9166         {
9167             // empty source range is needed, s.t. length, slicing etc. works properly
9168             static if (needsEndTracker)
9169             {
9170                 if (poppedElems < windowSize)
9171                      _empty = true;
9172             }
9173             else
9174             {
9175                 if (source.length < windowSize)
9176                      _empty = true;
9177             }
9178         }
9179     }
9180 
9181     /// Forward range primitives. Always present.
9182     @property auto front()
9183     {
9184         assert(!empty, "Attempting to access front on an empty slide.");
9185         static if (hasSlicing!Source && hasLength!Source)
9186         {
9187             static if (withPartial)
9188             {
9189                 import std.algorithm.comparison : min;
9190                 return source[0 .. min(windowSize, source.length)];
9191             }
9192             else
9193             {
9194                 assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
9195                 return source[0 .. windowSize];
9196             }
9197         }
9198         else
9199         {
9200             static if (withPartial)
9201                 return source.save.take(windowSize);
9202             else
9203                 return source.save.takeExactly(windowSize);
9204         }
9205     }
9206 
9207     /// Ditto
9208     void popFront()
9209     {
9210         assert(!empty, "Attempting to call popFront() on an empty slide.");
9211         source.popFrontN(stepSize);
9212 
9213         if (source.empty)
9214         {
9215             _empty = true;
9216             return;
9217         }
9218 
9219         static if (withPartial)
9220         {
9221             if (hasShownPartialBefore)
9222                 _empty = true;
9223         }
9224 
9225         static if (needsEndTracker)
9226         {
9227             // Check the upcoming slide
9228             auto poppedElements = nextSource.popFrontN(stepSize);
9229             static if (withPartial)
9230             {
9231                 if (poppedElements < stepSize || nextSource.empty)
9232                     hasShownPartialBefore = true;
9233             }
9234             else
9235             {
9236                 if (poppedElements < stepSize)
9237                     _empty = true;
9238             }
9239         }
9240         else
9241         {
9242             static if (withPartial)
9243             {
9244                 if (source.length <= windowSize)
9245                     hasShownPartialBefore = true;
9246             }
9247             else
9248             {
9249                 if (source.length < windowSize)
9250                     _empty = true;
9251             }
9252         }
9253     }
9254 
9255     static if (!isInfinite!Source)
9256     {
9257         /// Ditto
9258         @property bool empty() const
9259         {
9260             return _empty;
9261         }
9262     }
9263     else
9264     {
9265         // undocumented
9266         enum empty = false;
9267     }
9268 
9269     /// Ditto
9270     @property typeof(this) save()
9271     {
9272         return typeof(this)(source.save, windowSize, stepSize);
9273     }
9274 
9275     static if (hasLength!Source)
9276     {
9277         // gaps between the last element and the end of the range
9278         private size_t gap()
9279         {
9280             /*
9281             * Note:
9282             * - In the following `end` is the exclusive end as used in opSlice
9283             * - For the trivial case with `stepSize = 1`  `end` is at `len`:
9284             *
9285             *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]]    (end = 4)
9286             *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]      (end = 4)
9287             *
9288             * - For the non-trivial cases, we need to calculate the gap
9289             *   between `len` and `end` - this is the number of missing elements
9290             *   from the input range:
9291             *
9292             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
9293             *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
9294             *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
9295             *
9296             *   As it can be seen `gap` can be at most `stepSize - 1`
9297             *   More generally the elements of the sliding window with
9298             *   `w = windowSize` and `s = stepSize` are:
9299             *
9300             *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
9301             *
9302             *  We can thus calculate the gap between the `end` and `len` as:
9303             *
9304             *     gap = len - (n * s + w) = len - w - (n * s)
9305             *
9306             *  As we aren't interested in exact value of `n`, but the best
9307             *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
9308             *
9309             *     gap = len - w - (s - s ... - s) = (len - w) % s
9310             *
9311             *  So for example:
9312             *
9313             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
9314             *      gap: (7 - 2) % 3 = 5 % 3 = 2
9315             *      end: 7 - 2 = 5
9316             *
9317             *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
9318             *      gap: (7 - 4) % 2 = 3 % 2 = 1
9319             *      end: 7 - 1 = 6
9320             */
9321             return (source.length - windowSize)  % stepSize;
9322         }
9323 
9324         private size_t numberOfFullFrames()
9325         {
9326             /**
9327             5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9328             7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (3)
9329             7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (2)
9330             6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5]         (2)
9331             7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (2)
9332 
9333             As the last window is only added iff its complete,
9334             we don't count the last window except if it's full due to integer rounding.
9335             */
9336             return 1 + (source.length - windowSize) / stepSize;
9337         }
9338 
9339         // Whether the last slide frame size is less than windowSize
9340         private bool hasPartialElements()
9341         {
9342             static if (withPartial)
9343                 return gap != 0 && source.length > numberOfFullFrames * stepSize;
9344             else
9345                 return 0;
9346         }
9347 
9348         /// Length. Only if `hasLength!Source` is `true`
9349         @property size_t length()
9350         {
9351             if (source.length < windowSize)
9352             {
9353                 static if (withPartial)
9354                     return source.length > 0;
9355                 else
9356                     return 0;
9357             }
9358             else
9359             {
9360                 /***
9361                   We bump the pointer by stepSize for every element.
9362                   If withPartial, we don't count the last element if its size
9363                   isn't windowSize
9364 
9365                   At most:
9366                       [p, p + stepSize, ..., p + stepSize * n]
9367 
9368                 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9369                 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (4)
9370                 7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (3)
9371                 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6]      (3)
9372                 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (3)
9373                 */
9374                 return numberOfFullFrames + hasPartialElements;
9375             }
9376         }
9377     }
9378 
9379     static if (hasSlicing!Source)
9380     {
9381         /**
9382         Indexing and slicing operations. Provided only if
9383         `hasSlicing!Source` is `true`.
9384          */
9385         auto opIndex(size_t index)
9386         {
9387             immutable start = index * stepSize;
9388 
9389             static if (isInfinite!Source)
9390             {
9391                 immutable end = start + windowSize;
9392             }
9393             else
9394             {
9395                 import std.algorithm.comparison : min;
9396 
9397                 immutable len = source.length;
9398                 assert(start < len, "slide index out of bounds");
9399                 immutable end = min(start + windowSize, len);
9400             }
9401 
9402             return source[start .. end];
9403         }
9404 
9405         static if (!isInfinite!Source)
9406         {
9407             /// ditto
9408             typeof(this) opSlice(size_t lower, size_t upper)
9409             {
9410                 import std.algorithm.comparison : min;
9411 
9412                 assert(upper <= length, "slide slicing index out of bounds");
9413                 assert(lower <= upper, "slide slicing index out of bounds");
9414 
9415                 lower *= stepSize;
9416                 upper *= stepSize;
9417 
9418                 immutable len = source.length;
9419 
9420                 static if (withPartial)
9421                 {
9422                     import std.algorithm.comparison : max;
9423 
9424                     if (lower == upper)
9425                         return this[$ .. $];
9426 
9427                     /*
9428                     A) If `stepSize` >= `windowSize` => `rightPos = upper`
9429 
9430                        [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9431                          rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9432                          6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9433 
9434                     B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9435 
9436                        [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9437                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9438                          1.iota.slide(2) = [[0]]
9439 
9440                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9441                          1.iota.slide(2) = [[0, 1]]
9442 
9443                        More complex:
9444 
9445                        20.iota.slide(7, 6)[0 .. 2]
9446                          rightPos: (upper=2) * (stepSize=6) = 12.iota
9447                          12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9448 
9449                        Now we add up for the difference between `windowSize` and `stepSize`:
9450 
9451                          rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9452                          13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9453                     */
9454                     immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9455                 }
9456                 else
9457                 {
9458                     /*
9459                     After we have normalized `lower` and `upper` by `stepSize`,
9460                     we only need to look at the case of `stepSize=1`.
9461                     As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9462                     Notice that starting from `upper`,
9463                     we only need to move for `windowSize - 1` to the right:
9464 
9465                       - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9466                         rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9467 
9468                       - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9469                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9470 
9471                       - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9472                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9473                     */
9474                     immutable rightPos = min(upper + windowSize - 1, len);
9475                 }
9476 
9477                 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9478             }
9479         }
9480         else static if (hasSliceToEnd)
9481         {
9482             // For slicing an infinite chunk, we need to slice the source to the infinite end.
9483             auto opSlice(size_t lower, size_t upper)
9484             {
9485                 assert(lower <= upper, "slide slicing index out of bounds");
9486                 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9487                                     .takeExactly(upper - lower);
9488             }
9489         }
9490 
9491         static if (isInfinite!Source)
9492         {
9493             static if (hasSliceToEnd)
9494             {
9495                 private static struct DollarToken{}
9496                 DollarToken opDollar()
9497                 {
9498                     return DollarToken();
9499                 }
9500                 //Slice to dollar
9501                 typeof(this) opSlice(size_t lower, DollarToken)
9502                 {
9503                     return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9504                 }
9505             }
9506         }
9507         else
9508         {
9509             // Dollar token carries a static type, with no extra information.
9510             // It can lazily transform into source.length on algorithmic
9511             // operations such as : slide[$/2, $-1];
9512             private static struct DollarToken
9513             {
9514                 private size_t _length;
9515                 alias _length this;
9516             }
9517 
9518             DollarToken opDollar()
9519             {
9520                 return DollarToken(this.length);
9521             }
9522 
9523             // Optimized slice overloads optimized for using dollar.
9524             typeof(this) opSlice(DollarToken, DollarToken)
9525             {
9526                 static if (hasSliceToEnd)
9527                 {
9528                     return typeof(this)(source[$ .. $], windowSize, stepSize);
9529                 }
9530                 else
9531                 {
9532                     immutable len = source.length;
9533                     return typeof(this)(source[len .. len], windowSize, stepSize);
9534                 }
9535             }
9536 
9537             // Optimized slice overloads optimized for using dollar.
9538             typeof(this) opSlice(size_t lower, DollarToken)
9539             {
9540                 import std.algorithm.comparison : min;
9541                 assert(lower <= length, "slide slicing index out of bounds");
9542                 lower *= stepSize;
9543                 static if (hasSliceToEnd)
9544                 {
9545                     return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9546                 }
9547                 else
9548                 {
9549                     immutable len = source.length;
9550                     return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9551                 }
9552             }
9553 
9554             // Optimized slice overloads optimized for using dollar.
9555             typeof(this) opSlice(DollarToken, size_t upper)
9556             {
9557                 assert(upper == length, "slide slicing index out of bounds");
9558                 return this[$ .. $];
9559             }
9560         }
9561 
9562         // Bidirectional range primitives
9563         static if (!isInfinite!Source)
9564         {
9565             /**
9566             Bidirectional range primitives. Provided only if both
9567             `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9568              */
9569             @property auto back()
9570             {
9571                 import std.algorithm.comparison : max;
9572 
9573                 assert(!empty, "Attempting to access front on an empty slide");
9574 
9575                 immutable len = source.length;
9576 
9577                 static if (withPartial)
9578                 {
9579                     if (source.length <= windowSize)
9580                         return source[0 .. source.length];
9581 
9582                     if (hasPartialElements)
9583                         return source[numberOfFullFrames * stepSize .. len];
9584                 }
9585 
9586                 // check for underflow
9587                 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9588                 return source[start .. len - gap];
9589             }
9590 
9591             /// Ditto
9592             void popBack()
9593             {
9594                 assert(!empty, "Attempting to call popBack() on an empty slide");
9595 
9596                 // Move by stepSize
9597                 immutable end = source.length > stepSize ? source.length - stepSize : 0;
9598 
9599                 static if (withPartial)
9600                 {
9601                     if (hasShownPartialBefore || source.empty)
9602                     {
9603                         _empty = true;
9604                         return;
9605                     }
9606 
9607                     // pop by stepSize, except for the partial frame at the end
9608                     if (hasPartialElements)
9609                         source = source[0 .. source.length - gap];
9610                     else
9611                         source = source[0 .. end];
9612                 }
9613                 else
9614                 {
9615                     source = source[0 .. end];
9616                 }
9617 
9618                 if (source.length < windowSize)
9619                     _empty = true;
9620             }
9621         }
9622     }
9623 }
9624 
9625 // test @nogc
9626 @safe pure nothrow @nogc unittest
9627 {
9628     import std.algorithm.comparison : equal;
9629 
9630     static immutable res1 = [[0], [1], [2], [3]];
9631     assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9632 
9633     static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9634     assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9635 }
9636 
9637 // test different window sizes
9638 @safe pure nothrow unittest
9639 {
9640     import std.array : array;
9641     import std.algorithm.comparison : equal;
9642 
9643     assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9644     assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9645     assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9646     assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9647     assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9648     assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9649 
9650     assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9651     assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9652     assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9653     assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9654     assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9655     assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9656     assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9657 }
9658 
9659 // test combinations
9660 @safe pure nothrow unittest
9661 {
9662     import std.algorithm.comparison : equal;
9663     import std.typecons : tuple;
9664 
9665     alias t = tuple;
9666     auto list = [
9667         t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9668         t(t(1, 2), [[0], [2], [4]]),
9669         t(t(1, 3), [[0], [3]]),
9670         t(t(1, 4), [[0], [4]]),
9671         t(t(1, 5), [[0], [5]]),
9672         t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9673         t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9674         t(t(2, 3), [[0, 1], [3, 4]]),
9675         t(t(2, 4), [[0, 1], [4, 5]]),
9676         t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9677         t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9678         t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9679         t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9680         t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9681     ];
9682 
9683     static foreach (Partial; [Yes.withPartial, No.withPartial])
9684         foreach (e; list)
9685             assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9686 
9687     auto listSpecial = [
9688         t(t(2, 5), [[0, 1], [5]]),
9689         t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9690         t(t(3, 4), [[0, 1, 2], [4, 5]]),
9691         t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9692         t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9693         t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9694     ];
9695     foreach (e; listSpecial)
9696     {
9697         assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
9698         assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
9699     }
9700 }
9701 
9702 // test emptiness and copyability
9703 @safe pure nothrow unittest
9704 {
9705     import std.algorithm.comparison : equal;
9706     import std.algorithm.iteration : map;
9707 
9708     // check with empty input
9709     int[] d;
9710     assert(d.slide!(Yes.withPartial)(2).empty);
9711     assert(d.slide!(Yes.withPartial)(2, 2).empty);
9712 
9713     // is copyable?
9714     auto e = iota(5).slide!(Yes.withPartial)(2);
9715     e.popFront;
9716     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9717     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9718     assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
9719 }
9720 
9721 // test with strings
9722 @safe pure nothrow unittest
9723 {
9724     import std.algorithm.iteration : each;
9725 
9726     int[dstring] f;
9727     "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
9728     assert(f == ["AGA"d: 2, "GAG"d: 1]);
9729 
9730     int[dstring] g;
9731     "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
9732     assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
9733     g = null;
9734     "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
9735     assert(g == ["ABC"d:1, "DEF"d:1]);
9736 }
9737 
9738 // test with utf8 strings
9739 @safe unittest
9740 {
9741     import std.stdio;
9742     import std.algorithm.comparison : equal;
9743 
9744     assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."]));
9745     assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"]));
9746 
9747     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
9748     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
9749     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]);
9750     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]);
9751 }
9752 
9753 // test length
9754 @safe pure nothrow unittest
9755 {
9756     // Slides with fewer elements are empty or 1 for Yes.withPartial
9757     static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
9758     {{
9759         assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
9760         assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
9761         assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
9762     }}
9763 
9764     static immutable list = [
9765     //  iota   slide    expected
9766         [4,    2, 1,     3, 3],
9767         [5,    3, 1,     3, 3],
9768         [7,    2, 2,     4, 3],
9769         [12,   2, 4,     3, 3],
9770         [6,    1, 2,     3, 3],
9771         [6,    2, 4,     2, 2],
9772         [3,    2, 4,     1, 1],
9773         [5,    2, 1,     4, 4],
9774         [7,    2, 2,     4, 3],
9775         [7,    2, 3,     3, 2],
9776         [7,    3, 2,     3, 3],
9777         [7,    3, 3,     3, 2],
9778     ];
9779     foreach (e; list)
9780     {
9781         assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
9782         assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
9783     }
9784 }
9785 
9786 // test index and slicing
9787 @safe pure nothrow unittest
9788 {
9789     import std.algorithm.comparison : equal;
9790     import std.array : array;
9791 
9792     static foreach (Partial; [Yes.withPartial, No.withPartial])
9793     {
9794         foreach (s; [5, 7, 10, 15, 20])
9795         foreach (windowSize; 1 .. 10)
9796         foreach (stepSize; 1 .. 10)
9797         {
9798             auto r = s.iota.slide!Partial(windowSize, stepSize);
9799             auto arr = r.array;
9800             assert(r.length == arr.length);
9801 
9802             // test indexing
9803             foreach (i; 0 .. arr.length)
9804                 assert(r[i] == arr[i]);
9805 
9806             // test slicing
9807             foreach (i; 0 .. arr.length)
9808             {
9809                 foreach (j; i .. arr.length)
9810                     assert(r[i .. j].equal(arr[i .. j]));
9811 
9812                 assert(r[i .. $].equal(arr[i .. $]));
9813             }
9814 
9815             // test opDollar slicing
9816             assert(r[$/2 .. $].equal(arr[$/2 .. $]));
9817             assert(r[$ .. $].empty);
9818             if (arr.empty)
9819             {
9820                 assert(r[$ .. 0].empty);
9821                 assert(r[$/2 .. $].empty);
9822 
9823             }
9824         }
9825     }
9826 }
9827 
9828 // test with infinite ranges
9829 @safe pure nothrow unittest
9830 {
9831     import std.algorithm.comparison : equal;
9832 
9833     static foreach (Partial; [Yes.withPartial, No.withPartial])
9834     {{
9835         // InfiniteRange without RandomAccess
9836         auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
9837         assert(fibs.slide!Partial(2).take(2).equal!equal([[1,  1], [1,  2]]));
9838         assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
9839 
9840         // InfiniteRange with RandomAccess and slicing
9841         auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9842         auto oddsByPairs = odds.slide!Partial(2);
9843         assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
9844         assert(oddsByPairs[1].equal([3, 5]));
9845         assert(oddsByPairs[4].equal([9, 11]));
9846 
9847         static assert(hasSlicing!(typeof(odds)));
9848         assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
9849         assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
9850 
9851         auto oddsWithGaps = odds.slide!Partial(2, 4);
9852         assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
9853         assert(oddsWithGaps[2].equal([17, 19]));
9854         assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
9855         assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
9856     }}
9857 }
9858 
9859 // test reverse
9860 @safe pure nothrow unittest
9861 {
9862     import std.algorithm.comparison : equal;
9863 
9864     static foreach (Partial; [Yes.withPartial, No.withPartial])
9865     {{
9866         foreach (windowSize; 1 .. 15)
9867         foreach (stepSize; 1 .. 15)
9868         {
9869             auto r = 20.iota.slide!Partial(windowSize, stepSize);
9870             auto rArr = r.array.retro;
9871             auto rRetro = r.retro;
9872 
9873             assert(rRetro.length == rArr.length);
9874             assert(rRetro.equal(rArr));
9875             assert(rRetro.array.retro.equal(r));
9876         }
9877     }}
9878 }
9879 
9880 // test with dummy ranges
9881 @safe pure nothrow unittest
9882 {
9883     import std.algorithm.comparison : equal;
9884     import std.internal.test.dummyrange : AllDummyRanges;
9885     import std.meta : Filter;
9886 
9887     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9888     {{
9889         Range r;
9890 
9891         static foreach (Partial; [Yes.withPartial, No.withPartial])
9892         {
9893             assert(r.slide!Partial(1).equal!equal(
9894                 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
9895             ));
9896             assert(r.slide!Partial(2).equal!equal(
9897                 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
9898             ));
9899             assert(r.slide!Partial(3).equal!equal(
9900                 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
9901                 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
9902             ));
9903             assert(r.slide!Partial(6).equal!equal(
9904                 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
9905                 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
9906             ));
9907         }
9908 
9909         // special cases
9910         assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
9911         assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
9912         assert(r.slide!(No.withPartial)(15).empty);
9913         assert(r.slide!(No.withPartial)(15).walkLength == 0);
9914     }}
9915 }
9916 
9917 // test with dummy ranges
9918 @safe pure nothrow unittest
9919 {
9920     import std.algorithm.comparison : equal;
9921     import std.internal.test.dummyrange : AllDummyRanges;
9922     import std.meta : Filter;
9923     import std.typecons : tuple;
9924 
9925     alias t = tuple;
9926     static immutable list = [
9927     // iota   slide    expected
9928         t(6,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
9929         t(6,  t(4, 6), [[1, 2, 3, 4]]),
9930         t(6,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
9931         t(7,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
9932         t(7,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
9933         t(8,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
9934         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]]),
9935         t(8,  t(3, 4), [[1, 2, 3], [5, 6, 7]]),
9936         t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
9937     ];
9938 
9939     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9940     static foreach (Partial; [Yes.withPartial, No.withPartial])
9941     foreach (e; list)
9942         assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
9943 
9944     static immutable listSpecial = [
9945     // iota   slide    expected
9946         t(6,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
9947         t(7,  t(4, 5), [[1, 2, 3, 4], [6, 7]]),
9948         t(7,  t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
9949         t(7,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
9950         t(8,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
9951         t(8,  t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
9952         t(8,  t(3, 6), [[1, 2, 3], [7, 8]]),
9953         t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
9954         t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
9955     ];
9956     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9957     static foreach (Partial; [Yes.withPartial, No.withPartial])
9958     foreach (e; listSpecial)
9959     {
9960         Range r;
9961         assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
9962         assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
9963     }
9964 }
9965 
9966 // test reverse with dummy ranges
9967 @safe pure nothrow unittest
9968 {
9969     import std.algorithm.comparison : equal;
9970     import std.internal.test.dummyrange : AllDummyRanges;
9971     import std.meta : Filter, templateAnd;
9972     import std.typecons : tuple;
9973     alias t = tuple;
9974 
9975     static immutable list = [
9976     //   slide   expected
9977         t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
9978         t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
9979         t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
9980                  [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
9981         t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
9982         t(2, 4, [[9, 10], [5, 6], [1, 2]]),
9983     ];
9984 
9985     static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
9986     {{
9987         Range r;
9988         static foreach (Partial; [Yes.withPartial, No.withPartial])
9989         {
9990             foreach (e; list)
9991                 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
9992 
9993             // front = back
9994             foreach (windowSize; 1 .. 10)
9995             foreach (stepSize; 1 .. 10)
9996             {
9997                 auto slider = r.slide!Partial(windowSize, stepSize);
9998                 auto sliderRetro = slider.retro.array;
9999                 assert(slider.length == sliderRetro.length);
10000                 assert(sliderRetro.retro.equal!equal(slider));
10001             }
10002         }
10003 
10004         // special cases
10005         assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
10006         assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
10007     }}
10008 }
10009 
10010 // test different sliceable ranges
10011 @safe pure nothrow unittest
10012 {
10013     import std.algorithm.comparison : equal;
10014     import std.internal.test.dummyrange : AllDummyRanges;
10015     import std.meta : AliasSeq;
10016 
10017     struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
10018                                  Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
10019     {
10020         Range arr = 10.iota.array; // similar to DummyRange
10021         @property auto save() { return typeof(this)(arr); }
10022         @property auto front() { return arr[0]; }
10023         void popFront() { arr.popFront(); }
10024         auto opSlice(size_t i, size_t j)
10025         {
10026             // subslices can't be infinite
10027             return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
10028         }
10029 
10030         static if (withInfiniteness)
10031         {
10032             enum empty = false;
10033         }
10034         else
10035         {
10036             @property bool empty() { return arr.empty; }
10037             @property auto length() { return arr.length; }
10038         }
10039 
10040         static if (withOpDollar)
10041         {
10042             static if (withInfiniteness)
10043             {
10044                 struct Dollar {}
10045                 Dollar opDollar() const { return Dollar.init; }
10046 
10047                 // Slice to dollar
10048                 typeof(this) opSlice(size_t lower, Dollar)
10049                 {
10050                     return typeof(this)(arr[lower .. $]);
10051                 }
10052 
10053             }
10054             else
10055             {
10056                 alias opDollar = length;
10057             }
10058         }
10059     }
10060 
10061     import std.meta : Filter,  templateNot;
10062     alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
10063 
10064     static foreach (Partial; [Yes.withPartial, No.withPartial])
10065     {{
10066         static foreach (Range; SliceableDummyRanges)
10067         {{
10068             Range r;
10069             r.reinit;
10070             r.arr[] -= 1; // use a 0-based array (for clarity)
10071 
10072             assert(r.slide!Partial(2)[0].equal([0, 1]));
10073             assert(r.slide!Partial(2)[1].equal([1, 2]));
10074 
10075             // saveable
10076             auto s = r.slide!Partial(2);
10077             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10078             s.save.popFront;
10079             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10080 
10081             assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
10082         }}
10083 
10084         static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
10085         {{
10086             Range r;
10087             r.reinit;
10088             r.arr[] -= 1; // use a 0-based array (for clarity)
10089 
10090             assert(r.slide!(No.withPartial)(6).equal!equal(
10091                 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
10092                 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
10093             ));
10094             assert(r.slide!(No.withPartial)(16).empty);
10095 
10096             assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
10097             assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
10098             assert(r.slide!Partial(2)[$ .. $].empty);
10099 
10100             assert(r.slide!Partial(3).retro.equal!equal(
10101                 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
10102             ));
10103         }}
10104 
10105         alias T = int[];
10106 
10107         // separate checks for infinity
10108         auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
10109         assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
10110         assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
10111 
10112         auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
10113         assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
10114         assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
10115         assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
10116     }}
10117 }
10118 
10119 // https://issues.dlang.org/show_bug.cgi?id=19082
10120 @safe unittest
10121 {
10122     import std.algorithm.comparison : equal;
10123     import std.algorithm.iteration : map;
10124     assert([1].map!(x => x).slide(2).equal!equal([[1]]));
10125 }
10126 
10127 // https://issues.dlang.org/show_bug.cgi?id=19642
10128 @safe unittest
10129 {
10130     import std.algorithm.comparison : equal;
10131     import std.algorithm.iteration : splitter;
10132 
10133     assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]]));
10134 }
10135 
10136 // https://issues.dlang.org/show_bug.cgi?id=23976
10137 @safe unittest
10138 {
10139     import std.algorithm.comparison : equal;
10140     import std.algorithm.iteration : splitter;
10141 
10142     assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]]));
10143 }
10144 
10145 private struct OnlyResult(Values...)
10146 if (Values.length > 1)
10147 {
10148     private enum arity = Values.length;
10149 
10150     private alias UnqualValues = staticMap!(Unqual, Values);
10151 
10152     private this(return scope ref Values values)
10153     {
10154         ref @trusted unqual(T)(ref T x){return cast() x;}
10155 
10156         // TODO: this calls any possible copy constructors without qualifiers.
10157         // Find a way to initialize values using qualified copy constructors.
10158         static foreach (i; 0 .. Values.length)
10159         {
10160             this.values[i] = unqual(values[i]);
10161         }
10162         this.backIndex = arity;
10163     }
10164 
10165     bool empty() @property
10166     {
10167         return frontIndex >= backIndex;
10168     }
10169 
10170     CommonType!Values front() @property
10171     {
10172         assert(!empty, "Attempting to fetch the front of an empty Only range");
10173         return this[0];
10174     }
10175 
10176     void popFront()
10177     {
10178         assert(!empty, "Attempting to popFront an empty Only range");
10179         ++frontIndex;
10180     }
10181 
10182     CommonType!Values back() @property
10183     {
10184         assert(!empty, "Attempting to fetch the back of an empty Only range");
10185         return this[$ - 1];
10186     }
10187 
10188     void popBack()
10189     {
10190         assert(!empty, "Attempting to popBack an empty Only range");
10191         --backIndex;
10192     }
10193 
10194     OnlyResult save() @property
10195     {
10196         return this;
10197     }
10198 
10199     size_t length() const @property
10200     {
10201         return backIndex - frontIndex;
10202     }
10203 
10204     alias opDollar = length;
10205 
10206     @trusted CommonType!Values opIndex(size_t idx)
10207     {
10208         // when i + idx points to elements popped
10209         // with popBack
10210         assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
10211         final switch (frontIndex + idx)
10212             static foreach (i, T; Values)
10213             case i:
10214                 return cast(T) values[i];
10215     }
10216 
10217     OnlyResult opSlice()
10218     {
10219         return this;
10220     }
10221 
10222     OnlyResult opSlice(size_t from, size_t to)
10223     {
10224         OnlyResult result = this;
10225         result.frontIndex += from;
10226         result.backIndex = this.frontIndex + to;
10227         assert(
10228             from <= to,
10229             "Attempting to slice an Only range with a larger first argument than the second."
10230         );
10231         assert(
10232             to <= length,
10233             "Attempting to slice using an out of bounds index on an Only range"
10234         );
10235         return result;
10236     }
10237 
10238     private size_t frontIndex = 0;
10239     private size_t backIndex = 0;
10240 
10241     // https://issues.dlang.org/show_bug.cgi?id=10643
10242     version (none)
10243     {
10244         import std.traits : hasElaborateAssign;
10245         static if (hasElaborateAssign!T)
10246             private UnqualValues values;
10247         else
10248             private UnqualValues values = void;
10249     }
10250     else
10251         // These may alias to shared or immutable data. Do not let the user
10252         // to access these directly, and do not allow mutation without checking
10253         // the qualifier.
10254         private UnqualValues values;
10255 }
10256 
10257 // Specialize for single-element results
10258 private struct OnlyResult(T)
10259 {
10260     @property T front()
10261     {
10262         assert(!empty, "Attempting to fetch the front of an empty Only range");
10263         return fetchFront();
10264     }
10265     @property T back()
10266     {
10267         assert(!empty, "Attempting to fetch the back of an empty Only range");
10268         return fetchFront();
10269     }
10270     @property bool empty() const { return _empty; }
10271     @property size_t length() const { return !_empty; }
10272     @property auto save() { return this; }
10273     void popFront()
10274     {
10275         assert(!_empty, "Attempting to popFront an empty Only range");
10276         _empty = true;
10277     }
10278     void popBack()
10279     {
10280         assert(!_empty, "Attempting to popBack an empty Only range");
10281         _empty = true;
10282     }
10283     alias opDollar = length;
10284 
10285     private this()(return scope auto ref T value)
10286     {
10287         ref @trusted unqual(ref T x){return cast() x;}
10288         // TODO: this calls the possible copy constructor without qualifiers.
10289         // Find a way to initialize value using a qualified copy constructor.
10290         this._value = unqual(value);
10291         this._empty = false;
10292     }
10293 
10294     T opIndex(size_t i)
10295     {
10296         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
10297         return fetchFront();
10298     }
10299 
10300     OnlyResult opSlice()
10301     {
10302         return this;
10303     }
10304 
10305     OnlyResult opSlice(size_t from, size_t to)
10306     {
10307         assert(
10308             from <= to,
10309             "Attempting to slice an Only range with a larger first argument than the second."
10310         );
10311         assert(
10312             to <= length,
10313             "Attempting to slice using an out of bounds index on an Only range"
10314         );
10315         OnlyResult copy = this;
10316         copy._empty = _empty || from == to;
10317         return copy;
10318     }
10319 
10320     // This may alias to shared or immutable data. Do not let the user
10321     // to access this directly, and do not allow mutation without checking
10322     // the qualifier.
10323     private Unqual!T _value;
10324     private bool _empty = true;
10325     private @trusted T fetchFront()
10326     {
10327         return *cast(T*)&_value;
10328     }
10329 }
10330 
10331 /**
10332 Assemble `values` into a range that carries all its
10333 elements in-situ.
10334 
10335 Useful when a single value or multiple disconnected values
10336 must be passed to an algorithm expecting a range, without
10337 having to perform dynamic memory allocation.
10338 
10339 As copying the range means copying all elements, it can be
10340 safely returned from functions. For the same reason, copying
10341 the returned range may be expensive for a large number of arguments.
10342 
10343 Params:
10344     values = the values to assemble together
10345 
10346 Returns:
10347     A `RandomAccessRange` of the assembled values.
10348 
10349 See_Also: $(LREF chain) to chain ranges
10350  */
10351 auto only(Values...)(return scope Values values)
10352 if (!is(CommonType!Values == void))
10353 {
10354     return OnlyResult!Values(values);
10355 }
10356 
10357 /// ditto
10358 auto only()()
10359 {
10360     // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383
10361     struct EmptyElementType {}
10362     EmptyElementType[] result;
10363     return result;
10364 }
10365 
10366 ///
10367 @safe unittest
10368 {
10369     import std.algorithm.comparison : equal;
10370     import std.algorithm.iteration : filter, joiner, map;
10371     import std.algorithm.searching : findSplitBefore;
10372     import std.uni : isUpper;
10373 
10374     assert(equal(only('♡'), "♡"));
10375     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
10376 
10377     assert(only("one", "two", "three").joiner(" ").equal("one two three"));
10378 
10379     string title = "The D Programming Language";
10380     assert(title
10381         .filter!isUpper // take the upper case letters
10382         .map!only       // make each letter its own range
10383         .joiner(".")    // join the ranges together lazily
10384         .equal("T.D.P.L"));
10385 }
10386 
10387 // https://issues.dlang.org/show_bug.cgi?id=20314
10388 @safe unittest
10389 {
10390     import std.algorithm.iteration : joiner;
10391 
10392     const string s = "foo", t = "bar";
10393 
10394     assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
10395 }
10396 
10397 // Tests the zero-element result
10398 @safe unittest
10399 {
10400     import std.algorithm.comparison : equal;
10401 
10402     auto emptyRange = only();
10403 
10404     alias EmptyRange = typeof(emptyRange);
10405     static assert(isInputRange!EmptyRange);
10406     static assert(isForwardRange!EmptyRange);
10407     static assert(isBidirectionalRange!EmptyRange);
10408     static assert(isRandomAccessRange!EmptyRange);
10409     static assert(hasLength!EmptyRange);
10410     static assert(hasSlicing!EmptyRange);
10411 
10412     assert(emptyRange.empty);
10413     assert(emptyRange.length == 0);
10414     assert(emptyRange.equal(emptyRange[]));
10415     assert(emptyRange.equal(emptyRange.save));
10416     assert(emptyRange[0 .. 0].equal(emptyRange));
10417 }
10418 
10419 // Tests the single-element result
10420 @safe unittest
10421 {
10422     import std.algorithm.comparison : equal;
10423     import std.typecons : tuple;
10424     foreach (x; tuple(1, '1', 1.0, "1", [1]))
10425     {
10426         auto a = only(x);
10427         typeof(x)[] e = [];
10428         assert(a.front == x);
10429         assert(a.back == x);
10430         assert(!a.empty);
10431         assert(a.length == 1);
10432         assert(equal(a, a[]));
10433         assert(equal(a, a[0 .. 1]));
10434         assert(equal(a[0 .. 0], e));
10435         assert(equal(a[1 .. 1], e));
10436         assert(a[0] == x);
10437 
10438         auto b = a.save;
10439         assert(equal(a, b));
10440         a.popFront();
10441         assert(a.empty && a.length == 0 && a[].empty);
10442         b.popBack();
10443         assert(b.empty && b.length == 0 && b[].empty);
10444 
10445         alias A = typeof(a);
10446         static assert(isInputRange!A);
10447         static assert(isForwardRange!A);
10448         static assert(isBidirectionalRange!A);
10449         static assert(isRandomAccessRange!A);
10450         static assert(hasLength!A);
10451         static assert(hasSlicing!A);
10452     }
10453 
10454     auto imm = only!(immutable int)(1);
10455     immutable int[] imme = [];
10456     assert(imm.front == 1);
10457     assert(imm.back == 1);
10458     assert(!imm.empty);
10459     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10460     assert(imm.length == 1);
10461     assert(equal(imm, imm[]));
10462     assert(equal(imm, imm[0 .. 1]));
10463     assert(equal(imm[0 .. 0], imme));
10464     assert(equal(imm[1 .. 1], imme));
10465     assert(imm[0] == 1);
10466 }
10467 
10468 // Tests multiple-element results
10469 @safe unittest
10470 {
10471     import std.algorithm.comparison : equal;
10472     import std.algorithm.iteration : joiner;
10473     import std.meta : AliasSeq;
10474     static assert(!__traits(compiles, only(1, "1")));
10475 
10476     auto nums = only!(byte, uint, long)(1, 2, 3);
10477     static assert(is(ElementType!(typeof(nums)) == long));
10478     assert(nums.length == 3);
10479 
10480     foreach (i; 0 .. 3)
10481         assert(nums[i] == i + 1);
10482 
10483     auto saved = nums.save;
10484 
10485     foreach (i; 1 .. 4)
10486     {
10487         assert(nums.front == nums[0]);
10488         assert(nums.front == i);
10489         nums.popFront();
10490         assert(nums.length == 3 - i);
10491     }
10492 
10493     assert(nums.empty);
10494 
10495     assert(saved.equal(only(1, 2, 3)));
10496     assert(saved.equal(saved[]));
10497     assert(saved[0 .. 1].equal(only(1)));
10498     assert(saved[0 .. 2].equal(only(1, 2)));
10499     assert(saved[0 .. 3].equal(saved));
10500     assert(saved[1 .. 3].equal(only(2, 3)));
10501     assert(saved[2 .. 3].equal(only(3)));
10502     assert(saved[0 .. 0].empty);
10503     assert(saved[3 .. 3].empty);
10504 
10505     alias data = AliasSeq!("one", "two", "three", "four");
10506     static joined =
10507         ["one two", "one two three", "one two three four"];
10508     string[] joinedRange = joined;
10509 
10510     static foreach (argCount; 2 .. 5)
10511     {{
10512         auto values = only(data[0 .. argCount]);
10513         alias Values = typeof(values);
10514         static assert(is(ElementType!Values == string));
10515         static assert(isInputRange!Values);
10516         static assert(isForwardRange!Values);
10517         static assert(isBidirectionalRange!Values);
10518         static assert(isRandomAccessRange!Values);
10519         static assert(hasSlicing!Values);
10520         static assert(hasLength!Values);
10521 
10522         assert(values.length == argCount);
10523         assert(values[0 .. $].equal(values[0 .. values.length]));
10524         assert(values.joiner(" ").equal(joinedRange.front));
10525         joinedRange.popFront();
10526     }}
10527 
10528     assert(saved.retro.equal(only(3, 2, 1)));
10529     assert(saved.length == 3);
10530 
10531     assert(saved.back == 3);
10532     saved.popBack();
10533     assert(saved.length == 2);
10534     assert(saved.back == 2);
10535 
10536     assert(saved.front == 1);
10537     saved.popFront();
10538     assert(saved.length == 1);
10539     assert(saved.front == 2);
10540 
10541     saved.popBack();
10542     assert(saved.empty);
10543 
10544     auto imm = only!(immutable int, immutable int)(42, 24);
10545     alias Imm = typeof(imm);
10546     static assert(is(ElementType!Imm == immutable(int)));
10547     assert(!imm.empty);
10548     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10549     assert(imm.front == 42);
10550     imm.popFront();
10551     assert(imm.front == 24);
10552     imm.popFront();
10553     assert(imm.empty);
10554 
10555     static struct Test { int* a; }
10556     immutable(Test) test;
10557     cast(void) only(test, test); // Works with mutable indirection
10558 }
10559 
10560 // https://issues.dlang.org/show_bug.cgi?id=21129
10561 @safe unittest
10562 {
10563     auto range = () @safe {
10564         const(char)[5] staticStr = "Hello";
10565 
10566         // `only` must store a char[5] - not a char[]!
10567         return only(staticStr, " World");
10568     } ();
10569 
10570     assert(range.join == "Hello World");
10571 }
10572 
10573 // https://issues.dlang.org/show_bug.cgi?id=21129
10574 @safe unittest
10575 {
10576     struct AliasedString
10577     {
10578         const(char)[5] staticStr = "Hello";
10579 
10580         @property const(char)[] slice() const
10581         {
10582             return staticStr[];
10583         }
10584         alias slice this;
10585     }
10586 
10587     auto range = () @safe {
10588         auto hello = AliasedString();
10589 
10590         // a copy of AliasedString is stored in the range.
10591         return only(hello, " World");
10592     } ();
10593 
10594     assert(range.join == "Hello World");
10595 }
10596 
10597 // https://issues.dlang.org/show_bug.cgi?id=21022
10598 @safe pure nothrow unittest
10599 {
10600     struct S
10601     {
10602         int* mem;
10603     }
10604 
10605     immutable S x;
10606     immutable(S)[] arr;
10607     auto r1 = arr.chain(x.only, only(x, x));
10608 }
10609 
10610 /**
10611 Iterate over `range` with an attached index variable.
10612 
10613 Each element is a $(REF Tuple, std,typecons) containing the index
10614 and the element, in that order, where the index member is named `index`
10615 and the element member is named `value`.
10616 
10617 The index starts at `start` and is incremented by one on every iteration.
10618 
10619 Overflow:
10620     If `range` has length, then it is an error to pass a value for `start`
10621     so that `start + range.length` is bigger than `Enumerator.max`, thus
10622     it is ensured that overflow cannot happen.
10623 
10624     If `range` does not have length, and `popFront` is called when
10625     `front.index == Enumerator.max`, the index will overflow and
10626     continue from `Enumerator.min`.
10627 
10628 Params:
10629     range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
10630     start = the number to start the index counter from
10631 
10632 Returns:
10633     At minimum, an input range. All other range primitives are given in the
10634     resulting range if `range` has them. The exceptions are the bidirectional
10635     primitives, which are propagated only if `range` has length.
10636 
10637 Example:
10638 Useful for using `foreach` with an index loop variable:
10639 ----
10640     import std.stdio : stdin, stdout;
10641     import std.range : enumerate;
10642 
10643     foreach (lineNum, line; stdin.byLine().enumerate(1))
10644         stdout.writefln("line #%s: %s", lineNum, line);
10645 ----
10646 */
10647 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
10648 if (isIntegral!Enumerator && isInputRange!Range)
10649 in
10650 {
10651     static if (hasLength!Range)
10652     {
10653         // TODO: core.checkedint supports mixed signedness yet?
10654         import core.checkedint : adds, addu;
10655         import std.conv : ConvException, to;
10656         import std.traits : isSigned, Largest, Signed;
10657 
10658         alias LengthType = typeof(range.length);
10659         bool overflow;
10660         static if (isSigned!Enumerator && isSigned!LengthType)
10661             auto result = adds(start, range.length, overflow);
10662         else static if (isSigned!Enumerator)
10663         {
10664             alias signed_t = Largest!(Enumerator, Signed!LengthType);
10665             signed_t signedLength;
10666             //This is to trick the compiler because if length is enum
10667             //the compiler complains about unreachable code.
10668             auto getLength()
10669             {
10670                 return range.length;
10671             }
10672             //Can length fit in the signed type
10673             assert(getLength() < signed_t.max,
10674                 "a signed length type is required but the range's length() is too great");
10675             signedLength = range.length;
10676             auto result = adds(start, signedLength, overflow);
10677         }
10678         else
10679         {
10680             static if (isSigned!LengthType)
10681                 assert(range.length >= 0);
10682             auto result = addu(start, range.length, overflow);
10683         }
10684 
10685         assert(!overflow && result <= Enumerator.max);
10686     }
10687 }
10688 do
10689 {
10690     // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
10691     static struct Result
10692     {
10693         import std.typecons : Tuple;
10694 
10695         private:
10696         alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
10697         Range range;
10698         Unqual!Enumerator index;
10699 
10700         public:
10701         ElemType front() @property
10702         {
10703             assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
10704             return typeof(return)(index, range.front);
10705         }
10706 
10707         static if (isInfinite!Range)
10708             enum bool empty = false;
10709         else
10710         {
10711             bool empty() @property
10712             {
10713                 return range.empty;
10714             }
10715         }
10716 
10717         void popFront()
10718         {
10719             assert(!range.empty, "Attempting to popFront an empty enumerate");
10720             range.popFront();
10721             ++index; // When !hasLength!Range, overflow is expected
10722         }
10723 
10724         static if (isForwardRange!Range)
10725         {
10726             Result save() @property
10727             {
10728                 return typeof(return)(range.save, index);
10729             }
10730         }
10731 
10732         static if (hasLength!Range)
10733         {
10734             mixin ImplementLength!range;
10735 
10736             static if (isBidirectionalRange!Range)
10737             {
10738                 ElemType back() @property
10739                 {
10740                     assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
10741                     return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
10742                 }
10743 
10744                 void popBack()
10745                 {
10746                     assert(!range.empty, "Attempting to popBack an empty enumerate");
10747                     range.popBack();
10748                 }
10749             }
10750         }
10751 
10752         static if (isRandomAccessRange!Range)
10753         {
10754              ElemType opIndex(size_t i)
10755              {
10756                 return typeof(return)(cast(Enumerator)(index + i), range[i]);
10757              }
10758         }
10759 
10760         static if (hasSlicing!Range)
10761         {
10762             static if (hasLength!Range)
10763             {
10764                 Result opSlice(size_t i, size_t j)
10765                 {
10766                     return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
10767                 }
10768             }
10769             else
10770             {
10771                 static struct DollarToken {}
10772                 enum opDollar = DollarToken.init;
10773 
10774                 Result opSlice(size_t i, DollarToken)
10775                 {
10776                     return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
10777                 }
10778 
10779                 auto opSlice(size_t i, size_t j)
10780                 {
10781                     return this[i .. $].takeExactly(j - 1);
10782                 }
10783             }
10784         }
10785     }
10786 
10787     return Result(range, start);
10788 }
10789 
10790 /// Can start enumeration from a negative position:
10791 pure @safe nothrow unittest
10792 {
10793     import std.array : assocArray;
10794     import std.range : enumerate;
10795 
10796     bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
10797     assert(aa[-1]);
10798     assert(aa[0]);
10799     assert(aa[1]);
10800 }
10801 
10802 // Make sure passing qualified types works
10803 pure @safe nothrow unittest
10804 {
10805     char[4] v;
10806     immutable start = 2;
10807     v[2 .. $].enumerate(start);
10808 }
10809 
10810 pure @safe nothrow unittest
10811 {
10812     import std.internal.test.dummyrange : AllDummyRanges;
10813     import std.meta : AliasSeq;
10814     import std.typecons : tuple;
10815 
10816     static struct HasSlicing
10817     {
10818         typeof(this) front() @property { return typeof(this).init; }
10819         bool empty() @property { return true; }
10820         void popFront() {}
10821 
10822         typeof(this) opSlice(size_t, size_t)
10823         {
10824             return typeof(this)();
10825         }
10826     }
10827 
10828     static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
10829     {{
10830         alias R = typeof(enumerate(DummyType.init));
10831         static assert(isInputRange!R);
10832         static assert(isForwardRange!R == isForwardRange!DummyType);
10833         static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
10834         static assert(!hasAssignableElements!R);
10835 
10836         static if (hasLength!DummyType)
10837         {
10838             static assert(hasLength!R);
10839             static assert(isBidirectionalRange!R ==
10840                 isBidirectionalRange!DummyType);
10841         }
10842 
10843         static assert(hasSlicing!R == hasSlicing!DummyType);
10844     }}
10845 
10846     static immutable values = ["zero", "one", "two", "three"];
10847     auto enumerated = values[].enumerate();
10848     assert(!enumerated.empty);
10849     assert(enumerated.front == tuple(0, "zero"));
10850     assert(enumerated.back == tuple(3, "three"));
10851 
10852     typeof(enumerated) saved = enumerated.save;
10853     saved.popFront();
10854     assert(enumerated.front == tuple(0, "zero"));
10855     assert(saved.front == tuple(1, "one"));
10856     assert(saved.length == enumerated.length - 1);
10857     saved.popBack();
10858     assert(enumerated.back == tuple(3, "three"));
10859     assert(saved.back == tuple(2, "two"));
10860     saved.popFront();
10861     assert(saved.front == tuple(2, "two"));
10862     assert(saved.back == tuple(2, "two"));
10863     saved.popFront();
10864     assert(saved.empty);
10865 
10866     size_t control = 0;
10867     foreach (i, v; enumerated)
10868     {
10869         static assert(is(typeof(i) == size_t));
10870         static assert(is(typeof(v) == typeof(values[0])));
10871         assert(i == control);
10872         assert(v == values[i]);
10873         assert(tuple(i, v) == enumerated[i]);
10874         ++control;
10875     }
10876 
10877     assert(enumerated[0 .. $].front == tuple(0, "zero"));
10878     assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
10879 
10880     foreach (i; 0 .. 10)
10881     {
10882         auto shifted = values[0 .. 2].enumerate(i);
10883         assert(shifted.front == tuple(i, "zero"));
10884         assert(shifted[0] == shifted.front);
10885 
10886         auto next = tuple(i + 1, "one");
10887         assert(shifted[1] == next);
10888         shifted.popFront();
10889         assert(shifted.front == next);
10890         shifted.popFront();
10891         assert(shifted.empty);
10892     }
10893 
10894     static foreach (T; AliasSeq!(ubyte, byte, uint, int))
10895     {{
10896         auto inf = 42.repeat().enumerate(T.max);
10897         alias Inf = typeof(inf);
10898         static assert(isInfinite!Inf);
10899         static assert(hasSlicing!Inf);
10900 
10901         // test overflow
10902         assert(inf.front == tuple(T.max, 42));
10903         inf.popFront();
10904         assert(inf.front == tuple(T.min, 42));
10905 
10906         // test slicing
10907         inf = inf[42 .. $];
10908         assert(inf.front == tuple(T.min + 42, 42));
10909         auto window = inf[0 .. 2];
10910         assert(window.length == 1);
10911         assert(window.front == inf.front);
10912         window.popFront();
10913         assert(window.empty);
10914     }}
10915 }
10916 
10917 pure @safe unittest
10918 {
10919     import std.algorithm.comparison : equal;
10920     import std.meta : AliasSeq;
10921     static immutable int[] values = [0, 1, 2, 3, 4];
10922     static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
10923     {{
10924         auto enumerated = values.enumerate!T();
10925         static assert(is(typeof(enumerated.front.index) == T));
10926         assert(enumerated.equal(values[].zip(values)));
10927 
10928         foreach (T i; 0 .. 5)
10929         {
10930             auto subset = values[cast(size_t) i .. $];
10931             auto offsetEnumerated = subset.enumerate(i);
10932             static assert(is(typeof(enumerated.front.index) == T));
10933             assert(offsetEnumerated.equal(subset.zip(subset)));
10934         }
10935     }}
10936 }
10937 @nogc @safe unittest
10938 {
10939    const val = iota(1, 100).enumerate(1);
10940 }
10941 @nogc @safe unittest
10942 {
10943     import core.exception : AssertError;
10944     import std.exception : assertThrown;
10945     struct RangePayload {
10946         enum length = size_t.max;
10947         void popFront() {}
10948         int front() { return 0; }
10949         bool empty() { return true; }
10950     }
10951     RangePayload thePayload;
10952     //Assertion won't happen when contracts are disabled for -release.
10953     debug assertThrown!AssertError(enumerate(thePayload, -10));
10954 }
10955 // https://issues.dlang.org/show_bug.cgi?id=10939
10956 version (none)
10957 {
10958     // Re-enable (or remove) if 10939 is resolved.
10959     /+pure+/ @safe unittest // Impure because of std.conv.to
10960     {
10961         import core.exception : RangeError;
10962         import std.exception : assertNotThrown, assertThrown;
10963         import std.meta : AliasSeq;
10964 
10965         static immutable values = [42];
10966 
10967         static struct SignedLengthRange
10968         {
10969             immutable(int)[] _values = values;
10970 
10971             int front() @property { assert(false); }
10972             bool empty() @property { assert(false); }
10973             void popFront() { assert(false); }
10974 
10975             int length() @property
10976             {
10977                 return cast(int)_values.length;
10978             }
10979         }
10980 
10981         SignedLengthRange svalues;
10982         static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
10983         {
10984             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
10985             assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
10986             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
10987 
10988             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
10989             assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
10990             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
10991         }
10992 
10993         static foreach (Enumerator; AliasSeq!(byte, short, int))
10994         {
10995             assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
10996         }
10997 
10998         assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
10999     }
11000 }
11001 
11002 /**
11003   Returns true if `fn` accepts variables of type T1 and T2 in any order.
11004   The following code should compile:
11005   ---
11006   (ref T1 a, ref T2 b)
11007   {
11008     fn(a, b);
11009     fn(b, a);
11010   }
11011   ---
11012 */
11013 template isTwoWayCompatible(alias fn, T1, T2)
11014 {
11015     enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
11016         {
11017             cast(void) fn(a, b);
11018             cast(void) fn(b, a);
11019         }
11020     ));
11021 }
11022 
11023 ///
11024 @safe unittest
11025 {
11026     void func1(int a, int b);
11027     void func2(int a, float b);
11028 
11029     static assert(isTwoWayCompatible!(func1, int, int));
11030     static assert(isTwoWayCompatible!(func1, short, int));
11031     static assert(!isTwoWayCompatible!(func2, int, float));
11032 
11033     void func3(ref int a, ref int b);
11034     static assert( isTwoWayCompatible!(func3, int, int));
11035     static assert(!isTwoWayCompatible!(func3, short, int));
11036 }
11037 
11038 
11039 /**
11040    Policy used with the searching primitives `lowerBound`, $(D
11041    upperBound), and `equalRange` of $(LREF SortedRange) below.
11042  */
11043 enum SearchPolicy
11044 {
11045     /**
11046        Searches in a linear fashion.
11047     */
11048     linear,
11049 
11050     /**
11051        Searches with a step that is grows linearly (1, 2, 3,...)
11052        leading to a quadratic search schedule (indexes tried are 0, 1,
11053        3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
11054        the remaining interval is searched using binary search. The
11055        search is completed in $(BIGOH sqrt(n)) time. Use it when you
11056        are reasonably confident that the value is around the beginning
11057        of the range.
11058     */
11059     trot,
11060 
11061     /**
11062        Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
11063        galloping search algorithm), i.e. searches
11064        with a step that doubles every time, (1, 2, 4, 8, ...)  leading
11065        to an exponential search schedule (indexes tried are 0, 1, 3,
11066        7, 15, 31, 63,...) Once the search overshoots its target, the
11067        remaining interval is searched using binary search. A value is
11068        found in $(BIGOH log(n)) time.
11069     */
11070     gallop,
11071 
11072     /**
11073        Searches using a classic interval halving policy. The search
11074        starts in the middle of the range, and each search step cuts
11075        the range in half. This policy finds a value in $(BIGOH log(n))
11076        time but is less cache friendly than `gallop` for large
11077        ranges. The `binarySearch` policy is used as the last step
11078        of `trot`, `gallop`, `trotBackwards`, and $(D
11079        gallopBackwards) strategies.
11080     */
11081     binarySearch,
11082 
11083     /**
11084        Similar to `trot` but starts backwards. Use it when
11085        confident that the value is around the end of the range.
11086     */
11087     trotBackwards,
11088 
11089     /**
11090        Similar to `gallop` but starts backwards. Use it when
11091        confident that the value is around the end of the range.
11092     */
11093     gallopBackwards
11094 }
11095 
11096 ///
11097 @safe unittest
11098 {
11099     import std.algorithm.comparison : equal;
11100 
11101     auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
11102     auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
11103     assert(p1.equal([4, 5, 6, 7, 8, 9]));
11104 
11105     auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
11106     assert(p2.equal([0, 1, 2, 3]));
11107 }
11108 
11109 /**
11110    Options for $(LREF SortedRange) ranges (below).
11111 */
11112 enum SortedRangeOptions
11113 {
11114    /**
11115       Assume, that the range is sorted without checking.
11116    */
11117    assumeSorted,
11118 
11119    /**
11120       All elements of the range are checked to be sorted.
11121       The check is performed in O(n) time.
11122    */
11123    checkStrictly,
11124 
11125    /**
11126       Some elements of the range are checked to be sorted.
11127       For ranges with random order, this will almost surely
11128       detect, that it is not sorted. For almost sorted ranges
11129       it's more likely to fail. The checked elements are choosen
11130       in a deterministic manner, which makes this check reproducable.
11131       The check is performed in O(log(n)) time.
11132    */
11133    checkRoughly,
11134 }
11135 
11136 ///
11137 @safe pure unittest
11138 {
11139     // create a SortedRange, that's checked strictly
11140     SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
11141 }
11142 
11143 /**
11144    Represents a sorted range. In addition to the regular range
11145    primitives, supports additional operations that take advantage of the
11146    ordering, such as merge and binary search. To obtain a $(D
11147    SortedRange) from an unsorted range `r`, use
11148    $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
11149    corresponding `SortedRange`. To construct a `SortedRange` from a range
11150    `r` that is known to be already sorted, use $(LREF assumeSorted).
11151 
11152    Params:
11153        pred: The predicate used to define the sortedness
11154        opt: Controls how strongly the range is checked for sortedness.
11155             Will only be used for `RandomAccessRanges`.
11156             Will not be used in CTFE.
11157 */
11158 struct SortedRange(Range, alias pred = "a < b",
11159     SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11160 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
11161 {
11162     import std.functional : binaryFun;
11163 
11164     private alias predFun = binaryFun!pred;
11165     private bool geq(L, R)(L lhs, R rhs)
11166     {
11167         return !predFun(lhs, rhs);
11168     }
11169     private bool gt(L, R)(L lhs, R rhs)
11170     {
11171         return predFun(rhs, lhs);
11172     }
11173     private Range _input;
11174 
11175     // Undocummented because a clearer way to invoke is by calling
11176     // assumeSorted.
11177     this(Range input)
11178     {
11179         static if (opt == SortedRangeOptions.checkRoughly)
11180         {
11181             roughlyVerifySorted(input);
11182         }
11183         static if (opt == SortedRangeOptions.checkStrictly)
11184         {
11185             strictlyVerifySorted(input);
11186         }
11187         this._input = input;
11188     }
11189 
11190     // Assertion only.
11191     static if (opt == SortedRangeOptions.checkRoughly)
11192     private void roughlyVerifySorted(Range r)
11193     {
11194         if (!__ctfe)
11195         {
11196             static if (isRandomAccessRange!Range && hasLength!Range)
11197             {
11198                 import core.bitop : bsr;
11199                 import std.algorithm.sorting : isSorted;
11200                 import std.exception : enforce;
11201 
11202                 // Check the sortedness of the input
11203                 if (r.length < 2) return;
11204 
11205                 immutable size_t msb = bsr(r.length) + 1;
11206                 assert(msb > 0 && msb <= r.length);
11207                 immutable step = r.length / msb;
11208                 auto st = stride(r, step);
11209 
11210                 enforce(isSorted!pred(st), "Range is not sorted");
11211             }
11212         }
11213     }
11214 
11215     // Assertion only.
11216     static if (opt == SortedRangeOptions.checkStrictly)
11217     private void strictlyVerifySorted(Range r)
11218     {
11219         if (!__ctfe)
11220         {
11221             static if (isRandomAccessRange!Range && hasLength!Range)
11222             {
11223                 import std.algorithm.sorting : isSorted;
11224                 import std.exception : enforce;
11225 
11226                 enforce(isSorted!pred(r), "Range is not sorted");
11227             }
11228         }
11229     }
11230 
11231     /// Range primitives.
11232     @property bool empty()             //const
11233     {
11234         return this._input.empty;
11235     }
11236 
11237     /// Ditto
11238     static if (isForwardRange!Range)
11239     @property auto save()
11240     {
11241         // Avoid the constructor
11242         typeof(this) result = this;
11243         result._input = _input.save;
11244         return result;
11245     }
11246 
11247     /// Ditto
11248     @property auto ref front()
11249     {
11250         return _input.front;
11251     }
11252 
11253     /// Ditto
11254     void popFront()
11255     {
11256         _input.popFront();
11257     }
11258 
11259     /// Ditto
11260     static if (isBidirectionalRange!Range)
11261     {
11262         @property auto ref back()
11263         {
11264             return _input.back;
11265         }
11266 
11267         /// Ditto
11268         void popBack()
11269         {
11270             _input.popBack();
11271         }
11272     }
11273 
11274     /// Ditto
11275     static if (isRandomAccessRange!Range)
11276         auto ref opIndex(size_t i)
11277         {
11278             return _input[i];
11279         }
11280 
11281     /// Ditto
11282     static if (hasSlicing!Range)
11283         auto opSlice(size_t a, size_t b) return scope
11284         {
11285             assert(
11286                 a <= b,
11287                 "Attempting to slice a SortedRange with a larger first argument than the second."
11288             );
11289             typeof(this) result = this;
11290             result._input = _input[a .. b];// skip checking
11291             return result;
11292         }
11293 
11294     mixin ImplementLength!_input;
11295 
11296 /**
11297     Releases the controlled range and returns it.
11298 
11299     This does the opposite of $(LREF assumeSorted): instead of turning a range
11300     into a `SortedRange`, it extracts the original range back out of the `SortedRange`
11301     using $(REF, move, std,algorithm,mutation).
11302 */
11303     auto release() return scope
11304     {
11305         import std.algorithm.mutation : move;
11306         return move(_input);
11307     }
11308 
11309     ///
11310     static if (is(Range : int[]))
11311     @safe unittest
11312     {
11313         import std.algorithm.sorting : sort;
11314         int[3] data = [ 1, 2, 3 ];
11315         auto a = assumeSorted(data[]);
11316         assert(a == sort!"a < b"(data[]));
11317         int[] p = a.release();
11318         assert(p == [ 1, 2, 3 ]);
11319     }
11320 
11321     // Assuming a predicate "test" that returns 0 for a left portion
11322     // of the range and then 1 for the rest, returns the index at
11323     // which the first 1 appears. Used internally by the search routines.
11324     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11325     if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
11326     {
11327         size_t first = 0, count = _input.length;
11328         while (count > 0)
11329         {
11330             immutable step = count / 2, it = first + step;
11331             if (!test(_input[it], v))
11332             {
11333                 first = it + 1;
11334                 count -= step + 1;
11335             }
11336             else
11337             {
11338                 count = step;
11339             }
11340         }
11341         return first;
11342     }
11343 
11344     // Specialization for trot and gallop
11345     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11346     if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
11347         && isRandomAccessRange!Range)
11348     {
11349         if (empty || test(front, v)) return 0;
11350         immutable count = length;
11351         if (count == 1) return 1;
11352         size_t below = 0, above = 1, step = 2;
11353         while (!test(_input[above], v))
11354         {
11355             // Still too small, update below and increase gait
11356             below = above;
11357             immutable next = above + step;
11358             if (next >= count)
11359             {
11360                 // Overshot - the next step took us beyond the end. So
11361                 // now adjust next and simply exit the loop to do the
11362                 // binary search thingie.
11363                 above = count;
11364                 break;
11365             }
11366             // Still in business, increase step and continue
11367             above = next;
11368             static if (sp == SearchPolicy.trot)
11369                 ++step;
11370             else
11371                 step <<= 1;
11372         }
11373         return below + this[below .. above].getTransitionIndex!(
11374             SearchPolicy.binarySearch, test, V)(v);
11375     }
11376 
11377     // Specialization for trotBackwards and gallopBackwards
11378     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11379     if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
11380         && isRandomAccessRange!Range)
11381     {
11382         immutable count = length;
11383         if (empty || !test(back, v)) return count;
11384         if (count == 1) return 0;
11385         size_t below = count - 2, above = count - 1, step = 2;
11386         while (test(_input[below], v))
11387         {
11388             // Still too large, update above and increase gait
11389             above = below;
11390             if (below < step)
11391             {
11392                 // Overshot - the next step took us beyond the end. So
11393                 // now adjust next and simply fall through to do the
11394                 // binary search thingie.
11395                 below = 0;
11396                 break;
11397             }
11398             // Still in business, increase step and continue
11399             below -= step;
11400             static if (sp == SearchPolicy.trot)
11401                 ++step;
11402             else
11403                 step <<= 1;
11404         }
11405         return below + this[below .. above].getTransitionIndex!(
11406             SearchPolicy.binarySearch, test, V)(v);
11407     }
11408 
11409 // lowerBound
11410 /**
11411    This function uses a search with policy `sp` to find the
11412    largest left subrange on which $(D pred(x, value)) is `true` for
11413    all `x` (e.g., if `pred` is "less than", returns the portion of
11414    the range with elements strictly smaller than `value`). The search
11415    schedule and its complexity are documented in
11416    $(LREF SearchPolicy).
11417 */
11418     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11419     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11420          && hasSlicing!Range)
11421     {
11422         return this[0 .. getTransitionIndex!(sp, geq)(value)];
11423     }
11424 
11425     ///
11426     static if (is(Range : int[]))
11427     @safe unittest
11428     {
11429         import std.algorithm.comparison : equal;
11430         auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
11431         auto p = a.lowerBound(4);
11432         assert(equal(p, [ 0, 1, 2, 3 ]));
11433     }
11434 
11435 // upperBound
11436 /**
11437 This function searches with policy `sp` to find the largest right
11438 subrange on which $(D pred(value, x)) is `true` for all `x`
11439 (e.g., if `pred` is "less than", returns the portion of the range
11440 with elements strictly greater than `value`). The search schedule
11441 and its complexity are documented in $(LREF SearchPolicy).
11442 
11443 For ranges that do not offer random access, `SearchPolicy.linear`
11444 is the only policy allowed (and it must be specified explicitly lest it exposes
11445 user code to unexpected inefficiencies). For random-access searches, all
11446 policies are allowed, and `SearchPolicy.binarySearch` is the default.
11447 */
11448     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11449     if (isTwoWayCompatible!(predFun, ElementType!Range, V))
11450     {
11451         static assert(hasSlicing!Range || sp == SearchPolicy.linear,
11452             "Specify SearchPolicy.linear explicitly for "
11453             ~ typeof(this).stringof);
11454         static if (sp == SearchPolicy.linear)
11455         {
11456             for (; !_input.empty && !predFun(value, _input.front);
11457                  _input.popFront())
11458             {
11459             }
11460             return this;
11461         }
11462         else
11463         {
11464             return this[getTransitionIndex!(sp, gt)(value) .. length];
11465         }
11466     }
11467 
11468     ///
11469     static if (is(Range : int[]))
11470     @safe unittest
11471     {
11472         import std.algorithm.comparison : equal;
11473         auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
11474         auto p = a.upperBound(3);
11475         assert(equal(p, [4, 4, 5, 6]));
11476     }
11477 
11478 
11479 // equalRange
11480 /**
11481    Returns the subrange containing all elements `e` for which both $(D
11482    pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11483    if `pred` is "less than", returns the portion of the range with
11484    elements equal to `value`). Uses a classic binary search with
11485    interval halving until it finds a value that satisfies the condition,
11486    then uses `SearchPolicy.gallopBackwards` to find the left boundary
11487    and `SearchPolicy.gallop` to find the right boundary. These
11488    policies are justified by the fact that the two boundaries are likely
11489    to be near the first found value (i.e., equal ranges are relatively
11490    small). Completes the entire search in $(BIGOH log(n)) time.
11491 */
11492     auto equalRange(V)(V value)
11493     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11494         && isRandomAccessRange!Range)
11495     {
11496         size_t first = 0, count = _input.length;
11497         while (count > 0)
11498         {
11499             immutable step = count / 2;
11500             auto it = first + step;
11501             if (predFun(_input[it], value))
11502             {
11503                 // Less than value, bump left bound up
11504                 first = it + 1;
11505                 count -= step + 1;
11506             }
11507             else if (predFun(value, _input[it]))
11508             {
11509                 // Greater than value, chop count
11510                 count = step;
11511             }
11512             else
11513             {
11514                 // Equal to value, do binary searches in the
11515                 // leftover portions
11516                 // Gallop towards the left end as it's likely nearby
11517                 immutable left = first
11518                     + this[first .. it]
11519                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11520                 first += count;
11521                 // Gallop towards the right end as it's likely nearby
11522                 immutable right = first
11523                     - this[it + 1 .. first]
11524                     .upperBound!(SearchPolicy.gallop)(value).length;
11525                 return this[left .. right];
11526             }
11527         }
11528         return this.init;
11529     }
11530 
11531     ///
11532     static if (is(Range : int[]))
11533     @safe unittest
11534     {
11535         import std.algorithm.comparison : equal;
11536         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11537         auto r = a.assumeSorted.equalRange(3);
11538         assert(equal(r, [ 3, 3, 3 ]));
11539     }
11540 
11541 // trisect
11542 /**
11543 Returns a tuple `r` such that `r[0]` is the same as the result
11544 of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11545 equalRange(value)), and `r[2]` is the same as the result of $(D
11546 upperBound(value)). The call is faster than computing all three
11547 separately. Uses a search schedule similar to $(D
11548 equalRange). Completes the entire search in $(BIGOH log(n)) time.
11549 */
11550     auto trisect(V)(V value)
11551     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11552         && isRandomAccessRange!Range && hasLength!Range)
11553     {
11554         import std.typecons : tuple;
11555         size_t first = 0, count = _input.length;
11556         while (count > 0)
11557         {
11558             immutable step = count / 2;
11559             auto it = first + step;
11560             if (predFun(_input[it], value))
11561             {
11562                 // Less than value, bump left bound up
11563                 first = it + 1;
11564                 count -= step + 1;
11565             }
11566             else if (predFun(value, _input[it]))
11567             {
11568                 // Greater than value, chop count
11569                 count = step;
11570             }
11571             else
11572             {
11573                 // Equal to value, do binary searches in the
11574                 // leftover portions
11575                 // Gallop towards the left end as it's likely nearby
11576                 immutable left = first
11577                     + this[first .. it]
11578                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11579                 first += count;
11580                 // Gallop towards the right end as it's likely nearby
11581                 immutable right = first
11582                     - this[it + 1 .. first]
11583                     .upperBound!(SearchPolicy.gallop)(value).length;
11584                 return tuple(this[0 .. left], this[left .. right],
11585                         this[right .. length]);
11586             }
11587         }
11588         // No equal element was found
11589         return tuple(this[0 .. first], this.init, this[first .. length]);
11590     }
11591 
11592     ///
11593     static if (is(Range : int[]))
11594     @safe unittest
11595     {
11596         import std.algorithm.comparison : equal;
11597         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11598         auto r = assumeSorted(a).trisect(3);
11599         assert(equal(r[0], [ 1, 2 ]));
11600         assert(equal(r[1], [ 3, 3, 3 ]));
11601         assert(equal(r[2], [ 4, 4, 5, 6 ]));
11602     }
11603 
11604 // contains
11605 /**
11606 Returns `true` if and only if `value` can be found in $(D
11607 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
11608 evaluations of `pred`.
11609  */
11610 
11611     bool contains(V)(V value)
11612     if (isRandomAccessRange!Range)
11613     {
11614         if (empty) return false;
11615         immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
11616         if (i >= length) return false;
11617         return !predFun(value, _input[i]);
11618     }
11619 
11620 /**
11621 Like `contains`, but the value is specified before the range.
11622 */
11623     bool opBinaryRight(string op, V)(V value)
11624     if (op == "in" && isRandomAccessRange!Range)
11625     {
11626         return contains(value);
11627     }
11628 
11629 // groupBy
11630 /**
11631 Returns a range of subranges of elements that are equivalent according to the
11632 sorting relation.
11633  */
11634     auto groupBy()()
11635     {
11636         import std.algorithm.iteration : chunkBy;
11637         return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
11638     }
11639 }
11640 
11641 /// ditto
11642 template SortedRange(Range, alias pred = "a < b",
11643                      SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11644 if (isInstanceOf!(SortedRange, Range))
11645 {
11646     // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
11647     alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
11648 }
11649 
11650 ///
11651 @safe unittest
11652 {
11653     import std.algorithm.sorting : sort;
11654     auto a = [ 1, 2, 3, 42, 52, 64 ];
11655     auto r = assumeSorted(a);
11656     assert(r.contains(3));
11657     assert(!(32 in r));
11658     auto r1 = sort!"a > b"(a);
11659     assert(3 in r1);
11660     assert(!r1.contains(32));
11661     assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
11662 }
11663 
11664 /**
11665 `SortedRange` could accept ranges weaker than random-access, but it
11666 is unable to provide interesting functionality for them. Therefore,
11667 `SortedRange` is currently restricted to random-access ranges.
11668 
11669 No copy of the original range is ever made. If the underlying range is
11670 changed concurrently with its corresponding `SortedRange` in ways
11671 that break its sorted-ness, `SortedRange` will work erratically.
11672 */
11673 @safe unittest
11674 {
11675     import std.algorithm.mutation : swap;
11676     auto a = [ 1, 2, 3, 42, 52, 64 ];
11677     auto r = assumeSorted(a);
11678     assert(r.contains(42));
11679     swap(a[3], a[5]);         // illegal to break sortedness of original range
11680     assert(!r.contains(42));  // passes although it shouldn't
11681 }
11682 
11683 /**
11684 `SortedRange` can be searched with predicates that do not take
11685 two elements of the underlying range as arguments.
11686 
11687 This is useful, if a range of structs is sorted by a member and you
11688 want to search in that range by only providing a value for that member.
11689 
11690 */
11691 @safe unittest
11692 {
11693     import std.algorithm.comparison : equal;
11694     static struct S { int i; }
11695     static bool byI(A, B)(A a, B b)
11696     {
11697         static if (is(A == S))
11698             return a.i < b;
11699         else
11700             return a < b.i;
11701     }
11702     auto r = assumeSorted!byI([S(1), S(2), S(3)]);
11703     auto lessThanTwo = r.lowerBound(2);
11704     assert(equal(lessThanTwo, [S(1)]));
11705 }
11706 
11707 @safe unittest
11708 {
11709     import std.exception : assertThrown, assertNotThrown;
11710 
11711     assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
11712     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
11713 
11714     // these two checks are implementation depended
11715     assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
11716     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
11717 }
11718 
11719 @safe unittest
11720 {
11721     import std.algorithm.comparison : equal;
11722 
11723     auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
11724     auto r = assumeSorted(a).trisect(30);
11725     assert(equal(r[0], [ 10, 20 ]));
11726     assert(equal(r[1], [ 30, 30, 30 ]));
11727     assert(equal(r[2], [ 40, 40, 50, 60 ]));
11728 
11729     r = assumeSorted(a).trisect(35);
11730     assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
11731     assert(r[1].empty);
11732     assert(equal(r[2], [ 40, 40, 50, 60 ]));
11733 }
11734 
11735 @safe unittest
11736 {
11737     import std.algorithm.comparison : equal;
11738     auto a = [ "A", "AG", "B", "E", "F" ];
11739     auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
11740     assert(equal(r[0], [ "A", "AG" ]));
11741     assert(equal(r[1], [ "B" ]));
11742     assert(equal(r[2], [ "E", "F" ]));
11743     r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
11744     assert(r[0].empty);
11745     assert(equal(r[1], [ "A" ]));
11746     assert(equal(r[2], [ "AG", "B", "E", "F" ]));
11747 }
11748 
11749 @safe unittest
11750 {
11751     import std.algorithm.comparison : equal;
11752     static void test(SearchPolicy pol)()
11753     {
11754         auto a = [ 1, 2, 3, 42, 52, 64 ];
11755         auto r = assumeSorted(a);
11756         assert(equal(r.lowerBound(42), [1, 2, 3]));
11757 
11758         assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
11759         assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
11760         assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
11761         assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
11762         assert(equal(r.lowerBound!(pol)(3), [1, 2]));
11763         assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
11764         assert(equal(r.lowerBound!(pol)(420), a));
11765         assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
11766 
11767         assert(equal(r.upperBound!(pol)(42), [52, 64]));
11768         assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
11769         assert(equal(r.upperBound!(pol)(43), [52, 64]));
11770         assert(equal(r.upperBound!(pol)(51), [52, 64]));
11771         assert(equal(r.upperBound!(pol)(53), [64]));
11772         assert(equal(r.upperBound!(pol)(55), [64]));
11773         assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
11774         assert(equal(r.upperBound!(pol)(0), a));
11775     }
11776 
11777     test!(SearchPolicy.trot)();
11778     test!(SearchPolicy.gallop)();
11779     test!(SearchPolicy.trotBackwards)();
11780     test!(SearchPolicy.gallopBackwards)();
11781     test!(SearchPolicy.binarySearch)();
11782 }
11783 
11784 @safe unittest
11785 {
11786     // Check for small arrays
11787     int[] a;
11788     auto r = assumeSorted(a);
11789     a = [ 1 ];
11790     r = assumeSorted(a);
11791     a = [ 1, 2 ];
11792     r = assumeSorted(a);
11793     a = [ 1, 2, 3 ];
11794     r = assumeSorted(a);
11795 }
11796 
11797 @safe unittest
11798 {
11799     import std.algorithm.mutation : swap;
11800     auto a = [ 1, 2, 3, 42, 52, 64 ];
11801     auto r = assumeSorted(a);
11802     assert(r.contains(42));
11803     swap(a[3], a[5]);                  // illegal to break sortedness of original range
11804     assert(!r.contains(42));            // passes although it shouldn't
11805 }
11806 
11807 @betterC @nogc nothrow @safe unittest
11808 {
11809     static immutable(int)[] arr = [ 1, 2, 3 ];
11810     auto s = assumeSorted(arr);
11811 }
11812 
11813 @system unittest
11814 {
11815     import std.algorithm.comparison : equal;
11816     int[] arr = [100, 101, 102, 200, 201, 300];
11817     auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
11818     assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
11819 }
11820 
11821 // Test on an input range
11822 @system unittest
11823 {
11824     import std.conv : text;
11825     import std.file : exists, remove, tempDir;
11826     import std.path : buildPath;
11827     import std.stdio : File;
11828     import std.uuid : randomUUID;
11829     auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
11830                           "." ~ randomUUID().toString());
11831     auto f = File(name, "w");
11832     scope(exit) if (exists(name)) remove(name);
11833     // write a sorted range of lines to the file
11834     f.write("abc\ndef\nghi\njkl");
11835     f.close();
11836     f.open(name, "r");
11837     auto r = assumeSorted(f.byLine());
11838     auto r1 = r.upperBound!(SearchPolicy.linear)("def");
11839     assert(r1.front == "ghi", r1.front);
11840     f.close();
11841 }
11842 
11843 // https://issues.dlang.org/show_bug.cgi?id=19337
11844 @safe unittest
11845 {
11846     import std.algorithm.sorting : sort;
11847     auto a = [ 1, 2, 3, 42, 52, 64 ];
11848     a.sort.sort!"a > b";
11849 }
11850 
11851 /**
11852 Assumes `r` is sorted by predicate `pred` and returns the
11853 corresponding $(D SortedRange!(pred, R)) having `r` as support.
11854 To check for sorted-ness at
11855 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
11856  */
11857 auto assumeSorted(alias pred = "a < b", R)(R r)
11858 if (isInputRange!(Unqual!R))
11859 {
11860     // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
11861     static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
11862     {
11863         static if (isInputRange!R && __traits(isSame, pred, RPred))
11864             // If the predicate is the same and we don't need to cast away
11865             // constness for the result to be an input range.
11866             return r;
11867         else
11868             return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
11869     }
11870     else
11871     {
11872         return SortedRange!(Unqual!R, pred)(r);
11873     }
11874 }
11875 
11876 ///
11877 @safe unittest
11878 {
11879     import std.algorithm.comparison : equal;
11880 
11881     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
11882     auto p = assumeSorted(a);
11883 
11884     assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
11885     assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
11886     assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
11887     assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
11888 }
11889 
11890 @safe unittest
11891 {
11892     import std.algorithm.comparison : equal;
11893     static assert(isRandomAccessRange!(SortedRange!(int[])));
11894     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11895     auto p = assumeSorted(a).upperBound(3);
11896     assert(equal(p, [4, 4, 5, 6 ]));
11897     p = assumeSorted(a).upperBound(4.2);
11898     assert(equal(p, [ 5, 6 ]));
11899 
11900     // https://issues.dlang.org/show_bug.cgi?id=18933
11901     // don't create senselessly nested SortedRange types.
11902     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
11903     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
11904 }
11905 
11906 @safe unittest
11907 {
11908     import std.algorithm.comparison : equal;
11909     import std.conv : text;
11910 
11911     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11912     auto p = assumeSorted(a).equalRange(3);
11913     assert(equal(p, [ 3, 3, 3 ]), text(p));
11914     p = assumeSorted(a).equalRange(4);
11915     assert(equal(p, [ 4, 4 ]), text(p));
11916     p = assumeSorted(a).equalRange(2);
11917     assert(equal(p, [ 2 ]));
11918     p = assumeSorted(a).equalRange(0);
11919     assert(p.empty);
11920     p = assumeSorted(a).equalRange(7);
11921     assert(p.empty);
11922     p = assumeSorted(a).equalRange(3.0);
11923     assert(equal(p, [ 3, 3, 3]));
11924 }
11925 
11926 @safe unittest
11927 {
11928     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11929     if (a.length)
11930     {
11931         auto b = a[a.length / 2];
11932         //auto r = sort(a);
11933         //assert(r.contains(b));
11934     }
11935 }
11936 
11937 @safe unittest
11938 {
11939     auto a = [ 5, 7, 34, 345, 677 ];
11940     auto r = assumeSorted(a);
11941     a = null;
11942     r = assumeSorted(a);
11943     a = [ 1 ];
11944     r = assumeSorted(a);
11945 }
11946 
11947 // https://issues.dlang.org/show_bug.cgi?id=15003
11948 @nogc @safe unittest
11949 {
11950     static immutable a = [1, 2, 3, 4];
11951     auto r = a.assumeSorted;
11952 }
11953 
11954 /++
11955     Wrapper which effectively makes it possible to pass a range by reference.
11956     Both the original range and the RefRange will always have the exact same
11957     elements. Any operation done on one will affect the other. So, for instance,
11958     if it's passed to a function which would implicitly copy the original range
11959     if it were passed to it, the original range is $(I not) copied but is
11960     consumed as if it were a reference type.
11961 
11962     Note:
11963         `save` works as normal and operates on a new range, so if
11964         `save` is ever called on the `RefRange`, then no operations on the
11965         saved range will affect the original.
11966 
11967     Params:
11968         range = the range to construct the `RefRange` from
11969 
11970     Returns:
11971         A `RefRange`. If the given range is a class type
11972         (and thus is already a reference type), then the original
11973         range is returned rather than a `RefRange`.
11974   +/
11975 struct RefRange(R)
11976 if (isInputRange!R)
11977 {
11978 public:
11979 
11980     /++ +/
11981     this(R* range) @safe pure nothrow
11982     {
11983         _range = range;
11984     }
11985 
11986 
11987     /++
11988         This does not assign the pointer of `rhs` to this `RefRange`.
11989         Rather it assigns the range pointed to by `rhs` to the range pointed
11990         to by this `RefRange`. This is because $(I any) operation on a
11991         `RefRange` is the same is if it occurred to the original range. The
11992         one exception is when a `RefRange` is assigned `null` either
11993         directly or because `rhs` is `null`. In that case, `RefRange`
11994         no longer refers to the original range but is `null`.
11995       +/
11996     auto opAssign(RefRange rhs)
11997     {
11998         if (_range && rhs._range)
11999             *_range = *rhs._range;
12000         else
12001             _range = rhs._range;
12002 
12003         return this;
12004     }
12005 
12006     /++ +/
12007     void opAssign(typeof(null) rhs)
12008     {
12009         _range = null;
12010     }
12011 
12012 
12013     /++
12014         A pointer to the wrapped range.
12015       +/
12016     @property inout(R*) ptr() @safe inout pure nothrow
12017     {
12018         return _range;
12019     }
12020 
12021 
12022     version (StdDdoc)
12023     {
12024         /++ +/
12025         @property auto front() {assert(0);}
12026         /++ Ditto +/
12027         @property auto front() const {assert(0);}
12028         /++ Ditto +/
12029         @property auto front(ElementType!R value) {assert(0);}
12030     }
12031     else
12032     {
12033         @property auto front()
12034         {
12035             return (*_range).front;
12036         }
12037 
12038         static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
12039         {
12040             return (*_range).front;
12041         }
12042 
12043         static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
12044         {
12045             return (*_range).front = value;
12046         }
12047     }
12048 
12049 
12050     version (StdDdoc)
12051     {
12052         @property bool empty(); ///
12053         @property bool empty() const; ///Ditto
12054     }
12055     else static if (isInfinite!R)
12056         enum empty = false;
12057     else
12058     {
12059         @property bool empty()
12060         {
12061             return (*_range).empty;
12062         }
12063 
12064         static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
12065         {
12066             return (*_range).empty;
12067         }
12068     }
12069 
12070 
12071     /++ +/
12072     void popFront()
12073     {
12074         return (*_range).popFront();
12075     }
12076 
12077 
12078     version (StdDdoc)
12079     {
12080         /++
12081             Only defined if `isForwardRange!R` is `true`.
12082           +/
12083         @property auto save() {assert(0);}
12084         /++ Ditto +/
12085         @property auto save() const {assert(0);}
12086         /++ Ditto +/
12087         auto opSlice() {assert(0);}
12088         /++ Ditto +/
12089         auto opSlice() const {assert(0);}
12090     }
12091     else static if (isForwardRange!R)
12092     {
12093         import std.traits : isSafe;
12094         private alias S = typeof((*_range).save);
12095 
12096         static if (is(typeof((*cast(const R*)_range).save)))
12097             private alias CS = typeof((*cast(const R*)_range).save);
12098 
12099         static if (isSafe!((R* r) => (*r).save))
12100         {
12101             @property RefRange!S save() @trusted
12102             {
12103                 mixin(_genSave());
12104             }
12105 
12106             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
12107             {
12108                 mixin(_genSave());
12109             }
12110         }
12111         else
12112         {
12113             @property RefRange!S save()
12114             {
12115                 mixin(_genSave());
12116             }
12117 
12118             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
12119             {
12120                 mixin(_genSave());
12121             }
12122         }
12123 
12124         auto opSlice()()
12125         {
12126             return save;
12127         }
12128 
12129         auto opSlice()() const
12130         {
12131             return save;
12132         }
12133 
12134         private static string _genSave() @safe pure nothrow
12135         {
12136             return `import core.lifetime : emplace;` ~
12137                    `alias S = typeof((*_range).save);` ~
12138                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
12139                    `auto mem = new void[S.sizeof];` ~
12140                    `emplace!S(mem, cast(S)(*_range).save);` ~
12141                    `return RefRange!S(cast(S*) mem.ptr);`;
12142         }
12143 
12144         static assert(isForwardRange!RefRange);
12145     }
12146 
12147 
12148     version (StdDdoc)
12149     {
12150         /++
12151             Only defined if `isBidirectionalRange!R` is `true`.
12152           +/
12153         @property auto back() {assert(0);}
12154         /++ Ditto +/
12155         @property auto back() const {assert(0);}
12156         /++ Ditto +/
12157         @property auto back(ElementType!R value) {assert(0);}
12158     }
12159     else static if (isBidirectionalRange!R)
12160     {
12161         @property auto back()
12162         {
12163             return (*_range).back;
12164         }
12165 
12166         static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
12167         {
12168             return (*_range).back;
12169         }
12170 
12171         static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
12172         {
12173             return (*_range).back = value;
12174         }
12175     }
12176 
12177 
12178     /++ Ditto +/
12179     static if (isBidirectionalRange!R) void popBack()
12180     {
12181         return (*_range).popBack();
12182     }
12183 
12184 
12185     version (StdDdoc)
12186     {
12187         /++
12188             Only defined if `isRandomAccessRange!R` is `true`.
12189           +/
12190         auto ref opIndex(IndexType)(IndexType index) {assert(0);}
12191 
12192         /++ Ditto +/
12193         auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
12194     }
12195     else static if (isRandomAccessRange!R)
12196     {
12197         auto ref opIndex(IndexType)(IndexType index)
12198             if (is(typeof((*_range)[index])))
12199         {
12200             return (*_range)[index];
12201         }
12202 
12203         auto ref opIndex(IndexType)(IndexType index) const
12204             if (is(typeof((*cast(const R*)_range)[index])))
12205         {
12206             return (*_range)[index];
12207         }
12208     }
12209 
12210 
12211     /++
12212         Only defined if `hasMobileElements!R` and `isForwardRange!R` are
12213         `true`.
12214       +/
12215     static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
12216     {
12217         return (*_range).moveFront();
12218     }
12219 
12220 
12221     /++
12222         Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
12223         are `true`.
12224       +/
12225     static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
12226     {
12227         return (*_range).moveBack();
12228     }
12229 
12230 
12231     /++
12232         Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
12233         are `true`.
12234       +/
12235     static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
12236     {
12237         return (*_range).moveAt(index);
12238     }
12239 
12240 
12241     version (StdDdoc)
12242     {
12243         /// Only defined if `hasLength!R` is `true`.
12244         @property size_t length();
12245         /// ditto
12246         @property size_t length() const;
12247         /// Ditto
12248         alias opDollar = length;
12249     }
12250     else static if (hasLength!R)
12251     {
12252         @property auto length()
12253         {
12254             return (*_range).length;
12255         }
12256         static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
12257         {
12258             return (*_range).length;
12259         }
12260         alias opDollar = length;
12261     }
12262 
12263 
12264     version (StdDdoc)
12265     {
12266         /++
12267             Only defined if `hasSlicing!R` is `true`.
12268           +/
12269         auto opSlice(IndexType1, IndexType2)
12270                     (IndexType1 begin, IndexType2 end) {assert(0);}
12271 
12272         /++ Ditto +/
12273         auto opSlice(IndexType1, IndexType2)
12274                     (IndexType1 begin, IndexType2 end) const {assert(0);}
12275     }
12276     else static if (hasSlicing!R)
12277     {
12278         private alias T = typeof((*_range)[1 .. 2]);
12279         static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
12280         {
12281             private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
12282         }
12283 
12284         RefRange!T opSlice(IndexType1, IndexType2)
12285                     (IndexType1 begin, IndexType2 end)
12286             if (is(typeof((*_range)[begin .. end])))
12287         {
12288             mixin(_genOpSlice());
12289         }
12290 
12291         RefRange!CT opSlice(IndexType1, IndexType2)
12292                     (IndexType1 begin, IndexType2 end) const
12293             if (is(typeof((*cast(const R*)_range)[begin .. end])))
12294         {
12295             mixin(_genOpSlice());
12296         }
12297 
12298         private static string _genOpSlice() @safe pure nothrow
12299         {
12300             return `import core.lifetime : emplace;` ~
12301                    `alias S = typeof((*_range)[begin .. end]);` ~
12302                    `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
12303                    `auto mem = new void[S.sizeof];` ~
12304                    `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
12305                    `return RefRange!S(cast(S*) mem.ptr);`;
12306         }
12307     }
12308 
12309 
12310 private:
12311 
12312     R* _range;
12313 }
12314 
12315 /// Basic Example
12316 @system unittest
12317 {
12318     import std.algorithm.searching : find;
12319     ubyte[] buffer = [1, 9, 45, 12, 22];
12320     auto found1 = find(buffer, 45);
12321     assert(found1 == [45, 12, 22]);
12322     assert(buffer == [1, 9, 45, 12, 22]);
12323 
12324     auto wrapped1 = refRange(&buffer);
12325     auto found2 = find(wrapped1, 45);
12326     assert(*found2.ptr == [45, 12, 22]);
12327     assert(buffer == [45, 12, 22]);
12328 
12329     auto found3 = find(wrapped1.save, 22);
12330     assert(*found3.ptr == [22]);
12331     assert(buffer == [45, 12, 22]);
12332 
12333     string str = "hello world";
12334     auto wrappedStr = refRange(&str);
12335     assert(str.front == 'h');
12336     str.popFrontN(5);
12337     assert(str == " world");
12338     assert(wrappedStr.front == ' ');
12339     assert(*wrappedStr.ptr == " world");
12340 }
12341 
12342 /// opAssign Example.
12343 @system unittest
12344 {
12345     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12346     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12347     auto wrapped1 = refRange(&buffer1);
12348     auto wrapped2 = refRange(&buffer2);
12349     assert(wrapped1.ptr is &buffer1);
12350     assert(wrapped2.ptr is &buffer2);
12351     assert(wrapped1.ptr !is wrapped2.ptr);
12352     assert(buffer1 != buffer2);
12353 
12354     wrapped1 = wrapped2;
12355 
12356     //Everything points to the same stuff as before.
12357     assert(wrapped1.ptr is &buffer1);
12358     assert(wrapped2.ptr is &buffer2);
12359     assert(wrapped1.ptr !is wrapped2.ptr);
12360 
12361     //But buffer1 has changed due to the assignment.
12362     assert(buffer1 == [6, 7, 8, 9, 10]);
12363     assert(buffer2 == [6, 7, 8, 9, 10]);
12364 
12365     buffer2 = [11, 12, 13, 14, 15];
12366 
12367     //Everything points to the same stuff as before.
12368     assert(wrapped1.ptr is &buffer1);
12369     assert(wrapped2.ptr is &buffer2);
12370     assert(wrapped1.ptr !is wrapped2.ptr);
12371 
12372     //But buffer2 has changed due to the assignment.
12373     assert(buffer1 == [6, 7, 8, 9, 10]);
12374     assert(buffer2 == [11, 12, 13, 14, 15]);
12375 
12376     wrapped2 = null;
12377 
12378     //The pointer changed for wrapped2 but not wrapped1.
12379     assert(wrapped1.ptr is &buffer1);
12380     assert(wrapped2.ptr is null);
12381     assert(wrapped1.ptr !is wrapped2.ptr);
12382 
12383     //buffer2 is not affected by the assignment.
12384     assert(buffer1 == [6, 7, 8, 9, 10]);
12385     assert(buffer2 == [11, 12, 13, 14, 15]);
12386 }
12387 
12388 @system unittest
12389 {
12390     import std.algorithm.iteration : filter;
12391     {
12392         ubyte[] buffer = [1, 2, 3, 4, 5];
12393         auto wrapper = refRange(&buffer);
12394         auto p = wrapper.ptr;
12395         auto f = wrapper.front;
12396         wrapper.front = f;
12397         auto e = wrapper.empty;
12398         wrapper.popFront();
12399         auto s = wrapper.save;
12400         auto b = wrapper.back;
12401         wrapper.back = b;
12402         wrapper.popBack();
12403         auto i = wrapper[0];
12404         wrapper.moveFront();
12405         wrapper.moveBack();
12406         wrapper.moveAt(0);
12407         auto l = wrapper.length;
12408         auto sl = wrapper[0 .. 1];
12409         assert(wrapper[0 .. $].length == buffer[0 .. $].length);
12410     }
12411 
12412     {
12413         ubyte[] buffer = [1, 2, 3, 4, 5];
12414         const wrapper = refRange(&buffer);
12415         const p = wrapper.ptr;
12416         const f = wrapper.front;
12417         const e = wrapper.empty;
12418         const s = wrapper.save;
12419         const b = wrapper.back;
12420         const i = wrapper[0];
12421         const l = wrapper.length;
12422         const sl = wrapper[0 .. 1];
12423     }
12424 
12425     {
12426         ubyte[] buffer = [1, 2, 3, 4, 5];
12427         auto filtered = filter!"true"(buffer);
12428         auto wrapper = refRange(&filtered);
12429         auto p = wrapper.ptr;
12430         auto f = wrapper.front;
12431         wrapper.front = f;
12432         auto e = wrapper.empty;
12433         wrapper.popFront();
12434         auto s = wrapper.save;
12435         wrapper.moveFront();
12436     }
12437 
12438     {
12439         ubyte[] buffer = [1, 2, 3, 4, 5];
12440         auto filtered = filter!"true"(buffer);
12441         const wrapper = refRange(&filtered);
12442         const p = wrapper.ptr;
12443 
12444         //Cannot currently be const. filter needs to be updated to handle const.
12445         /+
12446         const f = wrapper.front;
12447         const e = wrapper.empty;
12448         const s = wrapper.save;
12449         +/
12450     }
12451 
12452     {
12453         string str = "hello world";
12454         auto wrapper = refRange(&str);
12455         auto p = wrapper.ptr;
12456         auto f = wrapper.front;
12457         auto e = wrapper.empty;
12458         wrapper.popFront();
12459         auto s = wrapper.save;
12460         auto b = wrapper.back;
12461         wrapper.popBack();
12462     }
12463 
12464     {
12465         // https://issues.dlang.org/show_bug.cgi?id=16534
12466         // opDollar should be defined if the wrapped range defines length.
12467         auto range = 10.iota.takeExactly(5);
12468         auto wrapper = refRange(&range);
12469         assert(wrapper.length == 5);
12470         assert(wrapper[0 .. $ - 1].length == 4);
12471     }
12472 }
12473 
12474 //Test assignment.
12475 @system unittest
12476 {
12477     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12478     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12479     RefRange!(ubyte[]) wrapper1;
12480     RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
12481     assert(wrapper1.ptr is null);
12482     assert(wrapper2.ptr is &buffer2);
12483 
12484     wrapper1 = refRange(&buffer1);
12485     assert(wrapper1.ptr is &buffer1);
12486 
12487     wrapper1 = wrapper2;
12488     assert(wrapper1.ptr is &buffer1);
12489     assert(buffer1 == buffer2);
12490 
12491     wrapper1 = RefRange!(ubyte[]).init;
12492     assert(wrapper1.ptr is null);
12493     assert(wrapper2.ptr is &buffer2);
12494     assert(buffer1 == buffer2);
12495     assert(buffer1 == [6, 7, 8, 9, 10]);
12496 
12497     wrapper2 = null;
12498     assert(wrapper2.ptr is null);
12499     assert(buffer2 == [6, 7, 8, 9, 10]);
12500 }
12501 
12502 @system unittest
12503 {
12504     import std.algorithm.comparison : equal;
12505     import std.algorithm.mutation : bringToFront;
12506     import std.algorithm.searching : commonPrefix, find, until;
12507     import std.algorithm.sorting : sort;
12508 
12509     //Test that ranges are properly consumed.
12510     {
12511         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12512         auto wrapper = refRange(&arr);
12513 
12514         assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12515         assert(arr == [41, 3, 40, 4, 42, 9]);
12516 
12517         assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12518         assert(arr == [40, 4, 42, 9]);
12519 
12520         assert(equal(until(wrapper, 42), [40, 4]));
12521         assert(arr == [42, 9]);
12522 
12523         assert(find(wrapper, 12).empty);
12524         assert(arr.empty);
12525     }
12526 
12527     {
12528         string str = "Hello, world-like object.";
12529         auto wrapper = refRange(&str);
12530 
12531         assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12532         assert(str == "llo, world-like object.");
12533 
12534         assert(equal(take(wrapper, 5), "llo, "));
12535         assert(str == "world-like object.");
12536     }
12537 
12538     //Test that operating on saved ranges does not consume the original.
12539     {
12540         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12541         auto wrapper = refRange(&arr);
12542         auto saved = wrapper.save;
12543         saved.popFrontN(3);
12544         assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12545         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12546     }
12547 
12548     {
12549         string str = "Hello, world-like object.";
12550         auto wrapper = refRange(&str);
12551         auto saved = wrapper.save;
12552         saved.popFrontN(13);
12553         assert(*saved.ptr == "like object.");
12554         assert(str == "Hello, world-like object.");
12555     }
12556 
12557     //Test that functions which use save work properly.
12558     {
12559         int[] arr = [1, 42];
12560         auto wrapper = refRange(&arr);
12561         assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12562     }
12563 
12564     {
12565         int[] arr = [4, 5, 6, 7, 1, 2, 3];
12566         auto wrapper = refRange(&arr);
12567         assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12568         assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12569     }
12570 
12571     //Test bidirectional functions.
12572     {
12573         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12574         auto wrapper = refRange(&arr);
12575 
12576         assert(wrapper.back == 9);
12577         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12578 
12579         wrapper.popBack();
12580         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12581     }
12582 
12583     {
12584         string str = "Hello, world-like object.";
12585         auto wrapper = refRange(&str);
12586 
12587         assert(wrapper.back == '.');
12588         assert(str == "Hello, world-like object.");
12589 
12590         wrapper.popBack();
12591         assert(str == "Hello, world-like object");
12592     }
12593 
12594     //Test random access functions.
12595     {
12596         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12597         auto wrapper = refRange(&arr);
12598 
12599         assert(wrapper[2] == 2);
12600         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12601 
12602         assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
12603         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12604     }
12605 
12606     //Test move functions.
12607     {
12608         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12609         auto wrapper = refRange(&arr);
12610 
12611         auto t1 = wrapper.moveFront();
12612         auto t2 = wrapper.moveBack();
12613         wrapper.front = t2;
12614         wrapper.back = t1;
12615         assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
12616 
12617         sort(wrapper.save);
12618         assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
12619     }
12620 }
12621 
12622 @system unittest
12623 {
12624     struct S
12625     {
12626         @property int front() @safe const pure nothrow { return 0; }
12627         enum bool empty = false;
12628         void popFront() @safe pure nothrow { }
12629         @property auto save() @safe pure nothrow return scope { return this; }
12630     }
12631 
12632     S s;
12633     auto wrapper = refRange(&s);
12634     static assert(isInfinite!(typeof(wrapper)));
12635 }
12636 
12637 @system unittest
12638 {
12639     class C
12640     {
12641         @property int front() @safe const pure nothrow { return 0; }
12642         @property bool empty() @safe const pure nothrow { return false; }
12643         void popFront() @safe pure nothrow { }
12644         @property auto save() @safe pure nothrow return scope { return this; }
12645     }
12646     static assert(isForwardRange!C);
12647 
12648     auto c = new C;
12649     auto cWrapper = refRange(&c);
12650     static assert(is(typeof(cWrapper) == C));
12651     assert(cWrapper is c);
12652 }
12653 
12654 // https://issues.dlang.org/show_bug.cgi?id=14373
12655 @system unittest
12656 {
12657     static struct R
12658     {
12659         @property int front() {return 0;}
12660         void popFront() {empty = true;}
12661         bool empty = false;
12662     }
12663     R r;
12664     refRange(&r).popFront();
12665     assert(r.empty);
12666 }
12667 
12668 // https://issues.dlang.org/show_bug.cgi?id=14575
12669 @system unittest
12670 {
12671     struct R
12672     {
12673         Object front;
12674         alias back = front;
12675         bool empty = false;
12676         void popFront() {empty = true;}
12677         alias popBack = popFront;
12678         @property R save() {return this;}
12679     }
12680     static assert(isBidirectionalRange!R);
12681     R r;
12682     auto rr = refRange(&r);
12683 
12684     struct R2
12685     {
12686         @property Object front() {return null;}
12687         @property const(Object) front() const {return null;}
12688         alias back = front;
12689         bool empty = false;
12690         void popFront() {empty = true;}
12691         alias popBack = popFront;
12692         @property R2 save() {return this;}
12693     }
12694     static assert(isBidirectionalRange!R2);
12695     R2 r2;
12696     auto rr2 = refRange(&r2);
12697 }
12698 
12699 /// ditto
12700 auto refRange(R)(R* range)
12701 if (isInputRange!R)
12702 {
12703     static if (!is(R == class))
12704         return RefRange!R(range);
12705     else
12706         return *range;
12707 }
12708 
12709 // https://issues.dlang.org/show_bug.cgi?id=9060
12710 @safe unittest
12711 {
12712     import std.algorithm.iteration : map, joiner, group;
12713     import std.algorithm.searching : until;
12714     // fix for std.algorithm
12715     auto r = map!(x => 0)([1]);
12716     chain(r, r);
12717     zip(r, r);
12718     roundRobin(r, r);
12719 
12720     struct NRAR {
12721         typeof(r) input;
12722         @property empty() { return input.empty; }
12723         @property front() { return input.front; }
12724         void popFront()   { input.popFront(); }
12725         @property save()  { return NRAR(input.save); }
12726     }
12727     auto n1 = NRAR(r);
12728     cycle(n1);  // non random access range version
12729 
12730     assumeSorted(r);
12731 
12732     // fix for std.range
12733     joiner([r], [9]);
12734 
12735     struct NRAR2 {
12736         NRAR input;
12737         @property empty() { return true; }
12738         @property front() { return input; }
12739         void popFront() { }
12740         @property save()  { return NRAR2(input.save); }
12741     }
12742     auto n2 = NRAR2(n1);
12743     joiner(n2);
12744 
12745     group(r);
12746 
12747     until(r, 7);
12748     static void foo(R)(R r) { until!(x => x > 7)(r); }
12749     foo(r);
12750 }
12751 
12752 private struct Bitwise(R)
12753 if (isInputRange!R && isIntegral!(ElementType!R))
12754 {
12755     import std.traits : Unsigned;
12756 private:
12757     alias ElemType = ElementType!R;
12758     alias UnsignedElemType = Unsigned!ElemType;
12759 
12760     R parent;
12761     enum bitsNum = ElemType.sizeof * 8;
12762     size_t maskPos = 1;
12763 
12764     static if (isBidirectionalRange!R)
12765     {
12766         size_t backMaskPos = bitsNum;
12767     }
12768 
12769 public:
12770     this()(auto ref R range)
12771     {
12772         parent = range;
12773     }
12774 
12775     static if (isInfinite!R)
12776     {
12777         enum empty = false;
12778     }
12779     else
12780     {
12781         /**
12782          * Check if the range is empty
12783          *
12784          * Returns: a boolean true or false
12785          */
12786         bool empty()
12787         {
12788             static if (hasLength!R)
12789             {
12790                 return length == 0;
12791             }
12792             else static if (isBidirectionalRange!R)
12793             {
12794                 if (parent.empty)
12795                 {
12796                     return true;
12797                 }
12798                 else
12799                 {
12800                     /*
12801                        If we have consumed the last element of the range both from
12802                        the front and the back, then the masks positions will overlap
12803                      */
12804                     return parent.save.dropOne.empty && (maskPos > backMaskPos);
12805                 }
12806             }
12807             else
12808             {
12809                 /*
12810                    If we consumed the last element of the range, but not all the
12811                    bits in the last element
12812                  */
12813                 return parent.empty;
12814             }
12815         }
12816     }
12817 
12818     bool front()
12819     {
12820         assert(!empty);
12821         return (parent.front & mask(maskPos)) != 0;
12822     }
12823 
12824     void popFront()
12825     {
12826         assert(!empty);
12827         ++maskPos;
12828         if (maskPos > bitsNum)
12829         {
12830             parent.popFront;
12831             maskPos = 1;
12832         }
12833     }
12834 
12835     static if (hasLength!R)
12836     {
12837         size_t length()
12838         {
12839             auto len = parent.length * bitsNum - (maskPos - 1);
12840             static if (isBidirectionalRange!R)
12841             {
12842                 len -= bitsNum - backMaskPos;
12843             }
12844             return len;
12845         }
12846 
12847         alias opDollar = length;
12848     }
12849 
12850     static if (isForwardRange!R)
12851     {
12852         typeof(this) save()
12853         {
12854             auto result = this;
12855             result.parent = parent.save;
12856             return result;
12857         }
12858     }
12859 
12860     static if (isBidirectionalRange!R)
12861     {
12862         bool back()
12863         {
12864             assert(!empty);
12865             return (parent.back & mask(backMaskPos)) != 0;
12866         }
12867 
12868         void popBack()
12869         {
12870             assert(!empty);
12871             --backMaskPos;
12872             if (backMaskPos == 0)
12873             {
12874                 parent.popBack;
12875                 backMaskPos = bitsNum;
12876             }
12877         }
12878     }
12879 
12880     static if (isRandomAccessRange!R)
12881     {
12882         /**
12883           Return the `n`th bit within the range
12884          */
12885         bool opIndex(size_t n)
12886         in
12887         {
12888             /*
12889                If it does not have the length property, it means that R is
12890                an infinite range
12891              */
12892             static if (hasLength!R)
12893             {
12894                 assert(n < length, "Index out of bounds");
12895             }
12896         }
12897         do
12898         {
12899             immutable size_t remainingBits = bitsNum - maskPos + 1;
12900             // If n >= maskPos, then the bit sign will be 1, otherwise 0
12901             immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12902             /*
12903                By truncating n with remainingBits bits we have skipped the
12904                remaining bits in parent[0], so we need to add 1 to elemIndex.
12905 
12906                Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
12907              */
12908             import core.bitop : bsf;
12909             immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12910 
12911             /*
12912                Since the indexing is from LSB to MSB, we need to index at the
12913                remainder of (n - remainingBits).
12914 
12915                Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
12916              */
12917             immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12918                              + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12919 
12920             return (parent[elemIndex] & mask(elemMaskPos)) != 0;
12921         }
12922 
12923         static if (hasAssignableElements!R)
12924         {
12925             /**
12926               Assigns `flag` to the `n`th bit within the range
12927              */
12928             void opIndexAssign(bool flag, size_t n)
12929                 in
12930                 {
12931                     static if (hasLength!R)
12932                     {
12933                         assert(n < length, "Index out of bounds");
12934                     }
12935                 }
12936             do
12937             {
12938                 import core.bitop : bsf;
12939 
12940                 immutable size_t remainingBits = bitsNum - maskPos + 1;
12941                 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12942                 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12943                 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12944                     + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12945 
12946                 auto elem = parent[elemIndex];
12947                 auto elemMask = mask(elemMaskPos);
12948                 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
12949                         + (flag ^ 1) * (elem & ~elemMask));
12950             }
12951         }
12952 
12953         Bitwise!R opSlice()
12954         {
12955             return this.save;
12956         }
12957 
12958         Bitwise!R opSlice(size_t start, size_t end)
12959         in
12960         {
12961             assert(start < end, "Invalid bounds: end <= start");
12962         }
12963         do
12964         {
12965             import core.bitop : bsf;
12966 
12967             size_t remainingBits = bitsNum - maskPos + 1;
12968             ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12969             immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
12970             immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
12971                                               + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
12972 
12973             immutable size_t sliceLen = end - start - 1;
12974             remainingBits = bitsNum - startElemMaskPos + 1;
12975             sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12976             immutable size_t endElemIndex = startElemIndex
12977                                           + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
12978             immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
12979                                             + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
12980 
12981             typeof(return) result;
12982             // Get the slice to be returned from the parent
12983             result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
12984             result.maskPos = startElemMaskPos;
12985             static if (isBidirectionalRange!R)
12986             {
12987                 result.backMaskPos = endElemMaskPos;
12988             }
12989             return result;
12990         }
12991     }
12992 
12993 private:
12994     auto mask(size_t maskPos)
12995     {
12996         return (1UL << (maskPos - 1UL));
12997     }
12998 }
12999 
13000 /**
13001 Bitwise adapter over an integral type range. Consumes the range elements bit by
13002 bit, from the least significant bit to the most significant bit.
13003 
13004 Params:
13005     R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
13006     range = range to consume bit by by
13007 
13008 Returns:
13009     A `Bitwise` input range with propagated forward, bidirectional
13010     and random access capabilities
13011 */
13012 auto bitwise(R)(auto ref R range)
13013 if (isInputRange!R && isIntegral!(ElementType!R))
13014 {
13015     return Bitwise!R(range);
13016 }
13017 
13018 ///
13019 @safe pure unittest
13020 {
13021     import std.algorithm.comparison : equal;
13022     import std.format : format;
13023 
13024     // 00000011 00001001
13025     ubyte[] arr = [3, 9];
13026     auto r = arr.bitwise;
13027 
13028     // iterate through it as with any other range
13029     assert(format("%(%d%)", r) == "1100000010010000");
13030     assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
13031 
13032     auto r2 = r[5 .. $];
13033     // set a bit
13034     r[2] = 1;
13035     assert(arr[0] == 7);
13036     assert(r[5] == r2[0]);
13037 }
13038 
13039 /// You can use bitwise to implement an uniform bool generator
13040 @safe unittest
13041 {
13042     import std.algorithm.comparison : equal;
13043     import std.random : rndGen;
13044 
13045     auto rb = rndGen.bitwise;
13046     static assert(isInfinite!(typeof(rb)));
13047 
13048     auto rb2 = rndGen.bitwise;
13049     // Don't forget that structs are passed by value
13050     assert(rb.take(10).equal(rb2.take(10)));
13051 }
13052 
13053 // Test nogc inference
13054 @safe @nogc unittest
13055 {
13056     static ubyte[] arr = [3, 9];
13057     auto bw = arr.bitwise;
13058     auto bw2 = bw[];
13059     auto bw3 = bw[8 .. $];
13060     bw3[2] = true;
13061 
13062     assert(arr[1] == 13);
13063     assert(bw[$ - 6]);
13064     assert(bw[$ - 6] == bw2[$ - 6]);
13065     assert(bw[$ - 6] == bw3[$ - 6]);
13066 }
13067 
13068 // Test all range types over all integral types
13069 @safe pure nothrow unittest
13070 {
13071     import std.meta : AliasSeq;
13072     import std.internal.test.dummyrange;
13073 
13074     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13075             long, ulong);
13076     foreach (IntegralType; IntegralTypes)
13077     {
13078         foreach (T; AllDummyRangesType!(IntegralType[]))
13079         {
13080             T a;
13081             auto bw = Bitwise!T(a);
13082 
13083             static if (isForwardRange!T)
13084             {
13085                 auto bwFwdSave = bw.save;
13086             }
13087 
13088             static if (isBidirectionalRange!T)
13089             {
13090                 auto bwBack = bw.save;
13091                 auto bwBackSave = bw.save;
13092             }
13093 
13094             static if (hasLength!T)
13095             {
13096                 auto bwLength = bw.length;
13097                 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
13098                 static if (isForwardRange!T)
13099                 {
13100                     assert(bw.length == bwFwdSave.length);
13101                 }
13102             }
13103 
13104             // Make sure front and back are not the mechanisms that modify the range
13105             long numCalls = 42;
13106             bool initialFrontValue;
13107 
13108             if (!bw.empty)
13109             {
13110                 initialFrontValue = bw.front;
13111             }
13112 
13113             while (!bw.empty && (--numCalls))
13114             {
13115                 bw.front;
13116                 assert(bw.front == initialFrontValue);
13117             }
13118 
13119             /*
13120                Check that empty works properly and that popFront does not get called
13121                more times than it should
13122              */
13123             numCalls = 0;
13124             while (!bw.empty)
13125             {
13126                 ++numCalls;
13127 
13128                 static if (hasLength!T)
13129                 {
13130                     assert(bw.length == bwLength);
13131                     --bwLength;
13132                 }
13133 
13134                 static if (isForwardRange!T)
13135                 {
13136                     assert(bw.front == bwFwdSave.front);
13137                     bwFwdSave.popFront();
13138                 }
13139 
13140                 static if (isBidirectionalRange!T)
13141                 {
13142                     assert(bwBack.front == bwBackSave.front);
13143                     bwBack.popBack();
13144                     bwBackSave.popBack();
13145                 }
13146                 bw.popFront();
13147             }
13148 
13149             auto rangeLen = numCalls / (IntegralType.sizeof * 8);
13150             assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
13151             assert(bw.empty);
13152             static if (isForwardRange!T)
13153             {
13154                 assert(bwFwdSave.empty);
13155             }
13156 
13157             static if (isBidirectionalRange!T)
13158             {
13159                 assert(bwBack.empty);
13160             }
13161         }
13162     }
13163 }
13164 
13165 // Test opIndex and opSlice
13166 @system unittest
13167 {
13168     import std.meta : AliasSeq;
13169     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13170             long, ulong);
13171     foreach (IntegralType; IntegralTypes)
13172     {
13173         size_t bitsNum = IntegralType.sizeof * 8;
13174 
13175         auto first = cast(IntegralType)(1);
13176 
13177         // 2 ^ (bitsNum - 1)
13178         auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
13179 
13180         IntegralType[] a = [first, second];
13181         auto bw = Bitwise!(IntegralType[])(a);
13182 
13183         // Check against lsb of a[0]
13184         assert(bw[0] == true);
13185         // Check against msb - 1 of a[1]
13186         assert(bw[2 * bitsNum - 2] == true);
13187 
13188         bw.popFront();
13189         assert(bw[2 * bitsNum - 3] == true);
13190 
13191         import std.exception : assertThrown;
13192 
13193         version (D_NoBoundsChecks) {}
13194         else
13195         {
13196             // Check out of bounds error
13197             assertThrown!Error(bw[2 * bitsNum - 1]);
13198         }
13199 
13200         bw[2] = true;
13201         assert(bw[2] == true);
13202         bw.popFront();
13203         assert(bw[1] == true);
13204 
13205         auto bw2 = bw[0 .. $ - 5];
13206         auto bw3 = bw2[];
13207         assert(bw2.length == (bw.length - 5));
13208         assert(bw2.length == bw3.length);
13209         bw2.popFront();
13210         assert(bw2.length != bw3.length);
13211     }
13212 }
13213 
13214 /*********************************
13215  * An OutputRange that discards the data it receives.
13216  */
13217 struct NullSink
13218 {
13219     void put(E)(scope const E) pure @safe @nogc nothrow {}
13220 }
13221 
13222 /// ditto
13223 auto ref nullSink()
13224 {
13225     static NullSink sink;
13226     return sink;
13227 }
13228 
13229 ///
13230 @safe nothrow unittest
13231 {
13232     import std.algorithm.iteration : map;
13233     import std.algorithm.mutation : copy;
13234     [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
13235 }
13236 
13237 ///
13238 @safe unittest
13239 {
13240     import std.csv : csvNextToken;
13241 
13242     string line = "a,b,c";
13243 
13244     // ignore the first column
13245     line.csvNextToken(nullSink, ',', '"');
13246     line.popFront;
13247 
13248     // look at the second column
13249     Appender!string app;
13250     line.csvNextToken(app, ',', '"');
13251     assert(app.data == "b");
13252 }
13253 
13254 @safe unittest
13255 {
13256     auto r = 10.iota
13257                 .tee(nullSink)
13258                 .dropOne;
13259 
13260     assert(r.front == 1);
13261 }
13262 
13263 /++
13264 
13265   Implements a "tee" style pipe, wrapping an input range so that elements of the
13266   range can be passed to a provided function or $(LREF OutputRange) as they are
13267   iterated over. This is useful for printing out intermediate values in a long
13268   chain of range code, performing some operation with side-effects on each call
13269   to `front` or `popFront`, or diverting the elements of a range into an
13270   auxiliary $(LREF OutputRange).
13271 
13272   It is important to note that as the resultant range is evaluated lazily,
13273   in the case of the version of `tee` that takes a function, the function
13274   will not actually be executed until the range is "walked" using functions
13275   that evaluate ranges, such as $(REF array, std,array) or
13276   $(REF fold, std,algorithm,iteration).
13277 
13278   Params:
13279   pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
13280   calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
13281   respectively, `fun`). Note that each `popFront()` call will mirror the
13282   old `front` value, not the new one. This means that the last value will
13283   not be forwarded if the range isn't iterated until empty. If
13284   `No.pipeOnPop`, only elements for which `front` does get called will be
13285   also sent to `outputRange`/`fun`. If `front` is called twice for the same
13286   element, it will still be sent only once. If this caching is undesired,
13287   consider using $(REF map, std,algorithm,iteration) instead.
13288   inputRange = The input range being passed through.
13289   outputRange = This range will receive elements of `inputRange` progressively
13290   as iteration proceeds.
13291   fun = This function will be called with elements of `inputRange`
13292   progressively as iteration proceeds.
13293 
13294   Returns:
13295   An input range that offers the elements of `inputRange`. Regardless of
13296   whether `inputRange` is a more powerful range (forward, bidirectional etc),
13297   the result is always an input range. Reading this causes `inputRange` to be
13298   iterated and returns its elements in turn. In addition, the same elements
13299   will be passed to `outputRange` or `fun` as well.
13300 
13301   See_Also: $(REF each, std,algorithm,iteration)
13302 +/
13303 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
13304 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
13305 {
13306     static struct Result
13307     {
13308         private R1 _input;
13309         private R2 _output;
13310         static if (!pipeOnPop)
13311         {
13312             private bool _frontAccessed;
13313         }
13314 
13315         mixin ImplementLength!_input;
13316 
13317         static if (isInfinite!R1)
13318         {
13319             enum bool empty = false;
13320         }
13321         else
13322         {
13323             @property bool empty() { return _input.empty; }
13324         }
13325 
13326         void popFront()
13327         {
13328             assert(!_input.empty, "Attempting to popFront an empty tee");
13329             static if (pipeOnPop)
13330             {
13331                 put(_output, _input.front);
13332             }
13333             else
13334             {
13335                 _frontAccessed = false;
13336             }
13337             _input.popFront();
13338         }
13339 
13340         @property auto ref front()
13341         {
13342             assert(!_input.empty, "Attempting to fetch the front of an empty tee");
13343             static if (!pipeOnPop)
13344             {
13345                 if (!_frontAccessed)
13346                 {
13347                     _frontAccessed = true;
13348                     put(_output, _input.front);
13349                 }
13350             }
13351             return _input.front;
13352         }
13353     }
13354 
13355     return Result(inputRange, outputRange);
13356 }
13357 
13358 /// Ditto
13359 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
13360 if (is(typeof(fun) == void) || isSomeFunction!fun)
13361 {
13362     import std.traits : isDelegate, isFunctionPointer;
13363     /*
13364         Distinguish between function literals and template lambdas
13365         when using either as an $(LREF OutputRange). Since a template
13366         has no type, typeof(template) will always return void.
13367         If it's a template lambda, it's first necessary to instantiate
13368         it with `ElementType!R1`.
13369     */
13370     static if (is(typeof(fun) == void))
13371         alias _fun = fun!(ElementType!R1);
13372     else
13373         alias _fun = fun;
13374 
13375     static if (isFunctionPointer!_fun || isDelegate!_fun)
13376     {
13377         return tee!pipeOnPop(inputRange, _fun);
13378     }
13379     else
13380     {
13381         return tee!pipeOnPop(inputRange, &_fun);
13382     }
13383 }
13384 
13385 ///
13386 @safe unittest
13387 {
13388     import std.algorithm.comparison : equal;
13389     import std.algorithm.iteration : filter, map;
13390 
13391     // Sum values while copying
13392     int[] values = [1, 4, 9, 16, 25];
13393     int sum = 0;
13394     auto newValues = values.tee!(a => sum += a).array;
13395     assert(equal(newValues, values));
13396     assert(sum == 1 + 4 + 9 + 16 + 25);
13397 
13398     // Count values that pass the first filter
13399     int count = 0;
13400     auto newValues4 = values.filter!(a => a < 10)
13401                             .tee!(a => count++)
13402                             .map!(a => a + 1)
13403                             .filter!(a => a < 10);
13404 
13405     //Fine, equal also evaluates any lazy ranges passed to it.
13406     //count is not 3 until equal evaluates newValues4
13407     assert(equal(newValues4, [2, 5]));
13408     assert(count == 3);
13409 }
13410 
13411 //
13412 @safe unittest
13413 {
13414     import std.algorithm.comparison : equal;
13415     import std.algorithm.iteration : filter, map;
13416 
13417     int[] values = [1, 4, 9, 16, 25];
13418 
13419     int count = 0;
13420     auto newValues = values.filter!(a => a < 10)
13421         .tee!(a => count++, No.pipeOnPop)
13422         .map!(a => a + 1)
13423         .filter!(a => a < 10);
13424 
13425     auto val = newValues.front;
13426     assert(count == 1);
13427     //front is only evaluated once per element
13428     val = newValues.front;
13429     assert(count == 1);
13430 
13431     //popFront() called, fun will be called
13432     //again on the next access to front
13433     newValues.popFront();
13434     newValues.front;
13435     assert(count == 2);
13436 
13437     int[] preMap = new int[](3), postMap = [];
13438     auto mappedValues = values.filter!(a => a < 10)
13439         //Note the two different ways of using tee
13440         .tee(preMap)
13441         .map!(a => a + 1)
13442         .tee!(a => postMap ~= a)
13443         .filter!(a => a < 10);
13444     assert(equal(mappedValues, [2, 5]));
13445     assert(equal(preMap, [1, 4, 9]));
13446     assert(equal(postMap, [2, 5, 10]));
13447 }
13448 
13449 //
13450 @safe unittest
13451 {
13452     import std.algorithm.comparison : equal;
13453     import std.algorithm.iteration : filter, map;
13454 
13455     char[] txt = "Line one, Line 2".dup;
13456 
13457     bool isVowel(dchar c)
13458     {
13459         import std.string : indexOf;
13460         return "AaEeIiOoUu".indexOf(c) != -1;
13461     }
13462 
13463     int vowelCount = 0;
13464     int shiftedCount = 0;
13465     auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
13466                                 .filter!(c => !isVowel(c))
13467                                 .map!(c => (c == ' ') ? c : c + 1)
13468                                 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
13469     assert(equal(removeVowels, "Mo o- Mo 3"));
13470     assert(vowelCount == 6);
13471     assert(shiftedCount == 3);
13472 }
13473 
13474 @safe unittest
13475 {
13476     // Manually stride to test different pipe behavior.
13477     void testRange(Range)(Range r)
13478     {
13479         const int strideLen = 3;
13480         int i = 0;
13481         ElementType!Range elem1;
13482         ElementType!Range elem2;
13483         while (!r.empty)
13484         {
13485             if (i % strideLen == 0)
13486             {
13487                 //Make sure front is only
13488                 //evaluated once per item
13489                 elem1 = r.front;
13490                 elem2 = r.front;
13491                 assert(elem1 == elem2);
13492             }
13493             r.popFront();
13494             i++;
13495         }
13496     }
13497 
13498     string txt = "abcdefghijklmnopqrstuvwxyz";
13499 
13500     int popCount = 0;
13501     auto pipeOnPop = txt.tee!(a => popCount++);
13502     testRange(pipeOnPop);
13503     assert(popCount == 26);
13504 
13505     int frontCount = 0;
13506     auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13507     testRange(pipeOnFront);
13508     assert(frontCount == 9);
13509 }
13510 
13511 @safe unittest
13512 {
13513     import std.algorithm.comparison : equal;
13514     import std.meta : AliasSeq;
13515 
13516     //Test diverting elements to an OutputRange
13517     string txt = "abcdefghijklmnopqrstuvwxyz";
13518 
13519     dchar[] asink1 = [];
13520     auto fsink = (dchar c) { asink1 ~= c; };
13521     auto result1 = txt.tee(fsink).array;
13522     assert(equal(txt, result1) && (equal(result1, asink1)));
13523 
13524     dchar[] _asink1 = [];
13525     auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13526     assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13527 
13528     dchar[] asink2 = new dchar[](txt.length);
13529     void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13530     auto result2 = txt.tee(&fsink2).array;
13531     assert(equal(txt, result2) && equal(result2, asink2));
13532 
13533     dchar[] asink3 = new dchar[](txt.length);
13534     auto result3 = txt.tee(asink3).array;
13535     assert(equal(txt, result3) && equal(result3, asink3));
13536 
13537     static foreach (CharType; AliasSeq!(char, wchar, dchar))
13538     {{
13539         auto appSink = appender!(CharType[])();
13540         auto appResult = txt.tee(appSink).array;
13541         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13542     }}
13543 
13544     static foreach (StringType; AliasSeq!(string, wstring, dstring))
13545     {{
13546         auto appSink = appender!StringType();
13547         auto appResult = txt.tee(appSink).array;
13548         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13549     }}
13550 }
13551 
13552 // https://issues.dlang.org/show_bug.cgi?id=13483
13553 @safe unittest
13554 {
13555     static void func1(T)(T x) {}
13556     void func2(int x) {}
13557 
13558     auto r = [1, 2, 3, 4].tee!func1.tee!func2;
13559 }
13560 
13561 /**
13562 Extends the length of the input range `r` by padding out the start of the
13563 range with the element `e`. The element `e` must be of a common type with
13564 the element type of the range `r` as defined by $(REF CommonType, std, traits).
13565 If `n` is less than the length of of `r`, then `r` is returned unmodified.
13566 
13567 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
13568 about length for strings, which is not the number of characters, or
13569 graphemes, but instead the number of encoding units. If you want to treat each
13570 grapheme as only one encoding unit long, then call
13571 $(REF byGrapheme, std, uni) before calling this function.
13572 
13573 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
13574 
13575 Params:
13576     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
13577     e = element to pad the range with
13578     n = the length to pad to
13579 
13580 Returns:
13581     A range containing the elements of the original range with the extra padding
13582 
13583 See Also:
13584     $(REF leftJustifier, std, string)
13585 */
13586 auto padLeft(R, E)(R r, E e, size_t n)
13587 if (
13588     ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
13589     !is(CommonType!(ElementType!R, E) == void)
13590 )
13591 {
13592     static if (hasLength!R)
13593         auto dataLength = r.length;
13594     else
13595         auto dataLength = r.save.walkLength(n);
13596 
13597     return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
13598 }
13599 
13600 ///
13601 @safe pure unittest
13602 {
13603     import std.algorithm.comparison : equal;
13604 
13605     assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
13606     assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
13607 
13608     assert("abc".padLeft('_', 6).equal("___abc"));
13609 }
13610 
13611 @safe pure nothrow unittest
13612 {
13613     import std.algorithm.comparison : equal;
13614     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
13615     import std.meta : AliasSeq;
13616 
13617     alias DummyRanges = AliasSeq!(
13618         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
13619         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
13620         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
13621         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
13622         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
13623         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
13624         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
13625         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
13626         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
13627         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
13628     );
13629 
13630     foreach (Range; DummyRanges)
13631     {
13632         Range r;
13633         assert(r
13634             .padLeft(0, 12)
13635             .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13636         );
13637     }
13638 }
13639 
13640 // Test nogc inference
13641 @safe @nogc pure unittest
13642 {
13643     import std.algorithm.comparison : equal;
13644 
13645     static immutable r1 = [1, 2, 3, 4];
13646     static immutable r2 = [0, 0, 1, 2, 3, 4];
13647     assert(r1.padLeft(0, 6).equal(r2));
13648 }
13649 
13650 /**
13651 Extend the length of the input range `r` by padding out the end of the range
13652 with the element `e`. The element `e` must be of a common type with the
13653 element type of the range `r` as defined by $(REF CommonType, std, traits).
13654 If `n` is less than the length of of `r`, then the contents of `r` are
13655 returned.
13656 
13657 The range primitives that the resulting range provides depends whether or not `r`
13658 provides them. Except the functions `back` and `popBack`, which also require
13659 the range to have a length as well as `back` and `popBack`
13660 
13661 Params:
13662     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
13663     e = element to pad the range with
13664     n = the length to pad to
13665 
13666 Returns:
13667     A range containing the elements of the original range with the extra padding
13668 
13669 See Also:
13670     $(REF rightJustifier, std, string)
13671 */
13672 auto padRight(R, E)(R r, E e, size_t n)
13673 if (
13674     isInputRange!R &&
13675     !isInfinite!R &&
13676     !is(CommonType!(ElementType!R, E) == void))
13677 {
13678     static struct Result
13679     {
13680         private:
13681         R data;
13682         E element;
13683         static if (hasLength!R)
13684         {
13685             size_t padLength;
13686         }
13687         else
13688         {
13689             size_t minLength;
13690             size_t consumed;
13691         }
13692 
13693         public:
13694         bool empty() @property
13695         {
13696             static if (hasLength!R)
13697             {
13698                 return data.empty && padLength == 0;
13699             }
13700             else
13701             {
13702                 return data.empty && consumed >= minLength;
13703             }
13704         }
13705 
13706         auto front() @property
13707         {
13708             assert(!empty, "Attempting to fetch the front of an empty padRight");
13709             return data.empty ? element : data.front;
13710         }
13711 
13712         void popFront()
13713         {
13714             assert(!empty, "Attempting to popFront an empty padRight");
13715 
13716             static if (hasLength!R)
13717             {
13718                 if (!data.empty)
13719                 {
13720                     data.popFront;
13721                 }
13722                 else
13723                 {
13724                     --padLength;
13725                 }
13726             }
13727             else
13728             {
13729                 ++consumed;
13730                 if (!data.empty)
13731                 {
13732                     data.popFront;
13733                 }
13734             }
13735         }
13736 
13737         static if (hasLength!R)
13738         {
13739             size_t length() @property
13740             {
13741                 return data.length + padLength;
13742             }
13743         }
13744 
13745         static if (isForwardRange!R)
13746         {
13747             auto save() @property
13748             {
13749                 typeof(this) result = this;
13750                 data = data.save;
13751                 return result;
13752             }
13753         }
13754 
13755         static if (isBidirectionalRange!R && hasLength!R)
13756         {
13757             auto back() @property
13758             {
13759                 assert(!empty, "Attempting to fetch the back of an empty padRight");
13760                 return padLength > 0 ? element : data.back;
13761             }
13762 
13763             void popBack()
13764             {
13765                 assert(!empty, "Attempting to popBack an empty padRight");
13766                 if (padLength > 0)
13767                 {
13768                     --padLength;
13769                 }
13770                 else
13771                 {
13772                     data.popBack;
13773                 }
13774             }
13775         }
13776 
13777         static if (isRandomAccessRange!R && hasLength!R)
13778         {
13779             E opIndex(size_t index)
13780             {
13781                 assert(index <= this.length, "Index out of bounds");
13782                 return index >= data.length ? element : data[index];
13783             }
13784         }
13785 
13786         static if (hasSlicing!R && hasLength!R)
13787         {
13788             auto opSlice(size_t a, size_t b)
13789             {
13790                 assert(
13791                     a <= b,
13792                     "Attempting to slice a padRight with a larger first argument than the second."
13793                 );
13794                 assert(
13795                     b <= length,
13796                     "Attempting to slice using an out of bounds index on a padRight"
13797                 );
13798                 return Result(
13799                     a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
13800                     element, b - a);
13801             }
13802 
13803             alias opDollar = length;
13804         }
13805 
13806         this(R r, E e, size_t n)
13807         {
13808             data = r;
13809             element = e;
13810             static if (hasLength!R)
13811             {
13812                 padLength = n > data.length ? n - data.length : 0;
13813             }
13814             else
13815             {
13816                 minLength = n;
13817             }
13818         }
13819 
13820         @disable this();
13821     }
13822 
13823     return Result(r, e, n);
13824 }
13825 
13826 ///
13827 @safe pure unittest
13828 {
13829     import std.algorithm.comparison : equal;
13830 
13831     assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
13832     assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
13833 
13834     assert("abc".padRight('_', 6).equal("abc___"));
13835 }
13836 
13837 pure @safe unittest
13838 {
13839     import std.algorithm.comparison : equal;
13840     import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
13841     import std.meta : AliasSeq;
13842 
13843     auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
13844     dchar padding = '_';
13845     assert(string_input_range.padRight(padding, 6).equal("abc___"));
13846 
13847     foreach (RangeType; AllDummyRanges)
13848     {
13849         RangeType r1;
13850         assert(r1
13851             .padRight(0, 12)
13852             .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13853         );
13854 
13855         // test if Result properly uses random access ranges
13856         static if (isRandomAccessRange!RangeType)
13857         {
13858             RangeType r3;
13859             assert(r3.padRight(0, 12)[0] == 1);
13860             assert(r3.padRight(0, 12)[2] == 3);
13861             assert(r3.padRight(0, 12)[9] == 10);
13862             assert(r3.padRight(0, 12)[10] == 0);
13863             assert(r3.padRight(0, 12)[11] == 0);
13864         }
13865 
13866         // test if Result properly uses slicing and opDollar
13867         static if (hasSlicing!RangeType)
13868         {
13869             RangeType r4;
13870             assert(r4
13871                 .padRight(0, 12)[0 .. 3]
13872                 .equal([1, 2, 3])
13873             );
13874             assert(r4
13875                 .padRight(0, 12)[0 .. 10]
13876                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13877             );
13878             assert(r4
13879                 .padRight(0, 12)[0 .. 11]
13880                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
13881             );
13882             assert(r4
13883                 .padRight(0, 12)[2 .. $]
13884                 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13885             );
13886             assert(r4
13887                 .padRight(0, 12)[0 .. $]
13888                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13889             );
13890         }
13891 
13892         // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
13893         RangeType r5;
13894         foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
13895     }
13896 }
13897 
13898 // Test nogc inference
13899 @safe @nogc pure unittest
13900 {
13901     import std.algorithm.comparison : equal;
13902 
13903     static immutable r1 = [1, 2, 3, 4];
13904     static immutable r2 = [1, 2, 3, 4, 0, 0];
13905     assert(r1.padRight(0, 6).equal(r2));
13906 }
13907 
13908 // Test back, popBack, and save
13909 @safe pure unittest
13910 {
13911     import std.algorithm.comparison : equal;
13912 
13913     auto r1 = [1, 2, 3, 4].padRight(0, 6);
13914     assert(r1.back == 0);
13915 
13916     r1.popBack;
13917     auto r2 = r1.save;
13918     assert(r1.equal([1, 2, 3, 4, 0]));
13919     assert(r2.equal([1, 2, 3, 4, 0]));
13920 
13921     r1.popBackN(2);
13922     assert(r1.back == 3);
13923     assert(r1.length == 3);
13924     assert(r2.length == 5);
13925     assert(r2.equal([1, 2, 3, 4, 0]));
13926 
13927     r2.popFront;
13928     assert(r2.length == 4);
13929     assert(r2[0] == 2);
13930     assert(r2[1] == 3);
13931     assert(r2[2] == 4);
13932     assert(r2[3] == 0);
13933     assert(r2.equal([2, 3, 4, 0]));
13934 
13935     r2.popBack;
13936     assert(r2.equal([2, 3, 4]));
13937 
13938     auto r3 = [1, 2, 3, 4].padRight(0, 6);
13939     size_t len = 0;
13940     while (!r3.empty)
13941     {
13942         ++len;
13943         r3.popBack;
13944     }
13945     assert(len == 6);
13946 }
13947 
13948 // https://issues.dlang.org/show_bug.cgi?id=19042
13949 @safe pure unittest
13950 {
13951     import std.algorithm.comparison : equal;
13952 
13953     assert([2, 5, 13].padRight(42, 10).chunks(5)
13954            .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
13955 
13956     assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
13957 }
13958 
13959 /**
13960 This simplifies a commonly used idiom in phobos for accepting any kind of string
13961 parameter. The type `R` can for example be a simple string, chained string using
13962 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
13963 characters.
13964 
13965 Only finite length character ranges are allowed with this constraint.
13966 
13967 This template is equivalent to:
13968 ---
13969 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
13970 ---
13971 
13972 See_Also:
13973 $(REF isInputRange, std,range,primitives),
13974 $(REF isInfinite, std,range,primitives),
13975 $(LREF isSomeChar),
13976 $(REF ElementEncodingType, std,range,primitives)
13977 */
13978 template isSomeFiniteCharInputRange(R)
13979 {
13980     import std.traits : isSomeChar;
13981 
13982     enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
13983         && isSomeChar!(ElementEncodingType!R);
13984 }
13985 
13986 ///
13987 @safe unittest
13988 {
13989     import std.path : chainPath;
13990     import std.range : chain;
13991 
13992     void someLibraryMethod(R)(R argument)
13993     if (isSomeFiniteCharInputRange!R)
13994     {
13995         // implementation detail, would iterate over each character of argument
13996     }
13997 
13998     someLibraryMethod("simple strings work");
13999     someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
14000     someLibraryMethod(chainPath("chained", "paths", "work"));
14001     // you can also use custom structs implementing a char range
14002 }
14003