The OpenD Programming Language

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()
1029                 {
1030                     if (frontIndex == 0)
1031                     {
1032                         // special handling: we might be in Range.init state!
1033                         // For instance, `format!"%s"` uses Range.init to ensure
1034                         // that formatting is possible.
1035                         // In that case, we must still behave in an internally consistent way.
1036                         return source[0].empty;
1037                     }
1038                     return frontIndex >= backIndex;
1039                 }
1040             }
1041 
1042             static if (allSatisfy!(isForwardRange, R))
1043             {
1044                 @property auto save()
1045                 {
1046                     auto saveI(size_t i)() => source[i].save;
1047 
1048                     // TODO: this has the constructor needlessly refind
1049                     // frontIndex and backIndex. It'd be better to just copy
1050                     // those from `.this`.
1051                     auto saveResult =
1052                         Result(staticMap!(saveI, aliasSeqOf!(R.length.iota)));
1053 
1054                     return saveResult;
1055                 }
1056             }
1057 
1058             void popFront()
1059             {
1060                 sw1: switch (frontIndex)
1061                 {
1062                     static foreach (i; 0 .. R.length)
1063                     {
1064                     case i:
1065                         source[i].popFront();
1066                         break sw1;
1067                     }
1068 
1069                 case R.length:
1070                     assert(0, "Attempt to `popFront` of empty `chain` range");
1071 
1072                 default:
1073                     assert(0, "Internal library error. Please report it.");
1074                 }
1075 
1076                 sw2: switch (frontIndex)
1077                 {
1078                     static foreach (i; 0 .. R.length)
1079                     {
1080                     case i:
1081                         if (source[i].empty)
1082                         {
1083                             frontIndex++;
1084                             goto case;
1085                         }
1086                         else break sw2;
1087                     }
1088 
1089                 // Only possible to reach from goto of previous case.
1090                 case R.length:
1091                     break;
1092 
1093                 default:
1094                     assert(0, "Internal library error. Please report it.");
1095                 }
1096             }
1097 
1098             @property auto ref front()
1099             {
1100                 switch (frontIndex)
1101                 {
1102                     static foreach (i; 0 .. R.length)
1103                     {
1104                     case i:
1105                         return fixRef(source[i].front);
1106                     }
1107 
1108                 case R.length:
1109                     assert(0, "Attempt to get `front` of empty `chain` range");
1110 
1111                 default:
1112                     assert(0, "Internal library error. Please report it.");
1113                 }
1114             }
1115 
1116             static if (assignableElements)
1117             {
1118                 // @@@BUG@@@
1119                 //@property void front(T)(T v) if (is(T : RvalueElementType))
1120 
1121                 @property void front(RvalueElementType v)
1122                 {
1123                     import std.algorithm.mutation : move;
1124 
1125                     sw: switch (frontIndex)
1126                     {
1127                         static foreach (i; 0 .. R.length)
1128                         {
1129                         case i:
1130                             source[i].front = move(v);
1131                             break sw;
1132                         }
1133 
1134                     case R.length:
1135                         assert(0, "Attempt to set `front` of empty `chain` range");
1136 
1137                     default:
1138                         assert(0, "Internal library error. Please report it.");
1139                     }
1140                 }
1141             }
1142 
1143             static if (mobileElements)
1144             {
1145                 RvalueElementType moveFront()
1146                 {
1147                     switch (frontIndex)
1148                     {
1149                         static foreach (i; 0 .. R.length)
1150                         {
1151                         case i:
1152                             return source[i].moveFront();
1153                         }
1154 
1155                     case R.length:
1156                         assert(0, "Attempt to `moveFront` of empty `chain` range");
1157 
1158                     default:
1159                         assert(0, "Internal library error. Please report it.");
1160                     }
1161                 }
1162             }
1163 
1164             static if (bidirectional)
1165             {
1166                 @property auto ref back()
1167                 {
1168                     switch (backIndex)
1169                     {
1170                         static foreach_reverse (i; 1 .. R.length + 1)
1171                         {
1172                         case i:
1173                             return fixRef(source[i-1].back);
1174                         }
1175 
1176                     case 0:
1177                         assert(0, "Attempt to get `back` of empty `chain` range");
1178 
1179                     default:
1180                         assert(0, "Internal library error. Please report it.");
1181                     }
1182                 }
1183 
1184                 void popBack()
1185                 {
1186                     sw1: switch (backIndex)
1187                     {
1188                         static foreach_reverse (i; 1 .. R.length + 1)
1189                         {
1190                         case i:
1191                             source[i-1].popBack();
1192                             break sw1;
1193                         }
1194 
1195                     case 0:
1196                         assert(0, "Attempt to `popFront` of empty `chain` range");
1197 
1198                     default:
1199                         assert(0, "Internal library error. Please report it.");
1200                     }
1201 
1202                     sw2: switch (backIndex)
1203                     {
1204                         static foreach_reverse (i; 1 .. R.length + 1)
1205                         {
1206                         case i:
1207                             if (source[i-1].empty)
1208                             {
1209                                 backIndex--;
1210                                 goto case;
1211                             }
1212                             else break sw2;
1213                         }
1214 
1215                     // Only possible to reach from goto of previous case.
1216                     case 0:
1217                         break;
1218 
1219                     default:
1220                         assert(0, "Internal library error. Please report it.");
1221                     }
1222                 }
1223 
1224                 static if (mobileElements)
1225                 {
1226                     RvalueElementType moveBack()
1227                     {
1228                         switch (backIndex)
1229                         {
1230                             static foreach_reverse (i; 1 .. R.length + 1)
1231                             {
1232                             case i:
1233                                 return source[i-1].moveBack();
1234                             }
1235 
1236                         case 0:
1237                             assert(0, "Attempt to `moveBack` of empty `chain` range");
1238 
1239                         default:
1240                             assert(0, "Internal library error. Please report it.");
1241                         }
1242                     }
1243                 }
1244 
1245                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1246                 {
1247                     @property void back(RvalueElementType v)
1248                     {
1249                         import std.algorithm.mutation : move;
1250 
1251                         sw: switch (backIndex)
1252                         {
1253                             static foreach_reverse (i; 1 .. R.length + 1)
1254                             {
1255                             case i:
1256                                 source[i-1].back = move(v);
1257                                 break sw;
1258                             }
1259 
1260                         case 0:
1261                             assert(0, "Attempt to set `back` of empty `chain` range");
1262 
1263                         default:
1264                             assert(0, "Internal library error. Please report it.");
1265                         }
1266                     }
1267                 }
1268             }
1269 
1270             static if (allSatisfy!(hasLength, R))
1271             {
1272                 @property size_t length()
1273                 {
1274                     size_t result = 0;
1275                     sw: switch (frontIndex)
1276                     {
1277                         static foreach (i; 0 .. R.length)
1278                         {
1279                         case i:
1280                             result += source[i].length;
1281                             if (backIndex == i+1) break sw;
1282                             else goto case;
1283                         }
1284 
1285                     case R.length:
1286                         break;
1287 
1288                     default:
1289                         assert(0, "Internal library error. Please report it.");
1290                     }
1291 
1292                     return result;
1293                 }
1294 
1295                 alias opDollar = length;
1296             }
1297 
1298             static if (allSatisfy!(isRandomAccessRange, R))
1299             {
1300                 auto ref opIndex(size_t index)
1301                 {
1302                     switch (frontIndex)
1303                     {
1304                         static foreach (i; 0 .. R.length)
1305                         {
1306                         case i:
1307                             static if (!isInfinite!(R[i]))
1308                             {
1309                                 immutable length = source[i].length;
1310                                 if (index >= length)
1311                                 {
1312                                     index -= length;
1313                                     goto case;
1314                                 }
1315                             }
1316 
1317                             return fixRef(source[i][index]);
1318                         }
1319 
1320                     case R.length:
1321                         assert(0, "Attempt to access out-of-bounds index of `chain` range");
1322 
1323                     default:
1324                         assert(0, "Internal library error. Please report it.");
1325                     }
1326                 }
1327 
1328                 static if (mobileElements)
1329                 {
1330                     RvalueElementType moveAt(size_t index)
1331                     {
1332                         switch (frontIndex)
1333                         {
1334                             static foreach (i; 0 .. R.length)
1335                             {
1336                             case i:
1337                                 static if (!isInfinite!(R[i]))
1338                                 {
1339                                     immutable length = source[i].length;
1340                                     if (index >= length)
1341                                     {
1342                                         index -= length;
1343                                         goto case;
1344                                     }
1345                                 }
1346 
1347                                 return source[i].moveAt(index);
1348                             }
1349 
1350                         case R.length:
1351                             assert(0, "Attempt to move out-of-bounds index of `chain` range");
1352 
1353                         default:
1354                             assert(0, "Internal library error. Please report it.");
1355                         }
1356                     }
1357                 }
1358 
1359                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1360                     void opIndexAssign(ElementType v, size_t index)
1361                     {
1362                         import std.algorithm.mutation : move;
1363 
1364                         sw: switch (frontIndex)
1365                         {
1366                             static foreach (i; 0 .. R.length)
1367                             {
1368                             case i:
1369                                 static if (!isInfinite!(R[i]))
1370                                 {
1371                                     immutable length = source[i].length;
1372                                     if (index >= length)
1373                                     {
1374                                         index -= length;
1375                                         goto case;
1376                                     }
1377                                 }
1378 
1379                                 source[i][index] = move(v);
1380                                 break sw;
1381                             }
1382 
1383                         case R.length:
1384                             assert(0, "Attempt to write out-of-bounds index of `chain` range");
1385 
1386                         default:
1387                             assert(0, "Internal library error. Please report it.");
1388                         }
1389                     }
1390             }
1391 
1392             static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
1393                 auto opSlice(size_t begin, size_t end) return scope
1394                 {
1395                     // force staticMap type conversion to Rebindable
1396                     static struct ResultRanges
1397                     {
1398                         staticMap!(Rebindable, typeof(source)) fields;
1399                     }
1400                     auto sourceI(size_t i)() => rebindable(this.source[i]);
1401                     auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields;
1402                     size_t resultFrontIndex = this.frontIndex;
1403                     static if (bidirectional)
1404                         size_t resultBackIndex = this.backIndex;
1405 
1406                     sw: switch (frontIndex)
1407                     {
1408                         static foreach (i; 0 .. R.length)
1409                         {
1410                         case i:
1411                             immutable len = resultRanges[i].length;
1412                             if (len <= begin)
1413                             {
1414                                 resultRanges[i] = resultRanges[i]
1415                                     [len .. len];
1416                                 begin -= len;
1417                                 resultFrontIndex++;
1418                                 goto case;
1419                             }
1420                             else
1421                             {
1422                                 resultRanges[i] = resultRanges[i]
1423                                     [begin .. len];
1424                                 break sw;
1425                             }
1426                         }
1427 
1428                     case R.length:
1429                         assert(begin == 0,
1430                             "Attempt to access out-of-bounds slice of `chain` range");
1431                         break;
1432 
1433                     default:
1434                         assert(0, "Internal library error. Please report it.");
1435                     }
1436 
1437                     // Overflow intentional if end index too big.
1438                     // This will trigger the bounds check failure below.
1439                     auto cut = length - end;
1440 
1441                     sw2: switch (backIndex)
1442                     {
1443                         static foreach_reverse (i; 1 .. R.length + 1)
1444                         {
1445                         case i:
1446                             immutable len = resultRanges[i-1].length;
1447                             if (len <= cut)
1448                             {
1449                                 resultRanges[i-1] = resultRanges[i-1]
1450                                     [0 .. 0];
1451                                 cut -= len;
1452                                 resultBackIndex--;
1453                                 goto case;
1454                             }
1455                             else
1456                             {
1457                                 resultRanges[i-1] = resultRanges[i-1]
1458                                     [0 .. len - cut];
1459                                 break sw2;
1460                             }
1461                         }
1462 
1463                     case 0:
1464                         assert(cut == 0, end > length?
1465                             "Attempt to access out-of-bounds slice of `chain` range":
1466                             "Attempt to access negative length slice of `chain` range");
1467                         break sw2;
1468 
1469                     default:
1470                         assert(0, "Internal library error. Please report it.");
1471                     }
1472 
1473                     static if (bidirectional)
1474                         return Result(resultRanges, resultFrontIndex, resultBackIndex);
1475                     else
1476                         return Result(resultRanges, resultFrontIndex);
1477                 }
1478         }
1479         return Result(rs);
1480     }
1481 }
1482 
1483 ///
1484 pure @safe nothrow unittest
1485 {
1486     import std.algorithm.comparison : equal;
1487 
1488     int[] arr1 = [ 1, 2, 3, 4 ];
1489     int[] arr2 = [ 5, 6 ];
1490     int[] arr3 = [ 7 ];
1491     auto s = chain(arr1, arr2, arr3);
1492     assert(s.length == 7);
1493     assert(s[5] == 6);
1494     assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1495 }
1496 
1497 /**
1498  * Range primitives are carried over to the returned range if
1499  * all of the ranges provide them
1500  */
1501 pure @safe nothrow unittest
1502 {
1503     import std.algorithm.comparison : equal;
1504     import std.algorithm.sorting : sort;
1505 
1506     int[] arr1 = [5, 2, 8];
1507     int[] arr2 = [3, 7, 9];
1508     int[] arr3 = [1, 4, 6];
1509 
1510     // in-place sorting across all of the arrays
1511     auto s = arr1.chain(arr2, arr3).sort;
1512 
1513     assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1514     assert(arr1.equal([1, 2, 3]));
1515     assert(arr2.equal([4, 5, 6]));
1516     assert(arr3.equal([7, 8, 9]));
1517 }
1518 
1519 /**
1520 Due to safe type promotion in D, chaining together different
1521 character ranges results in a `uint` range.
1522 
1523 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf),
1524 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges
1525 to get the type you need.
1526  */
1527 pure @safe nothrow unittest
1528 {
1529     import std.utf : byChar, byCodeUnit;
1530 
1531     auto s1 = "string one";
1532     auto s2 = "string two";
1533     // s1 and s2 front is dchar because of auto-decoding
1534     static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
1535 
1536     auto r1 = s1.chain(s2);
1537     // chains of ranges of the same character type give that same type
1538     static assert(is(typeof(r1.front) == dchar));
1539 
1540     auto s3 = "string three".byCodeUnit;
1541     static assert(is(typeof(s3.front) == immutable char));
1542     auto r2 = s1.chain(s3);
1543     // chaining ranges of mixed character types gives `dchar`
1544     static assert(is(typeof(r2.front) == dchar));
1545 
1546     // use byChar on character ranges to correctly convert them to UTF-8
1547     auto r3 = s1.byChar.chain(s3);
1548     static assert(is(typeof(r3.front) == immutable char));
1549 }
1550 
1551 pure @safe nothrow unittest
1552 {
1553     import std.algorithm.comparison : equal;
1554     import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1555                                           propagatesRangeType;
1556 
1557     {
1558         int[] arr1 = [ 1, 2, 3, 4 ];
1559         int[] arr2 = [ 5, 6 ];
1560         int[] arr3 = [ 7 ];
1561         int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1562         auto s1 = chain(arr1);
1563         static assert(isRandomAccessRange!(typeof(s1)));
1564         auto s2 = chain(arr1, arr2);
1565         static assert(isBidirectionalRange!(typeof(s2)));
1566         static assert(isRandomAccessRange!(typeof(s2)));
1567         s2.front = 1;
1568         auto s = chain(arr1, arr2, arr3);
1569         assert(s[5] == 6);
1570         assert(equal(s, witness));
1571         assert(s[4 .. 6].equal(arr2));
1572         assert(s[2 .. 5].equal([3, 4, 5]));
1573         assert(s[0 .. 0].empty);
1574         assert(s[7 .. $].empty);
1575         assert(s[5] == 6);
1576     }
1577     {
1578         int[] arr1 = [ 1, 2, 3, 4 ];
1579         int[] witness = [ 1, 2, 3, 4 ];
1580         assert(equal(chain(arr1), witness));
1581     }
1582     {
1583         uint[] foo = [1,2,3,4,5];
1584         uint[] bar = [1,2,3,4,5];
1585         auto c = chain(foo, bar);
1586         c[3] = 42;
1587         assert(c[3] == 42);
1588         assert(c.moveFront() == 1);
1589         assert(c.moveBack() == 5);
1590         assert(c.moveAt(4) == 5);
1591         assert(c.moveAt(5) == 1);
1592     }
1593 
1594 
1595     // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed.
1596     // elements are mutable.
1597     assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1598 
1599     // Test the case where infinite ranges are present.
1600     auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1601     assert(inf[0] == 0);
1602     assert(inf[3] == 4);
1603     assert(inf[6] == 4);
1604     assert(inf[7] == 5);
1605     static assert(isInfinite!(typeof(inf)));
1606 
1607     immutable int[] immi = [ 1, 2, 3 ];
1608     immutable float[] immf = [ 1, 2, 3 ];
1609     static assert(is(typeof(chain(immi, immf))));
1610 
1611     // Check that chain at least instantiates and compiles with every possible
1612     // pair of DummyRange types, in either order.
1613 
1614     foreach (DummyType1; AllDummyRanges)
1615     (){ // workaround slow optimizations for large functions
1616         // https://issues.dlang.org/show_bug.cgi?id=2396
1617         DummyType1 dummy1;
1618         foreach (DummyType2; AllDummyRanges)
1619         {
1620             DummyType2 dummy2;
1621             auto myChain = chain(dummy1, dummy2);
1622 
1623             static assert(
1624                 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1625             );
1626 
1627             assert(myChain.front == 1);
1628             foreach (i; 0 .. dummyLength)
1629             {
1630                 myChain.popFront();
1631             }
1632             assert(myChain.front == 1);
1633 
1634             static if (isBidirectionalRange!DummyType1 &&
1635                       isBidirectionalRange!DummyType2) {
1636                 assert(myChain.back == 10);
1637             }
1638 
1639             static if (isRandomAccessRange!DummyType1 &&
1640                       isRandomAccessRange!DummyType2) {
1641                 assert(myChain[0] == 1);
1642             }
1643 
1644             static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1645             {
1646                 static assert(hasLvalueElements!(typeof(myChain)));
1647             }
1648             else
1649             {
1650                 static assert(!hasLvalueElements!(typeof(myChain)));
1651             }
1652         }
1653     }();
1654 }
1655 
1656 pure @safe nothrow @nogc unittest
1657 {
1658     class Foo{}
1659     immutable(Foo)[] a;
1660     immutable(Foo)[] b;
1661     assert(chain(a, b).empty);
1662 }
1663 
1664 // https://issues.dlang.org/show_bug.cgi?id=18657
1665 pure @safe unittest
1666 {
1667     import std.algorithm.comparison : equal;
1668     string s = "foo";
1669     auto r = refRange(&s).chain("bar");
1670     assert(equal(r.save, "foobar"));
1671     assert(equal(r, "foobar"));
1672 }
1673 
1674 // https://issues.dlang.org/show_bug.cgi?id=23844
1675 pure @safe unittest
1676 {
1677     struct S
1678     {
1679         immutable int value;
1680     }
1681 
1682     auto range = chain(only(S(5)), only(S(6)));
1683     assert(range.array == [S(5), S(6)]);
1684 }
1685 
1686 /// https://issues.dlang.org/show_bug.cgi?id=24064
1687 pure @safe nothrow unittest
1688 {
1689     import std.algorithm.comparison : equal;
1690     import std.typecons : Nullable;
1691 
1692     immutable Nullable!string foo = "b";
1693     string[] bar = ["a"];
1694     assert(chain(bar, foo).equal(["a", "b"]));
1695 }
1696 
1697 pure @safe nothrow @nogc unittest
1698 {
1699     // support non-copyable items
1700 
1701     static struct S {
1702         int v;
1703         @disable this(this);
1704     }
1705 
1706     S[2] s0, s1;
1707     foreach (ref el; chain(s0[], s1[]))
1708     {
1709         int n = el.v;
1710     }
1711 
1712     S[] s2, s3;
1713     foreach (ref el; chain(s2, s3))
1714     {
1715         int n = el.v;
1716     }
1717 }
1718 
1719 /// https://issues.dlang.org/show_bug.cgi?id=24243
1720 pure @safe nothrow unittest
1721 {
1722     import std.algorithm.iteration : filter;
1723 
1724     auto range = chain([2], [3].filter!"a");
1725 
1726     // This might happen in format!"%s"(range), for instance.
1727     assert(typeof(range).init.empty);
1728 }
1729 
1730 /**
1731 Choose one of two ranges at runtime depending on a Boolean condition.
1732 
1733 The ranges may be different, but they must have compatible element types (i.e.
1734 `CommonType` must exist for the two element types). The result is a range
1735 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D
1736 R1) is a random-access range and `R2` is a forward range).
1737 
1738 Params:
1739     condition = which range to choose: `r1` if `true`, `r2` otherwise
1740     r1 = the "true" range
1741     r2 = the "false" range
1742 
1743 Returns:
1744     A range type dependent on `R1` and `R2`.
1745  */
1746 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
1747 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1748     !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1749 {
1750     size_t choice = condition? 0: 1;
1751     return ChooseResult!(R1, R2)(choice, r1, r2);
1752 }
1753 
1754 ///
1755 @safe nothrow pure @nogc unittest
1756 {
1757     import std.algorithm.comparison : equal;
1758     import std.algorithm.iteration : filter, map;
1759 
1760     auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
1761     auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
1762 
1763     // choose() is primarily useful when you need to select one of two ranges
1764     // with different types at runtime.
1765     static assert(!is(typeof(data1) == typeof(data2)));
1766 
1767     auto chooseRange(bool pickFirst)
1768     {
1769         // The returned range is a common wrapper type that can be used for
1770         // returning or storing either range without running into a type error.
1771         return choose(pickFirst, data1, data2);
1772 
1773         // Simply returning the chosen range without using choose() does not
1774         // work, because map() and filter() return different types.
1775         //return pickFirst ? data1 : data2; // does not compile
1776     }
1777 
1778     auto result = chooseRange(true);
1779     assert(result.equal(only(1, 2, 4)));
1780 
1781     result = chooseRange(false);
1782     assert(result.equal(only(6, 7, 8, 9)));
1783 }
1784 
1785 
1786 private struct ChooseResult(Ranges...)
1787 {
1788     import std.meta : aliasSeqOf, ApplyLeft;
1789     import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor,
1790         lvalueOf;
1791 
1792     private union
1793     {
1794         Ranges rs;
1795     }
1796     private size_t chosenI;
1797 
1798     private static auto ref actOnChosen(alias foo, ExtraArgs ...)
1799         (ref ChooseResult r, auto ref ExtraArgs extraArgs)
1800     {
1801         ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1802 
1803         switch (r.chosenI)
1804         {
1805             static foreach (candI; 0 .. rs.length)
1806             {
1807                 case candI: return foo(getI!candI(r), extraArgs);
1808             }
1809 
1810             default: assert(false);
1811         }
1812     }
1813 
1814     // @trusted because of assignment of r which overlap each other
1815     this(size_t chosen, return scope Ranges rs) @trusted
1816     {
1817         import core.lifetime : emplace;
1818 
1819         // This should be the only place chosenI is ever assigned
1820         // independently
1821         this.chosenI = chosen;
1822 
1823         // Otherwise the compiler will complain about skipping these fields
1824         static foreach (i; 0 .. rs.length)
1825         {
1826             this.rs[i] = Ranges[i].init;
1827         }
1828 
1829         // The relevant field needs to be initialized last so it will overwrite
1830         // the other initializations and not the other way around.
1831         sw: switch (chosenI)
1832         {
1833             static foreach (i; 0 .. rs.length)
1834             {
1835                 case i:
1836                 emplace(&this.rs[i], rs[i]);
1837                 break sw;
1838             }
1839 
1840             default: assert(false);
1841         }
1842     }
1843 
1844     // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/)
1845     // without this overload the regular constructor would invert the meaning of
1846     // the boolean
1847     static if (rs.length == 2)
1848     pragma(inline, true)
1849     deprecated("Call with size_t (0 = first), or use the choose function")
1850     this(bool firstChosen, Ranges rs)
1851     {
1852         import core.lifetime : move;
1853         this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move);
1854     }
1855 
1856     void opAssign(ChooseResult r)
1857     {
1858         ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1859 
1860         static if (anySatisfy!(hasElaborateDestructor, Ranges))
1861             if (chosenI != r.chosenI)
1862         {
1863             // destroy the current item
1864             actOnChosen!((ref r) => destroy(r))(this);
1865         }
1866         chosenI = r.chosenI;
1867 
1868         sw: switch (chosenI)
1869         {
1870             static foreach (candI; 0 .. rs.length)
1871             {
1872                 case candI: getI!candI(this) = getI!candI(r);
1873                 break sw;
1874             }
1875 
1876             default: assert(false);
1877         }
1878     }
1879 
1880     // Carefully defined postblit to postblit the appropriate range
1881     static if (anySatisfy!(hasElaborateCopyConstructor, Ranges))
1882     this(this)
1883     {
1884         actOnChosen!((ref r) {
1885                 static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit();
1886             })(this);
1887     }
1888 
1889     static if (anySatisfy!(hasElaborateDestructor, Ranges))
1890     ~this()
1891     {
1892         actOnChosen!((ref r) => destroy(r))(this);
1893     }
1894 
1895     // Propagate infiniteness.
1896     static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false;
1897     else @property bool empty()
1898     {
1899         return actOnChosen!(r => r.empty)(this);
1900     }
1901 
1902     @property auto ref front()
1903     {
1904         static auto ref getFront(R)(ref R r) { return r.front; }
1905         return actOnChosen!getFront(this);
1906     }
1907 
1908     void popFront()
1909     {
1910         return actOnChosen!((ref r) { r.popFront; })(this);
1911     }
1912 
1913     static if (allSatisfy!(isForwardRange, Ranges))
1914     @property auto save() // return scope inferred
1915     {
1916         auto saveOrInit(size_t i)()
1917         {
1918             ref getI() @trusted { return rs[i]; }
1919             if (i == chosenI) return getI().save;
1920             else return Ranges[i].init;
1921         }
1922 
1923         return typeof(this)(chosenI, staticMap!(saveOrInit,
1924             aliasSeqOf!(rs.length.iota)));
1925     }
1926 
1927     template front(T)
1928     {
1929         private enum overloadValidFor(alias r) = is(typeof(r.front = T.init));
1930 
1931         static if (allSatisfy!(overloadValidFor, rs))
1932         void front(T v)
1933         {
1934             actOnChosen!((ref r, T v) { r.front = v; })(this, v);
1935         }
1936     }
1937 
1938     static if (allSatisfy!(hasMobileElements, Ranges))
1939     auto moveFront()
1940     {
1941         return actOnChosen!((ref r) => r.moveFront)(this);
1942     }
1943 
1944     static if (allSatisfy!(isBidirectionalRange, Ranges))
1945     {
1946         @property auto ref back()
1947         {
1948             static auto ref getBack(R)(ref R r) { return r.back; }
1949             return actOnChosen!getBack(this);
1950         }
1951 
1952         void popBack()
1953         {
1954             actOnChosen!((ref r) { r.popBack; })(this);
1955         }
1956 
1957         static if (allSatisfy!(hasMobileElements, Ranges))
1958         auto moveBack()
1959         {
1960             return actOnChosen!((ref r) => r.moveBack)(this);
1961         }
1962 
1963         template back(T)
1964         {
1965             private enum overloadValidFor(alias r) = is(typeof(r.back = T.init));
1966 
1967             static if (allSatisfy!(overloadValidFor, rs))
1968             void back(T v)
1969             {
1970                 actOnChosen!((ref r, T v) { r.back = v; })(this, v);
1971             }
1972         }
1973     }
1974 
1975     static if (allSatisfy!(hasLength, Ranges))
1976     {
1977         @property size_t length()
1978         {
1979             return actOnChosen!(r => r.length)(this);
1980         }
1981         alias opDollar = length;
1982     }
1983 
1984     static if (allSatisfy!(isRandomAccessRange, Ranges))
1985     {
1986         auto ref opIndex(size_t index)
1987         {
1988             static auto ref get(R)(ref R r, size_t index) { return r[index]; }
1989             return actOnChosen!get(this, index);
1990         }
1991 
1992         static if (allSatisfy!(hasMobileElements, Ranges))
1993             auto moveAt(size_t index)
1994             {
1995                 return actOnChosen!((ref r, size_t index) => r.moveAt(index))
1996                     (this, index);
1997             }
1998 
1999         private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init));
2000 
2001         template opIndexAssign(T)
2002         if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges))
2003         {
2004             void opIndexAssign(T v, size_t index)
2005             {
2006                 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
2007                     (this, index, v);
2008             }
2009         }
2010     }
2011 
2012     static if (allSatisfy!(hasSlicing, Ranges))
2013     auto opSlice(size_t begin, size_t end)
2014     {
2015         alias Slice(R) = typeof(R.init[0 .. 1]);
2016         alias Slices = staticMap!(Slice, Ranges);
2017 
2018         auto sliceOrInit(size_t i)()
2019         {
2020             ref getI() @trusted { return rs[i]; }
2021             return i == chosenI? getI()[begin .. end]: Slices[i].init;
2022         }
2023 
2024         return chooseAmong(chosenI, staticMap!(sliceOrInit,
2025             aliasSeqOf!(rs.length.iota)));
2026     }
2027 }
2028 
2029 // https://issues.dlang.org/show_bug.cgi?id=18657
2030 pure @safe unittest
2031 {
2032     import std.algorithm.comparison : equal;
2033     string s = "foo";
2034     auto r = choose(true, refRange(&s), "bar");
2035     assert(equal(r.save, "foo"));
2036     assert(equal(r, "foo"));
2037 }
2038 
2039 @safe unittest
2040 {
2041     static void* p;
2042     static struct R
2043     {
2044         void* q;
2045         int front;
2046         bool empty;
2047         void popFront() {}
2048         // `p = q;` is only there to prevent inference of `scope return`.
2049         @property @safe R save() { p = q; return this; }
2050 
2051     }
2052     R r;
2053     choose(true, r, r).save;
2054 }
2055 
2056 // Make sure ChooseResult.save doesn't trust @system user code.
2057 @system unittest // copy is @system
2058 {
2059     static struct R
2060     {
2061         int front;
2062         bool empty;
2063         void popFront() {}
2064         this(this) @system {}
2065         @property R save() { return R(front, empty); }
2066     }
2067     choose(true, R(), R()).save;
2068     choose(true, [0], R()).save;
2069     choose(true, R(), [0]).save;
2070 }
2071 
2072 @safe unittest // copy is @system
2073 {
2074     static struct R
2075     {
2076         int front;
2077         bool empty;
2078         void popFront() {}
2079         this(this) @system {}
2080         @property R save() { return R(front, empty); }
2081     }
2082     static assert(!__traits(compiles, choose(true, R(), R()).save));
2083     static assert(!__traits(compiles, choose(true, [0], R()).save));
2084     static assert(!__traits(compiles, choose(true, R(), [0]).save));
2085 }
2086 
2087 @system unittest // .save is @system
2088 {
2089     static struct R
2090     {
2091         int front;
2092         bool empty;
2093         void popFront() {}
2094         @property R save() @system { return this; }
2095     }
2096     choose(true, R(), R()).save;
2097     choose(true, [0], R()).save;
2098     choose(true, R(), [0]).save;
2099 }
2100 
2101 @safe unittest // .save is @system
2102 {
2103     static struct R
2104     {
2105         int front;
2106         bool empty;
2107         void popFront() {}
2108         @property R save() @system { return this; }
2109     }
2110     static assert(!__traits(compiles, choose(true, R(), R()).save));
2111     static assert(!__traits(compiles, choose(true, [0], R()).save));
2112     static assert(!__traits(compiles, choose(true, R(), [0]).save));
2113 }
2114 
2115 //https://issues.dlang.org/show_bug.cgi?id=19738
2116 @safe nothrow pure @nogc unittest
2117 {
2118     static struct EvilRange
2119     {
2120         enum empty = true;
2121         int front;
2122         void popFront() @safe {}
2123         auto opAssign(const ref EvilRange other)
2124         {
2125             *(cast(uint*) 0xcafebabe) = 0xdeadbeef;
2126             return this;
2127         }
2128     }
2129 
2130     static assert(!__traits(compiles, () @safe
2131     {
2132         auto c1 = choose(true, EvilRange(), EvilRange());
2133         auto c2 = c1;
2134         c1 = c2;
2135     }));
2136 }
2137 
2138 
2139 // https://issues.dlang.org/show_bug.cgi?id=20495
2140 @safe unittest
2141 {
2142     static struct KillableRange
2143     {
2144         int *item;
2145         ref int front() { return *item; }
2146         bool empty() { return *item > 10; }
2147         void popFront() { ++(*item); }
2148         this(this)
2149         {
2150             assert(item is null || cast(size_t) item > 1000);
2151             item = new int(*item);
2152         }
2153         KillableRange save() { return this; }
2154     }
2155 
2156     auto kr = KillableRange(new int(1));
2157     int[] x = [1,2,3,4,5]; // length is first
2158 
2159     auto chosen = choose(true, x, kr);
2160     auto chosen2 = chosen.save;
2161 }
2162 
2163 pure @safe nothrow unittest
2164 {
2165     static struct S {
2166         int v;
2167         @disable this(this);
2168     }
2169 
2170     auto a = [S(1), S(2), S(3)];
2171     auto b = [S(4), S(5), S(6)];
2172 
2173     auto chosen = choose(true, a, b);
2174     assert(chosen.front.v == 1);
2175 
2176     auto chosen2 = choose(false, a, b);
2177     assert(chosen2.front.v == 4);
2178 }
2179 
2180 /**
2181 Choose one of multiple ranges at runtime.
2182 
2183 The ranges may be different, but they must have compatible element types. The
2184 result is a range that offers the weakest capabilities of all `Ranges`.
2185 
2186 Params:
2187     index = which range to choose, must be less than the number of ranges
2188     rs = two or more ranges
2189 
2190 Returns:
2191     The indexed range. If rs consists of only one range, the return type is an
2192     alias of that range's type.
2193  */
2194 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
2195 if (Ranges.length >= 2
2196         && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
2197         && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
2198 {
2199         return ChooseResult!Ranges(index, rs);
2200 }
2201 
2202 ///
2203 @safe nothrow pure @nogc unittest
2204 {
2205     auto test()
2206     {
2207         import std.algorithm.comparison : equal;
2208 
2209         int[4] sarr1 = [1, 2, 3, 4];
2210         int[2] sarr2 = [5, 6];
2211         int[1] sarr3 = [7];
2212         auto arr1 = sarr1[];
2213         auto arr2 = sarr2[];
2214         auto arr3 = sarr3[];
2215 
2216         {
2217             auto s = chooseAmong(0, arr1, arr2, arr3);
2218             auto t = s.save;
2219             assert(s.length == 4);
2220             assert(s[2] == 3);
2221             s.popFront();
2222             assert(equal(t, only(1, 2, 3, 4)));
2223         }
2224         {
2225             auto s = chooseAmong(1, arr1, arr2, arr3);
2226             assert(s.length == 2);
2227             s.front = 8;
2228             assert(equal(s, only(8, 6)));
2229         }
2230         {
2231             auto s = chooseAmong(1, arr1, arr2, arr3);
2232             assert(s.length == 2);
2233             s[1] = 9;
2234             assert(equal(s, only(8, 9)));
2235         }
2236         {
2237             auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
2238             assert(s.length == 2);
2239             assert(equal(s, only(2, 3)));
2240         }
2241         {
2242             auto s = chooseAmong(0, arr1, arr2, arr3);
2243             assert(s.length == 4);
2244             assert(s.back == 4);
2245             s.popBack();
2246             s.back = 5;
2247             assert(equal(s, only(1, 2, 5)));
2248             s.back = 3;
2249             assert(equal(s, only(1, 2, 3)));
2250         }
2251         {
2252             uint[5] foo = [1, 2, 3, 4, 5];
2253             uint[5] bar = [6, 7, 8, 9, 10];
2254             auto c = chooseAmong(1, foo[], bar[]);
2255             assert(c[3] == 9);
2256             c[3] = 42;
2257             assert(c[3] == 42);
2258             assert(c.moveFront() == 6);
2259             assert(c.moveBack() == 10);
2260             assert(c.moveAt(4) == 10);
2261         }
2262         {
2263             import std.range : cycle;
2264             auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
2265             assert(isInfinite!(typeof(s)));
2266             assert(!s.empty);
2267             assert(s[100] == 8);
2268             assert(s[101] == 9);
2269             assert(s[0 .. 3].equal(only(8, 9, 8)));
2270         }
2271         return 0;
2272     }
2273     // works at runtime
2274     auto a = test();
2275     // and at compile time
2276     static b = test();
2277 }
2278 
2279 @safe nothrow pure @nogc unittest
2280 {
2281     int[3] a = [1, 2, 3];
2282     long[3] b = [4, 5, 6];
2283     auto c = chooseAmong(0, a[], b[]);
2284     c[0] = 42;
2285     assert(c[0] == 42);
2286 }
2287 
2288 @safe nothrow pure @nogc unittest
2289 {
2290     static struct RefAccessRange
2291     {
2292         int[] r;
2293         ref front() @property { return r[0]; }
2294         ref back() @property { return r[$ - 1]; }
2295         void popFront() { r = r[1 .. $]; }
2296         void popBack() { r = r[0 .. $ - 1]; }
2297         auto empty() @property { return r.empty; }
2298         ref opIndex(size_t i) { return r[i]; }
2299         auto length() @property { return r.length; }
2300         alias opDollar = length;
2301         auto save() { return this; }
2302     }
2303     static assert(isRandomAccessRange!RefAccessRange);
2304     static assert(isRandomAccessRange!RefAccessRange);
2305     int[4] a = [4, 3, 2, 1];
2306     int[2] b = [6, 5];
2307     auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[]));
2308 
2309     void refFunc(ref int a, int target) { assert(a == target); }
2310 
2311     refFunc(c[2], 2);
2312     refFunc(c.front, 4);
2313     refFunc(c.back, 1);
2314 }
2315 
2316 
2317 /**
2318 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`,
2319 then `r3.front`, after which it pops off one element from each and
2320 continues again from `r1`. For example, if two ranges are involved,
2321 it alternately yields elements off the two ranges. `roundRobin`
2322 stops after it has consumed all ranges (skipping over the ones that
2323 finish early).
2324  */
2325 auto roundRobin(Rs...)(Rs rs)
2326 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
2327 {
2328     struct Result
2329     {
2330         import std.conv : to;
2331 
2332         public Rs source;
2333         private size_t _current = size_t.max;
2334 
2335         @property bool empty()
2336         {
2337             foreach (i, Unused; Rs)
2338             {
2339                 if (!source[i].empty) return false;
2340             }
2341             return true;
2342         }
2343 
2344         @property auto ref front()
2345         {
2346             final switch (_current)
2347             {
2348                 foreach (i, R; Rs)
2349                 {
2350                     case i:
2351                         assert(
2352                             !source[i].empty,
2353                             "Attempting to fetch the front of an empty roundRobin"
2354                         );
2355                         return source[i].front;
2356                 }
2357             }
2358             assert(0);
2359         }
2360 
2361         void popFront()
2362         {
2363             final switch (_current)
2364             {
2365                 foreach (i, R; Rs)
2366                 {
2367                     case i:
2368                         source[i].popFront();
2369                         break;
2370                 }
2371             }
2372 
2373             auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
2374             final switch (next)
2375             {
2376                 foreach (i, R; Rs)
2377                 {
2378                     case i:
2379                         if (!source[i].empty)
2380                         {
2381                             _current = i;
2382                             return;
2383                         }
2384                         if (i == _current)
2385                         {
2386                             _current = _current.max;
2387                             return;
2388                         }
2389                         goto case (i + 1) % Rs.length;
2390                 }
2391             }
2392         }
2393 
2394         static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
2395             @property auto save()
2396             {
2397                 auto saveSource(size_t len)()
2398                 {
2399                     import std.typecons : tuple;
2400                     static assert(len > 0);
2401                     static if (len == 1)
2402                     {
2403                         return tuple(source[0].save);
2404                     }
2405                     else
2406                     {
2407                         return saveSource!(len - 1)() ~
2408                             tuple(source[len - 1].save);
2409                     }
2410                 }
2411                 return Result(saveSource!(Rs.length).expand, _current);
2412             }
2413 
2414         static if (allSatisfy!(hasLength, Rs))
2415         {
2416             @property size_t length()
2417             {
2418                 size_t result;
2419                 foreach (i, R; Rs)
2420                 {
2421                     result += source[i].length;
2422                 }
2423                 return result;
2424             }
2425 
2426             alias opDollar = length;
2427         }
2428     }
2429 
2430     return Result(rs, 0);
2431 }
2432 
2433 ///
2434 @safe unittest
2435 {
2436     import std.algorithm.comparison : equal;
2437 
2438     int[] a = [ 1, 2, 3 ];
2439     int[] b = [ 10, 20, 30, 40 ];
2440     auto r = roundRobin(a, b);
2441     assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
2442 }
2443 
2444 /**
2445  * roundRobin can be used to create "interleave" functionality which inserts
2446  * an element between each element in a range.
2447  */
2448 @safe unittest
2449 {
2450     import std.algorithm.comparison : equal;
2451 
2452     auto interleave(R, E)(R range, E element)
2453     if ((isInputRange!R && hasLength!R) || isForwardRange!R)
2454     {
2455         static if (hasLength!R)
2456             immutable len = range.length;
2457         else
2458             immutable len = range.save.walkLength;
2459 
2460         return roundRobin(
2461             range,
2462             element.repeat(len - 1)
2463         );
2464     }
2465 
2466     assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
2467 }
2468 
2469 pure @safe unittest
2470 {
2471     import std.algorithm.comparison : equal;
2472     string f = "foo", b = "bar";
2473     auto r = roundRobin(refRange(&f), refRange(&b));
2474     assert(equal(r.save, "fboaor"));
2475     assert(equal(r.save, "fboaor"));
2476 }
2477 pure @safe nothrow unittest
2478 {
2479     import std.algorithm.comparison : equal;
2480 
2481     static struct S {
2482         int v;
2483         @disable this(this);
2484     }
2485 
2486     S[] a = [ S(1), S(2) ];
2487     S[] b = [ S(10), S(20) ];
2488     auto r = roundRobin(a, b);
2489     assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
2490 }
2491 
2492 /**
2493 Iterates a random-access range starting from a given point and
2494 progressively extending left and right from that point. If no initial
2495 point is given, iteration starts from the middle of the
2496 range. Iteration spans the entire range.
2497 
2498 When `startingIndex` is 0 the range will be fully iterated in order
2499 and in reverse order when `r.length` is given.
2500 
2501 Params:
2502     r = a random access range with length and slicing
2503     startingIndex = the index to begin iteration from
2504 
2505 Returns:
2506     A forward range with length
2507  */
2508 auto radial(Range, I)(Range r, I startingIndex)
2509 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
2510 {
2511     if (startingIndex != r.length) ++startingIndex;
2512     return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
2513 }
2514 
2515 /// Ditto
2516 auto radial(R)(R r)
2517 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
2518 {
2519     return .radial(r, (r.length - !r.empty) / 2);
2520 }
2521 
2522 ///
2523 @safe unittest
2524 {
2525     import std.algorithm.comparison : equal;
2526     int[] a = [ 1, 2, 3, 4, 5 ];
2527     assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
2528     a = [ 1, 2, 3, 4 ];
2529     assert(equal(radial(a), [ 2, 3, 1, 4 ]));
2530 
2531     // If the left end is reached first, the remaining elements on the right
2532     // are concatenated in order:
2533     a = [ 0, 1, 2, 3, 4, 5 ];
2534     assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
2535 
2536     // If the right end is reached first, the remaining elements on the left
2537     // are concatenated in reverse order:
2538     assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
2539 }
2540 
2541 @safe unittest
2542 {
2543     import std.algorithm.comparison : equal;
2544     import std.conv : text;
2545     import std.exception : enforce;
2546     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2547 
2548     void test(int[] input, int[] witness)
2549     {
2550         enforce(equal(radial(input), witness),
2551                 text(radial(input), " vs. ", witness));
2552     }
2553     test([], []);
2554     test([ 1 ], [ 1 ]);
2555     test([ 1, 2 ], [ 1, 2 ]);
2556     test([ 1, 2, 3 ], [ 2, 3, 1 ]);
2557     test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
2558     test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
2559     test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
2560 
2561     int[] a = [ 1, 2, 3, 4, 5 ];
2562     assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
2563     assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
2564     assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
2565     static assert(isForwardRange!(typeof(radial(a, 1))));
2566 
2567     auto r = radial([1,2,3,4,5]);
2568     for (auto rr = r.save; !rr.empty; rr.popFront())
2569     {
2570         assert(rr.front == moveFront(rr));
2571     }
2572     r.front = 5;
2573     assert(r.front == 5);
2574 
2575     // Test instantiation without lvalue elements.
2576     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
2577     assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
2578 
2579     // immutable int[] immi = [ 1, 2 ];
2580     // static assert(is(typeof(radial(immi))));
2581 }
2582 
2583 @safe unittest
2584 {
2585     import std.algorithm.comparison : equal;
2586 
2587     auto LL = iota(1L, 6L);
2588     auto r = radial(LL);
2589     assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
2590 }
2591 
2592 /**
2593 Lazily takes only up to `n` elements of a range. This is
2594 particularly useful when using with infinite ranges.
2595 
2596 Unlike $(LREF takeExactly), `take` does not require that there
2597 are `n` or more elements in `input`. As a consequence, length
2598 information is not applied to the result unless `input` also has
2599 length information.
2600 
2601 Params:
2602     input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2603     to iterate over up to `n` times
2604     n = the number of elements to take
2605 
2606 Returns:
2607     At minimum, an input range. If the range offers random access
2608     and `length`, `take` offers them as well.
2609  */
2610 Take!R take(R)(R input, size_t n)
2611 if (isInputRange!(Unqual!R))
2612 {
2613     alias U = Unqual!R;
2614     static if (is(R T == Take!T))
2615     {
2616         import std.algorithm.comparison : min;
2617         return R(input.source, min(n, input._maxAvailable));
2618     }
2619     else static if (!isInfinite!U && hasSlicing!U)
2620     {
2621         import std.algorithm.comparison : min;
2622         return input[0 .. min(n, input.length)];
2623     }
2624     else
2625     {
2626         return Take!R(input, n);
2627     }
2628 }
2629 
2630 /// ditto
2631 struct Take(Range)
2632 if (isInputRange!(Unqual!Range) &&
2633     //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
2634     //take for slicing infinite ranges.
2635     !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
2636 {
2637     private alias R = Unqual!Range;
2638 
2639     /// User accessible in read and write
2640     public R source;
2641 
2642     private size_t _maxAvailable;
2643 
2644     alias Source = R;
2645 
2646     /// Range primitives
2647     @property bool empty()
2648     {
2649         return _maxAvailable == 0 || source.empty;
2650     }
2651 
2652     /// ditto
2653     @property auto ref front()
2654     {
2655         assert(!empty,
2656             "Attempting to fetch the front of an empty "
2657             ~ Take.stringof);
2658         return source.front;
2659     }
2660 
2661     /// ditto
2662     void popFront()
2663     {
2664         assert(!empty,
2665             "Attempting to popFront() past the end of a "
2666             ~ Take.stringof);
2667         source.popFront();
2668         --_maxAvailable;
2669     }
2670 
2671     static if (isForwardRange!R)
2672         /// ditto
2673         @property Take save()
2674         {
2675             return Take(source.save, _maxAvailable);
2676         }
2677 
2678     static if (hasAssignableElements!R)
2679         /// ditto
2680         @property void front(ElementType!R v)
2681         {
2682             import std.algorithm.mutation : move;
2683 
2684             assert(!empty,
2685                 "Attempting to assign to the front of an empty "
2686                 ~ Take.stringof);
2687             source.front = move(v);
2688         }
2689 
2690     static if (hasMobileElements!R)
2691     {
2692         /// ditto
2693         auto moveFront()
2694         {
2695             assert(!empty,
2696                 "Attempting to move the front of an empty "
2697                 ~ Take.stringof);
2698             return source.moveFront();
2699         }
2700     }
2701 
2702     static if (isInfinite!R)
2703     {
2704         /// ditto
2705         @property size_t length() const
2706         {
2707             return _maxAvailable;
2708         }
2709 
2710         /// ditto
2711         alias opDollar = length;
2712 
2713         //Note: Due to Take/hasSlicing circular dependency,
2714         //This needs to be a restrained template.
2715         /// ditto
2716         auto opSlice()(size_t i, size_t j)
2717         if (hasSlicing!R)
2718         {
2719             assert(i <= j, "Invalid slice bounds");
2720             assert(j <= length, "Attempting to slice past the end of a "
2721                 ~ Take.stringof);
2722             return source[i .. j];
2723         }
2724     }
2725     else static if (hasLength!R)
2726     {
2727         /// ditto
2728         @property size_t length()
2729         {
2730             import std.algorithm.comparison : min;
2731             return min(_maxAvailable, source.length);
2732         }
2733 
2734         alias opDollar = length;
2735     }
2736 
2737     static if (isRandomAccessRange!R)
2738     {
2739         /// ditto
2740         void popBack()
2741         {
2742             assert(!empty,
2743                 "Attempting to popBack() past the beginning of a "
2744                 ~ Take.stringof);
2745             --_maxAvailable;
2746         }
2747 
2748         /// ditto
2749         @property auto ref back()
2750         {
2751             assert(!empty,
2752                 "Attempting to fetch the back of an empty "
2753                 ~ Take.stringof);
2754             return source[this.length - 1];
2755         }
2756 
2757         /// ditto
2758         auto ref opIndex(size_t index)
2759         {
2760             assert(index < length,
2761                 "Attempting to index out of the bounds of a "
2762                 ~ Take.stringof);
2763             return source[index];
2764         }
2765 
2766         static if (hasAssignableElements!R)
2767         {
2768             /// ditto
2769             @property void back(ElementType!R v)
2770             {
2771                 // This has to return auto instead of void because of
2772                 // https://issues.dlang.org/show_bug.cgi?id=4706
2773                 assert(!empty,
2774                     "Attempting to assign to the back of an empty "
2775                     ~ Take.stringof);
2776                 source[this.length - 1] = v;
2777             }
2778 
2779             /// ditto
2780             void opIndexAssign(ElementType!R v, size_t index)
2781             {
2782                 assert(index < length,
2783                     "Attempting to index out of the bounds of a "
2784                     ~ Take.stringof);
2785                 source[index] = v;
2786             }
2787         }
2788 
2789         static if (hasMobileElements!R)
2790         {
2791             /// ditto
2792             auto moveBack()
2793             {
2794                 assert(!empty,
2795                     "Attempting to move the back of an empty "
2796                     ~ Take.stringof);
2797                 return source.moveAt(this.length - 1);
2798             }
2799 
2800             /// ditto
2801             auto moveAt(size_t index)
2802             {
2803                 assert(index < length,
2804                     "Attempting to index out of the bounds of a "
2805                     ~ Take.stringof);
2806                 return source.moveAt(index);
2807             }
2808         }
2809     }
2810 
2811     /**
2812     Access to maximal length of the range.
2813     Note: the actual length of the range depends on the underlying range.
2814     If it has fewer elements, it will stop before maxLength is reached.
2815     */
2816     @property size_t maxLength() const
2817     {
2818         return _maxAvailable;
2819     }
2820 }
2821 
2822 /// ditto
2823 template Take(R)
2824 if (isInputRange!(Unqual!R) &&
2825     ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2826 {
2827     alias Take = R;
2828 }
2829 
2830 ///
2831 pure @safe nothrow unittest
2832 {
2833     import std.algorithm.comparison : equal;
2834 
2835     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2836     auto s = take(arr1, 5);
2837     assert(s.length == 5);
2838     assert(s[4] == 5);
2839     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2840 }
2841 
2842 /**
2843  * If the range runs out before `n` elements, `take` simply returns the entire
2844  * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2845  * the range ends prematurely):
2846  */
2847 pure @safe nothrow unittest
2848 {
2849     import std.algorithm.comparison : equal;
2850 
2851     int[] arr2 = [ 1, 2, 3 ];
2852     auto t = take(arr2, 5);
2853     assert(t.length == 3);
2854     assert(equal(t, [ 1, 2, 3 ]));
2855 }
2856 
2857 pure @safe nothrow unittest
2858 {
2859     import std.algorithm.comparison : equal;
2860     import std.internal.test.dummyrange : AllDummyRanges;
2861 
2862     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2863     auto s = take(arr1, 5);
2864     assert(s.length == 5);
2865     assert(s[4] == 5);
2866     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2867     assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2868 
2869     // Test fix for bug 4464.
2870     static assert(is(typeof(s) == Take!(int[])));
2871     static assert(is(typeof(s) == int[]));
2872 
2873     // Test using narrow strings.
2874     import std.exception : assumeWontThrow;
2875 
2876     auto myStr = "This is a string.";
2877     auto takeMyStr = take(myStr, 7);
2878     assert(assumeWontThrow(equal(takeMyStr, "This is")));
2879     // Test fix for bug 5052.
2880     auto takeMyStrAgain = take(takeMyStr, 4);
2881     assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2882     static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
2883     takeMyStrAgain = take(takeMyStr, 10);
2884     assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
2885 
2886     foreach (DummyType; AllDummyRanges)
2887     {
2888         DummyType dummy;
2889         auto t = take(dummy, 5);
2890         alias T = typeof(t);
2891 
2892         static if (isRandomAccessRange!DummyType)
2893         {
2894             static assert(isRandomAccessRange!T);
2895             assert(t[4] == 5);
2896 
2897             assert(moveAt(t, 1) == t[1]);
2898             assert(t.back == moveBack(t));
2899         }
2900         else static if (isForwardRange!DummyType)
2901         {
2902             static assert(isForwardRange!T);
2903         }
2904 
2905         for (auto tt = t; !tt.empty; tt.popFront())
2906         {
2907             assert(tt.front == moveFront(tt));
2908         }
2909 
2910         // Bidirectional ranges can't be propagated properly if they don't
2911         // also have random access.
2912 
2913         assert(equal(t, [1,2,3,4,5]));
2914 
2915         //Test that take doesn't wrap the result of take.
2916         assert(take(t, 4) == take(dummy, 4));
2917     }
2918 
2919     immutable myRepeat = repeat(1);
2920     static assert(is(Take!(typeof(myRepeat))));
2921 }
2922 
2923 pure @safe nothrow @nogc unittest
2924 {
2925     //check for correct slicing of Take on an infinite range
2926     import std.algorithm.comparison : equal;
2927     foreach (start; 0 .. 4)
2928         foreach (stop; start .. 4)
2929             assert(iota(4).cycle.take(4)[start .. stop]
2930                 .equal(iota(start, stop)));
2931 }
2932 
2933 pure @safe nothrow @nogc unittest
2934 {
2935     // Check that one can declare variables of all Take types,
2936     // and that they match the return type of the corresponding
2937     // take().
2938     // See https://issues.dlang.org/show_bug.cgi?id=4464
2939     int[] r1;
2940     Take!(int[]) t1;
2941     t1 = take(r1, 1);
2942     assert(t1.empty);
2943 
2944     string r2;
2945     Take!string t2;
2946     t2 = take(r2, 1);
2947     assert(t2.empty);
2948 
2949     Take!(Take!string) t3;
2950     t3 = take(t2, 1);
2951     assert(t3.empty);
2952 }
2953 
2954 pure @safe nothrow @nogc unittest
2955 {
2956     alias R1 = typeof(repeat(1));
2957     alias R2 = typeof(cycle([1]));
2958     alias TR1 = Take!R1;
2959     alias TR2 = Take!R2;
2960     static assert(isBidirectionalRange!TR1);
2961     static assert(isBidirectionalRange!TR2);
2962 }
2963 
2964 // https://issues.dlang.org/show_bug.cgi?id=12731
2965 pure @safe nothrow @nogc unittest
2966 {
2967     auto a = repeat(1);
2968     auto s = a[1 .. 5];
2969     s = s[1 .. 3];
2970     assert(s.length == 2);
2971     assert(s[0] == 1);
2972     assert(s[1] == 1);
2973 }
2974 
2975 // https://issues.dlang.org/show_bug.cgi?id=13151
2976 pure @safe nothrow @nogc unittest
2977 {
2978     import std.algorithm.comparison : equal;
2979 
2980     auto r = take(repeat(1, 4), 3);
2981     assert(r.take(2).equal(repeat(1, 2)));
2982 }
2983 
2984 
2985 /**
2986 Similar to $(LREF take), but assumes that `range` has at least $(D
2987 n) elements. Consequently, the result of $(D takeExactly(range, n))
2988 always defines the `length` property (and initializes it to `n`)
2989 even when `range` itself does not define `length`.
2990 
2991 The result of `takeExactly` is identical to that of $(LREF take) in
2992 cases where the original range defines `length` or is infinite.
2993 
2994 Unlike $(LREF take), however, it is illegal to pass a range with less than
2995 `n` elements to `takeExactly`; this will cause an assertion failure.
2996  */
2997 auto takeExactly(R)(R range, size_t n)
2998 if (isInputRange!R)
2999 {
3000     static if (is(typeof(takeExactly(range._input, n)) == R))
3001     {
3002         assert(n <= range._n,
3003                "Attempted to take more than the length of the range with takeExactly.");
3004         // takeExactly(takeExactly(r, n1), n2) has the same type as
3005         // takeExactly(r, n1) and simply returns takeExactly(r, n2)
3006         range._n = n;
3007         return range;
3008     }
3009     //Also covers hasSlicing!R for finite ranges.
3010     else static if (hasLength!R)
3011     {
3012         assert(n <= range.length,
3013                "Attempted to take more than the length of the range with takeExactly.");
3014         return take(range, n);
3015     }
3016     else static if (isInfinite!R)
3017         return Take!R(range, n);
3018     else
3019     {
3020         static struct Result
3021         {
3022             R _input;
3023             private size_t _n;
3024 
3025             @property bool empty() const { return !_n; }
3026             @property auto ref front()
3027             {
3028                 assert(_n > 0, "front() on an empty " ~ Result.stringof);
3029                 return _input.front;
3030             }
3031             void popFront() { _input.popFront(); --_n; }
3032             @property size_t length() const { return _n; }
3033             alias opDollar = length;
3034 
3035             @property auto _takeExactly_Result_asTake()
3036             {
3037                 return take(_input, _n);
3038             }
3039 
3040             alias _takeExactly_Result_asTake this;
3041 
3042             static if (isForwardRange!R)
3043                 @property auto save()
3044                 {
3045                     return Result(_input.save, _n);
3046                 }
3047 
3048             static if (hasMobileElements!R)
3049             {
3050                 auto moveFront()
3051                 {
3052                     assert(!empty,
3053                         "Attempting to move the front of an empty "
3054                         ~ typeof(this).stringof);
3055                     return _input.moveFront();
3056                 }
3057             }
3058 
3059             static if (hasAssignableElements!R)
3060             {
3061                 @property auto ref front(ElementType!R v)
3062                 {
3063                     import std.algorithm.mutation : move;
3064 
3065                     assert(!empty,
3066                         "Attempting to assign to the front of an empty "
3067                         ~ typeof(this).stringof);
3068                     return _input.front = move(v);
3069                 }
3070             }
3071         }
3072 
3073         return Result(range, n);
3074     }
3075 }
3076 
3077 ///
3078 pure @safe nothrow unittest
3079 {
3080     import std.algorithm.comparison : equal;
3081 
3082     auto a = [ 1, 2, 3, 4, 5 ];
3083 
3084     auto b = takeExactly(a, 3);
3085     assert(equal(b, [1, 2, 3]));
3086     static assert(is(typeof(b.length) == size_t));
3087     assert(b.length == 3);
3088     assert(b.front == 1);
3089     assert(b.back == 3);
3090 }
3091 
3092 pure @safe nothrow unittest
3093 {
3094     import std.algorithm.comparison : equal;
3095     import std.algorithm.iteration : filter;
3096 
3097     auto a = [ 1, 2, 3, 4, 5 ];
3098     auto b = takeExactly(a, 3);
3099     assert(equal(b, [1, 2, 3]));
3100     auto c = takeExactly(b, 2);
3101     assert(equal(c, [1, 2]));
3102 
3103 
3104 
3105     auto d = filter!"a > 2"(a);
3106     auto e = takeExactly(d, 3);
3107     assert(equal(e, [3, 4, 5]));
3108     static assert(is(typeof(e.length) == size_t));
3109     assert(e.length == 3);
3110     assert(e.front == 3);
3111 
3112     assert(equal(takeExactly(e, 3), [3, 4, 5]));
3113 }
3114 
3115 pure @safe nothrow unittest
3116 {
3117     import std.algorithm.comparison : equal;
3118     import std.internal.test.dummyrange : AllDummyRanges;
3119 
3120     auto a = [ 1, 2, 3, 4, 5 ];
3121     //Test that take and takeExactly are the same for ranges which define length
3122     //but aren't sliceable.
3123     struct L
3124     {
3125         @property auto front() { return _arr[0]; }
3126         @property bool empty() { return _arr.empty; }
3127         void popFront() { _arr.popFront(); }
3128         @property size_t length() { return _arr.length; }
3129         int[] _arr;
3130     }
3131     static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
3132     assert(take(L(a), 3) == takeExactly(L(a), 3));
3133 
3134     //Test that take and takeExactly are the same for ranges which are sliceable.
3135     static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
3136     assert(take(a, 3) == takeExactly(a, 3));
3137 
3138     //Test that take and takeExactly are the same for infinite ranges.
3139     auto inf = repeat(1);
3140     static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
3141     assert(take(inf, 5) == takeExactly(inf, 5));
3142 
3143     //Test that take and takeExactly are _not_ the same for ranges which don't
3144     //define length.
3145     static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
3146 
3147     foreach (DummyType; AllDummyRanges)
3148     {
3149         {
3150             DummyType dummy;
3151             auto t = takeExactly(dummy, 5);
3152 
3153             //Test that takeExactly doesn't wrap the result of takeExactly.
3154             assert(takeExactly(t, 4) == takeExactly(dummy, 4));
3155         }
3156 
3157         static if (hasMobileElements!DummyType)
3158         {
3159             {
3160                 auto t = takeExactly(DummyType.init, 4);
3161                 assert(t.moveFront() == 1);
3162                 assert(equal(t, [1, 2, 3, 4]));
3163             }
3164         }
3165 
3166         static if (hasAssignableElements!DummyType)
3167         {
3168             {
3169                 auto t = takeExactly(DummyType.init, 4);
3170                 t.front = 9;
3171                 assert(equal(t, [9, 2, 3, 4]));
3172             }
3173         }
3174     }
3175 }
3176 
3177 pure @safe nothrow unittest
3178 {
3179     import std.algorithm.comparison : equal;
3180     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
3181 
3182     alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
3183     auto te = takeExactly(DummyType(), 5);
3184     Take!DummyType t = te;
3185     assert(equal(t, [1, 2, 3, 4, 5]));
3186     assert(equal(t, te));
3187 }
3188 
3189 // https://issues.dlang.org/show_bug.cgi?id=18092
3190 // can't combine take and takeExactly
3191 @safe unittest
3192 {
3193     import std.algorithm.comparison : equal;
3194     import std.internal.test.dummyrange : AllDummyRanges;
3195 
3196     static foreach (Range; AllDummyRanges)
3197     {{
3198         Range r;
3199         assert(r.take(6).takeExactly(2).equal([1, 2]));
3200         assert(r.takeExactly(6).takeExactly(2).equal([1, 2]));
3201         assert(r.takeExactly(6).take(2).equal([1, 2]));
3202     }}
3203 }
3204 
3205 /**
3206 Returns a range with at most one element; for example, $(D
3207 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
3208 42). Calling `popFront()` off that range renders it empty.
3209 
3210 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in
3211 certain interfaces it is important to know statically that the range may only
3212 have at most one element.
3213 
3214 The type returned by `takeOne` is a random-access range with length
3215 regardless of `R`'s capabilities, as long as it is a forward range.
3216 (another feature that distinguishes `takeOne` from `take`). If
3217 (D R) is an input range but not a forward range, return type is an input
3218 range with all random-access capabilities except save.
3219  */
3220 auto takeOne(R)(R source)
3221 if (isInputRange!R)
3222 {
3223     static if (hasSlicing!R)
3224     {
3225         return source[0 .. !source.empty];
3226     }
3227     else
3228     {
3229         static struct Result
3230         {
3231             private R _source;
3232             private bool _empty = true;
3233             @property bool empty() const { return _empty; }
3234             @property auto ref front()
3235             {
3236                 assert(!empty, "Attempting to fetch the front of an empty takeOne");
3237                 return _source.front;
3238             }
3239             void popFront()
3240             {
3241                 assert(!empty, "Attempting to popFront an empty takeOne");
3242                 _source.popFront();
3243                 _empty = true;
3244             }
3245             void popBack()
3246             {
3247                 assert(!empty, "Attempting to popBack an empty takeOne");
3248                 _source.popFront();
3249                 _empty = true;
3250             }
3251             static if (isForwardRange!(Unqual!R))
3252             {
3253                 @property auto save() { return Result(_source.save, empty); }
3254             }
3255             @property auto ref back()
3256             {
3257                 assert(!empty, "Attempting to fetch the back of an empty takeOne");
3258                 return _source.front;
3259             }
3260             @property size_t length() const { return !empty; }
3261             alias opDollar = length;
3262             auto ref opIndex(size_t n)
3263             {
3264                 assert(n < length, "Attempting to index a takeOne out of bounds");
3265                 return _source.front;
3266             }
3267             auto opSlice(size_t m, size_t n)
3268             {
3269                 assert(
3270                     m <= n,
3271                     "Attempting to slice a takeOne range with a larger first argument than the second."
3272                 );
3273                 assert(
3274                     n <= length,
3275                     "Attempting to slice using an out of bounds index on a takeOne range."
3276                     );
3277                 return n > m ? this : Result(_source, true);
3278             }
3279             // Non-standard property
3280             @property R source() { return _source; }
3281         }
3282 
3283         return Result(source, source.empty);
3284     }
3285 }
3286 
3287 ///
3288 pure @safe nothrow unittest
3289 {
3290     auto s = takeOne([42, 43, 44]);
3291     static assert(isRandomAccessRange!(typeof(s)));
3292     assert(s.length == 1);
3293     assert(!s.empty);
3294     assert(s.front == 42);
3295     s.front = 43;
3296     assert(s.front == 43);
3297     assert(s.back == 43);
3298     assert(s[0] == 43);
3299     s.popFront();
3300     assert(s.length == 0);
3301     assert(s.empty);
3302 }
3303 
3304 pure @safe nothrow @nogc unittest
3305 {
3306     struct NonForwardRange
3307     {
3308         enum empty = false;
3309         int front() { return 42; }
3310         void popFront() {}
3311     }
3312 
3313     static assert(!isForwardRange!NonForwardRange);
3314 
3315     auto s = takeOne(NonForwardRange());
3316     assert(s.length == 1);
3317     assert(!s.empty);
3318     assert(s.front == 42);
3319     assert(s.back == 42);
3320     assert(s[0] == 42);
3321 
3322     auto t = s[0 .. 0];
3323     assert(t.empty);
3324     assert(t.length == 0);
3325 
3326     auto u = s[1 .. 1];
3327     assert(u.empty);
3328     assert(u.length == 0);
3329 
3330     auto v = s[0 .. 1];
3331     s.popFront();
3332     assert(s.length == 0);
3333     assert(s.empty);
3334     assert(!v.empty);
3335     assert(v.front == 42);
3336     v.popBack();
3337     assert(v.empty);
3338     assert(v.length == 0);
3339 }
3340 
3341 pure @safe nothrow @nogc unittest
3342 {
3343     struct NonSlicingForwardRange
3344     {
3345         enum empty = false;
3346         int front() { return 42; }
3347         void popFront() {}
3348         @property auto save() { return this; }
3349     }
3350 
3351     static assert(isForwardRange!NonSlicingForwardRange);
3352     static assert(!hasSlicing!NonSlicingForwardRange);
3353 
3354     auto s = takeOne(NonSlicingForwardRange());
3355     assert(s.length == 1);
3356     assert(!s.empty);
3357     assert(s.front == 42);
3358     assert(s.back == 42);
3359     assert(s[0] == 42);
3360     auto t = s.save;
3361     s.popFront();
3362     assert(s.length == 0);
3363     assert(s.empty);
3364     assert(!t.empty);
3365     assert(t.front == 42);
3366     t.popBack();
3367     assert(t.empty);
3368     assert(t.length == 0);
3369 }
3370 
3371 // Test that asserts trigger correctly
3372 @system unittest
3373 {
3374     import std.exception : assertThrown;
3375     import core.exception : AssertError;
3376 
3377     struct NonForwardRange
3378     {
3379         enum empty = false;
3380         int front() { return 42; }
3381         void popFront() {}
3382     }
3383 
3384     auto s = takeOne(NonForwardRange());
3385 
3386     assertThrown!AssertError(s[1]);
3387     assertThrown!AssertError(s[0 .. 2]);
3388 
3389     size_t one = 1;     // Avoid style warnings triggered by literals
3390     size_t zero = 0;
3391     assertThrown!AssertError(s[one .. zero]);
3392 
3393     s.popFront;
3394     assert(s.empty);
3395     assertThrown!AssertError(s.front);
3396     assertThrown!AssertError(s.back);
3397     assertThrown!AssertError(s.popFront);
3398     assertThrown!AssertError(s.popBack);
3399 }
3400 
3401 // https://issues.dlang.org/show_bug.cgi?id=16999
3402 pure @safe unittest
3403 {
3404     auto myIota = new class
3405     {
3406         int front = 0;
3407         @safe void popFront(){front++;}
3408         enum empty = false;
3409     };
3410     auto iotaPart = myIota.takeOne;
3411     int sum;
3412     foreach (var; chain(iotaPart, iotaPart, iotaPart))
3413     {
3414         sum += var;
3415     }
3416     assert(sum == 3);
3417     assert(iotaPart.front == 3);
3418 }
3419 
3420 /++
3421     Returns an empty range which is statically known to be empty and is
3422     guaranteed to have `length` and be random access regardless of `R`'s
3423     capabilities.
3424   +/
3425 auto takeNone(R)()
3426 if (isInputRange!R)
3427 {
3428     return typeof(takeOne(R.init)).init;
3429 }
3430 
3431 ///
3432 pure @safe nothrow @nogc unittest
3433 {
3434     auto range = takeNone!(int[])();
3435     assert(range.length == 0);
3436     assert(range.empty);
3437 }
3438 
3439 pure @safe nothrow @nogc unittest
3440 {
3441     enum ctfe = takeNone!(int[])();
3442     static assert(ctfe.length == 0);
3443     static assert(ctfe.empty);
3444 }
3445 
3446 
3447 /++
3448     Creates an empty range from the given range in $(BIGOH 1). If it can, it
3449     will return the same range type. If not, it will return
3450     $(D takeExactly(range, 0)).
3451   +/
3452 auto takeNone(R)(R range)
3453 if (isInputRange!R)
3454 {
3455     import std.traits : isDynamicArray;
3456     //Makes it so that calls to takeNone which don't use UFCS still work with a
3457     //member version if it's defined.
3458     static if (is(typeof(R.takeNone)))
3459         auto retval = range.takeNone();
3460     // https://issues.dlang.org/show_bug.cgi?id=8339
3461     else static if (isDynamicArray!R)/+ ||
3462                    (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
3463     {
3464         auto retval = R.init;
3465     }
3466     //An infinite range sliced at [0 .. 0] would likely still not be empty...
3467     else static if (hasSlicing!R && !isInfinite!R)
3468         auto retval = range[0 .. 0];
3469     else
3470         auto retval = takeExactly(range, 0);
3471 
3472     // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being
3473     // done in an out block.
3474     assert(retval.empty);
3475     return retval;
3476 }
3477 
3478 ///
3479 pure @safe nothrow unittest
3480 {
3481     import std.algorithm.iteration : filter;
3482     assert(takeNone([42, 27, 19]).empty);
3483     assert(takeNone("dlang.org").empty);
3484     assert(takeNone(filter!"true"([42, 27, 19])).empty);
3485 }
3486 
3487 @safe unittest
3488 {
3489     import std.algorithm.iteration : filter;
3490     import std.meta : AliasSeq;
3491 
3492     struct Dummy
3493     {
3494         mixin template genInput()
3495         {
3496         @safe:
3497             @property bool empty() { return _arr.empty; }
3498             @property auto front() { return _arr.front; }
3499             void popFront() { _arr.popFront(); }
3500             static assert(isInputRange!(typeof(this)));
3501         }
3502     }
3503     alias genInput = Dummy.genInput;
3504 
3505     static struct NormalStruct
3506     {
3507         //Disabled to make sure that the takeExactly version is used.
3508         @disable this();
3509         this(int[] arr) { _arr = arr; }
3510         mixin genInput;
3511         int[] _arr;
3512     }
3513 
3514     static struct SliceStruct
3515     {
3516         @disable this();
3517         this(int[] arr) { _arr = arr; }
3518         mixin genInput;
3519         @property auto save() { return this; }
3520         auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
3521         @property size_t length() { return _arr.length; }
3522         int[] _arr;
3523     }
3524 
3525     static struct InitStruct
3526     {
3527         mixin genInput;
3528         int[] _arr;
3529     }
3530 
3531     static struct TakeNoneStruct
3532     {
3533         this(int[] arr) { _arr = arr; }
3534         @disable this();
3535         mixin genInput;
3536         auto takeNone() { return typeof(this)(null); }
3537         int[] _arr;
3538     }
3539 
3540     static class NormalClass
3541     {
3542         this(int[] arr) {_arr = arr;}
3543         mixin genInput;
3544         int[] _arr;
3545     }
3546 
3547     static class SliceClass
3548     {
3549     @safe:
3550         this(int[] arr) { _arr = arr; }
3551         mixin genInput;
3552         @property auto save() { return new typeof(this)(_arr); }
3553         auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
3554         @property size_t length() { return _arr.length; }
3555         int[] _arr;
3556     }
3557 
3558     static class TakeNoneClass
3559     {
3560     @safe:
3561         this(int[] arr) { _arr = arr; }
3562         mixin genInput;
3563         auto takeNone() { return new typeof(this)(null); }
3564         int[] _arr;
3565     }
3566 
3567     import std.format : format;
3568 
3569     static foreach (range; AliasSeq!([1, 2, 3, 4, 5],
3570                              "hello world",
3571                              "hello world"w,
3572                              "hello world"d,
3573                              SliceStruct([1, 2, 3]),
3574                              // https://issues.dlang.org/show_bug.cgi?id=8339
3575                              // forces this to be takeExactly `InitStruct([1, 2, 3]),
3576                              TakeNoneStruct([1, 2, 3])))
3577     {
3578         static assert(takeNone(range).empty, typeof(range).stringof);
3579         assert(takeNone(range).empty);
3580         static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
3581     }
3582 
3583     static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
3584                              InitStruct([1, 2, 3])))
3585     {
3586         static assert(takeNone(range).empty, typeof(range).stringof);
3587         assert(takeNone(range).empty);
3588         static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
3589     }
3590 
3591     //Don't work in CTFE.
3592     auto normal = new NormalClass([1, 2, 3]);
3593     assert(takeNone(normal).empty);
3594     static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
3595 
3596     auto slice = new SliceClass([1, 2, 3]);
3597     assert(takeNone(slice).empty);
3598     static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
3599 
3600     auto taken = new TakeNoneClass([1, 2, 3]);
3601     assert(takeNone(taken).empty);
3602     static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
3603 
3604     auto filtered = filter!"true"([1, 2, 3, 4, 5]);
3605     assert(takeNone(filtered).empty);
3606     // https://issues.dlang.org/show_bug.cgi?id=8339 and
3607     // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly
3608     //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
3609 }
3610 
3611 /++
3612  + Return a range advanced to within `_n` elements of the end of
3613  + `range`.
3614  +
3615  + Intended as the range equivalent of the Unix
3616  + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
3617  + of `range` is less than or equal to `_n`, `range` is returned
3618  + as-is.
3619  +
3620  + Completes in $(BIGOH 1) steps for ranges that support slicing and have
3621  + length. Completes in $(BIGOH range.length) time for all other ranges.
3622  +
3623  + Params:
3624  +    range = range to get _tail of
3625  +    n = maximum number of elements to include in _tail
3626  +
3627  + Returns:
3628  +    Returns the _tail of `range` augmented with length information
3629  +/
3630 auto tail(Range)(Range range, size_t n)
3631 if (isInputRange!Range && !isInfinite!Range &&
3632     (hasLength!Range || isForwardRange!Range))
3633 {
3634     static if (hasLength!Range)
3635     {
3636         immutable length = range.length;
3637         if (n >= length)
3638             return range.takeExactly(length);
3639         else
3640             return range.drop(length - n).takeExactly(n);
3641     }
3642     else
3643     {
3644         Range scout = range.save;
3645         foreach (immutable i; 0 .. n)
3646         {
3647             if (scout.empty)
3648                 return range.takeExactly(i);
3649             scout.popFront();
3650         }
3651 
3652         auto tail = range.save;
3653         while (!scout.empty)
3654         {
3655             assert(!tail.empty);
3656             scout.popFront();
3657             tail.popFront();
3658         }
3659 
3660         return tail.takeExactly(n);
3661     }
3662 }
3663 
3664 ///
3665 pure @safe nothrow unittest
3666 {
3667     // tail -c n
3668     assert([1, 2, 3].tail(1) == [3]);
3669     assert([1, 2, 3].tail(2) == [2, 3]);
3670     assert([1, 2, 3].tail(3) == [1, 2, 3]);
3671     assert([1, 2, 3].tail(4) == [1, 2, 3]);
3672     assert([1, 2, 3].tail(0).length == 0);
3673 
3674     // tail --lines=n
3675     import std.algorithm.comparison : equal;
3676     import std.algorithm.iteration : joiner;
3677     import std.exception : assumeWontThrow;
3678     import std.string : lineSplitter;
3679     assert("one\ntwo\nthree"
3680         .lineSplitter
3681         .tail(2)
3682         .joiner("\n")
3683         .equal("two\nthree")
3684         .assumeWontThrow);
3685 }
3686 
3687 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408
3688 pure nothrow @safe /+@nogc+/ unittest
3689 {
3690     import std.algorithm.comparison : equal;
3691     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
3692         RangeType, ReturnBy;
3693 
3694     static immutable cheatsheet = [6, 7, 8, 9, 10];
3695 
3696     foreach (R; AllDummyRanges)
3697     {
3698         static if (isInputRange!R && !isInfinite!R &&
3699                    (hasLength!R || isForwardRange!R))
3700         {
3701             assert(R.init.tail(5).equal(cheatsheet));
3702             static assert(R.init.tail(5).equal(cheatsheet));
3703 
3704             assert(R.init.tail(0).length == 0);
3705             assert(R.init.tail(10).equal(R.init));
3706             assert(R.init.tail(11).equal(R.init));
3707         }
3708     }
3709 
3710     // Infinite ranges are not supported
3711     static assert(!__traits(compiles, repeat(0).tail(0)));
3712 
3713     // Neither are non-forward ranges without length
3714     static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
3715         RangeType.Input).init.tail(5)));
3716 }
3717 
3718 pure @safe nothrow @nogc unittest
3719 {
3720     static immutable input = [1, 2, 3];
3721     static immutable expectedOutput = [2, 3];
3722     assert(input.tail(2) == expectedOutput);
3723 }
3724 
3725 /++
3726     Convenience function which calls
3727     $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`.
3728     `drop` makes it easier to pop elements from a range
3729     and then pass it to another function within a single expression,
3730     whereas `popFrontN` would require multiple statements.
3731 
3732     `dropBack` provides the same functionality but instead calls
3733     $(REF popBackN, std, range, primitives)`(range, n)`
3734 
3735     Note: `drop` and `dropBack` will only pop $(I up to)
3736     `n` elements but will stop if the range is empty first.
3737     In other languages this is sometimes called `skip`.
3738 
3739     Params:
3740         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3741         n = the number of elements to drop
3742 
3743     Returns:
3744         `range` with up to `n` elements dropped
3745 
3746     See_Also:
3747         $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives)
3748   +/
3749 R drop(R)(R range, size_t n)
3750 if (isInputRange!R)
3751 {
3752     range.popFrontN(n);
3753     return range;
3754 }
3755 
3756 ///
3757 @safe unittest
3758 {
3759     import std.algorithm.comparison : equal;
3760 
3761     assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
3762     assert("hello world".drop(6) == "world");
3763     assert("hello world".drop(50).empty);
3764     assert("hello world".take(6).drop(3).equal("lo "));
3765 }
3766 
3767 /// ditto
3768 R dropBack(R)(R range, size_t n)
3769 if (isBidirectionalRange!R)
3770 {
3771     range.popBackN(n);
3772     return range;
3773 }
3774 
3775 ///
3776 @safe unittest
3777 {
3778     import std.algorithm.comparison : equal;
3779 
3780     assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
3781     assert("hello world".dropBack(6) == "hello");
3782     assert("hello world".dropBack(50).empty);
3783     assert("hello world".drop(4).dropBack(4).equal("o w"));
3784 }
3785 
3786 @safe unittest
3787 {
3788     import std.algorithm.comparison : equal;
3789     import std.container.dlist : DList;
3790 
3791     //Remove all but the first two elements
3792     auto a = DList!int(0, 1, 9, 9, 9, 9);
3793     a.remove(a[].drop(2));
3794     assert(a[].equal(a[].take(2)));
3795 }
3796 
3797 @safe unittest
3798 {
3799     import std.algorithm.comparison : equal;
3800     import std.algorithm.iteration : filter;
3801 
3802     assert(drop("", 5).empty);
3803     assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3804 }
3805 
3806 @safe unittest
3807 {
3808     import std.algorithm.comparison : equal;
3809     import std.container.dlist : DList;
3810 
3811     //insert before the last two elements
3812     auto a = DList!int(0, 1, 2, 5, 6);
3813     a.insertAfter(a[].dropBack(2), [3, 4]);
3814     assert(a[].equal(iota(0, 7)));
3815 }
3816 
3817 /++
3818     Similar to $(LREF drop) and `dropBack` but they call
3819     $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)`
3820     instead.
3821 
3822     Note: Unlike `drop`, `dropExactly` will assume that the
3823     range holds at least `n` elements. This makes `dropExactly`
3824     faster than `drop`, but it also means that if `range` does
3825     not contain at least `n` elements, it will attempt to call `popFront`
3826     on an empty range, which is undefined behavior. So, only use
3827     `popFrontExactly` when it is guaranteed that `range` holds at least
3828     `n` elements.
3829 
3830     Params:
3831         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3832         n = the number of elements to drop
3833 
3834     Returns:
3835         `range` with `n` elements dropped
3836 
3837     See_Also:
3838         $(REF popFrontExcatly, std, range, primitives),
3839         $(REF popBackExcatly, std, range, primitives)
3840 +/
3841 R dropExactly(R)(R range, size_t n)
3842 if (isInputRange!R)
3843 {
3844     popFrontExactly(range, n);
3845     return range;
3846 }
3847 /// ditto
3848 R dropBackExactly(R)(R range, size_t n)
3849 if (isBidirectionalRange!R)
3850 {
3851     popBackExactly(range, n);
3852     return range;
3853 }
3854 
3855 ///
3856 @safe unittest
3857 {
3858     import std.algorithm.comparison : equal;
3859     import std.algorithm.iteration : filterBidirectional;
3860 
3861     auto a = [1, 2, 3];
3862     assert(a.dropExactly(2) == [3]);
3863     assert(a.dropBackExactly(2) == [1]);
3864 
3865     string s = "日本語";
3866     assert(s.dropExactly(2) == "語");
3867     assert(s.dropBackExactly(2) == "日");
3868 
3869     auto bd = filterBidirectional!"true"([1, 2, 3]);
3870     assert(bd.dropExactly(2).equal([3]));
3871     assert(bd.dropBackExactly(2).equal([1]));
3872 }
3873 
3874 /++
3875     Convenience function which calls
3876     `range.popFront()` and returns `range`. `dropOne`
3877     makes it easier to pop an element from a range
3878     and then pass it to another function within a single expression,
3879     whereas `popFront` would require multiple statements.
3880 
3881     `dropBackOne` provides the same functionality but instead calls
3882     `range.popBack()`.
3883 +/
3884 R dropOne(R)(R range)
3885 if (isInputRange!R)
3886 {
3887     range.popFront();
3888     return range;
3889 }
3890 /// ditto
3891 R dropBackOne(R)(R range)
3892 if (isBidirectionalRange!R)
3893 {
3894     range.popBack();
3895     return range;
3896 }
3897 
3898 ///
3899 pure @safe nothrow unittest
3900 {
3901     import std.algorithm.comparison : equal;
3902     import std.algorithm.iteration : filterBidirectional;
3903     import std.container.dlist : DList;
3904 
3905     auto dl = DList!int(9, 1, 2, 3, 9);
3906     assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
3907 
3908     auto a = [1, 2, 3];
3909     assert(a.dropOne() == [2, 3]);
3910     assert(a.dropBackOne() == [1, 2]);
3911 
3912     string s = "日本語";
3913     import std.exception : assumeWontThrow;
3914     assert(assumeWontThrow(s.dropOne() == "本語"));
3915     assert(assumeWontThrow(s.dropBackOne() == "日本"));
3916 
3917     auto bd = filterBidirectional!"true"([1, 2, 3]);
3918     assert(bd.dropOne().equal([2, 3]));
3919     assert(bd.dropBackOne().equal([1, 2]));
3920 }
3921 
3922 /**
3923 Create a range which repeats one value.
3924 
3925 Params:
3926     value = the _value to repeat
3927     n = the number of times to repeat `value`
3928 
3929 Returns:
3930     If `n` is not defined, an infinite random access range
3931     with slicing.
3932 
3933     If `n` is defined, a random access range with slicing.
3934 */
3935 struct Repeat(T)
3936 {
3937 private:
3938     import std.typecons : Rebindable2;
3939 
3940     // Store a rebindable T to make Repeat assignable.
3941     Rebindable2!T _value;
3942 
3943 public:
3944     /// Range primitives
3945     @property inout(T) front() inout { return _value.get; }
3946 
3947     /// ditto
3948     @property inout(T) back() inout { return _value.get; }
3949 
3950     /// ditto
3951     enum bool empty = false;
3952 
3953     /// ditto
3954     void popFront() {}
3955 
3956     /// ditto
3957     void popBack() {}
3958 
3959     /// ditto
3960     @property auto save() inout { return this; }
3961 
3962     /// ditto
3963     inout(T) opIndex(size_t) inout { return _value.get; }
3964 
3965     /// ditto
3966     auto opSlice(size_t i, size_t j)
3967     in
3968     {
3969         assert(
3970             i <= j,
3971             "Attempting to slice a Repeat with a larger first argument than the second."
3972         );
3973     }
3974     do
3975     {
3976         return this.takeExactly(j - i);
3977     }
3978     private static struct DollarToken {}
3979 
3980     /// ditto
3981     enum opDollar = DollarToken.init;
3982 
3983     /// ditto
3984     auto opSlice(size_t, DollarToken) inout { return this; }
3985 }
3986 
3987 /// Ditto
3988 Repeat!T repeat(T)(T value)
3989 {
3990     import std.typecons : Rebindable2;
3991 
3992     return Repeat!T(Rebindable2!T(value));
3993 }
3994 
3995 ///
3996 pure @safe nothrow unittest
3997 {
3998     import std.algorithm.comparison : equal;
3999 
4000     assert(5.repeat().take(4).equal([5, 5, 5, 5]));
4001 }
4002 
4003 pure @safe nothrow unittest
4004 {
4005     import std.algorithm.comparison : equal;
4006 
4007     auto  r = repeat(5);
4008     alias R = typeof(r);
4009     static assert(isBidirectionalRange!R);
4010     static assert(isForwardRange!R);
4011     static assert(isInfinite!R);
4012     static assert(hasSlicing!R);
4013 
4014     assert(r.back == 5);
4015     assert(r.front == 5);
4016     assert(r.take(4).equal([ 5, 5, 5, 5 ]));
4017     assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
4018 
4019     R r2 = r[5 .. $];
4020     assert(r2.back == 5);
4021     assert(r2.front == 5);
4022 }
4023 
4024 /// ditto
4025 Take!(Repeat!T) repeat(T)(T value, size_t n)
4026 {
4027     return take(repeat(value), n);
4028 }
4029 
4030 ///
4031 pure @safe nothrow unittest
4032 {
4033     import std.algorithm.comparison : equal;
4034 
4035     assert(5.repeat(4).equal([5, 5, 5, 5]));
4036 }
4037 
4038 // https://issues.dlang.org/show_bug.cgi?id=12007
4039 pure @safe nothrow unittest
4040 {
4041     static class C{}
4042     Repeat!(immutable int) ri;
4043     ri = ri.save;
4044     Repeat!(immutable C) rc;
4045     rc = rc.save;
4046 
4047     import std.algorithm.setops : cartesianProduct;
4048     import std.algorithm.comparison : equal;
4049     import std.typecons : tuple;
4050     immutable int[] A = [1,2,3];
4051     immutable int[] B = [4,5,6];
4052 
4053     assert(equal(cartesianProduct(A,B),
4054         [
4055             tuple(1, 4), tuple(1, 5), tuple(1, 6),
4056             tuple(2, 4), tuple(2, 5), tuple(2, 6),
4057             tuple(3, 4), tuple(3, 5), tuple(3, 6),
4058         ]));
4059 }
4060 
4061 /**
4062 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
4063 whose front is defined by successive calls to `fun()`.
4064 This is especially useful to call function with global side effects (random
4065 functions), or to create ranges expressed as a single delegate, rather than
4066 an entire `front`/`popFront`/`empty` structure.
4067 `fun` maybe be passed either a template alias parameter (existing
4068 function, delegate, struct type defining `static opCall`) or
4069 a run-time value argument (delegate, function object).
4070 The result range models an InputRange
4071 ($(REF isInputRange, std,range,primitives)).
4072 The resulting range will call `fun()` on construction, and every call to
4073 `popFront`, and the cached value will be returned when `front` is called.
4074 
4075 Returns: an `inputRange` where each element represents another call to fun.
4076 */
4077 auto generate(Fun)(Fun fun)
4078 if (isCallable!fun)
4079 {
4080     auto gen = Generator!(Fun)(fun);
4081     gen.popFront(); // prime the first element
4082     return gen;
4083 }
4084 
4085 /// ditto
4086 auto generate(alias fun)()
4087 if (isCallable!fun)
4088 {
4089     auto gen = Generator!(fun)();
4090     gen.popFront(); // prime the first element
4091     return gen;
4092 }
4093 
4094 ///
4095 @safe pure nothrow unittest
4096 {
4097     import std.algorithm.comparison : equal;
4098     import std.algorithm.iteration : map;
4099 
4100     int i = 1;
4101     auto powersOfTwo = generate!(() => i *= 2)().take(10);
4102     assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
4103 }
4104 
4105 ///
4106 @safe pure nothrow unittest
4107 {
4108     import std.algorithm.comparison : equal;
4109 
4110     //Returns a run-time delegate
4111     auto infiniteIota(T)(T low, T high)
4112     {
4113         T i = high;
4114         return (){if (i == high) i = low; return i++;};
4115     }
4116     //adapted as a range.
4117     assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
4118 }
4119 
4120 ///
4121 @safe unittest
4122 {
4123     import std.format : format;
4124     import std.random : uniform;
4125 
4126     auto r = generate!(() => uniform(0, 6)).take(10);
4127     format("%(%s %)", r);
4128 }
4129 
4130 private struct Generator(Fun...)
4131 {
4132     static assert(Fun.length == 1);
4133     static assert(isInputRange!Generator);
4134     import std.traits : FunctionAttribute, functionAttributes, ReturnType;
4135 
4136 private:
4137     static if (is(Fun[0]))
4138         Fun[0] fun;
4139     else
4140         alias fun = Fun[0];
4141 
4142     enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
4143 
4144     import std.traits : hasIndirections;
4145     static if (!hasIndirections!(ReturnType!fun))
4146         alias RetType = Unqual!(ReturnType!fun);
4147     else
4148         alias RetType = ReturnType!fun;
4149 
4150     static if (returnByRef_)
4151         RetType *elem_;
4152     else
4153         RetType elem_;
4154 public:
4155     /// Range primitives
4156     enum empty = false;
4157 
4158     static if (returnByRef_)
4159     {
4160         /// ditto
4161         ref front() @property
4162         {
4163             return *elem_;
4164         }
4165         /// ditto
4166         void popFront()
4167         {
4168             elem_ = &fun();
4169         }
4170     }
4171     else
4172     {
4173         /// ditto
4174         auto front() @property
4175         {
4176             return elem_;
4177         }
4178         /// ditto
4179         void popFront()
4180         {
4181             elem_ = fun();
4182         }
4183     }
4184 }
4185 
4186 @safe nothrow unittest
4187 {
4188     import std.algorithm.comparison : equal;
4189 
4190     struct StaticOpCall
4191     {
4192         static ubyte opCall() { return 5 ; }
4193     }
4194 
4195     assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
4196 }
4197 
4198 @safe pure unittest
4199 {
4200     import std.algorithm.comparison : equal;
4201 
4202     struct OpCall
4203     {
4204         ubyte opCall() @safe pure { return 5 ; }
4205     }
4206 
4207     OpCall op;
4208     assert(equal(generate(op).take(10), repeat(5).take(10)));
4209 }
4210 
4211 // verify ref mechanism works
4212 @system nothrow unittest
4213 {
4214     int[10] arr;
4215     int idx;
4216 
4217     ref int fun() {
4218         auto x = idx++;
4219         idx %= arr.length;
4220         return arr[x];
4221     }
4222     int y = 1;
4223     foreach (ref x; generate!(fun).take(20))
4224     {
4225         x += y++;
4226     }
4227     import std.algorithm.comparison : equal;
4228     assert(equal(arr[], iota(12, 32, 2)));
4229 }
4230 
4231 // assure front isn't the mechanism to make generate go to the next element.
4232 @safe unittest
4233 {
4234     int i;
4235     auto g = generate!(() => ++i);
4236     auto f = g.front;
4237     assert(f == g.front);
4238     g = g.drop(5); // reassign because generate caches
4239     assert(g.front == f + 5);
4240 }
4241 
4242 // https://issues.dlang.org/show_bug.cgi?id=23319
4243 @safe pure nothrow unittest
4244 {
4245     auto b = generate!(() => const(int)(42));
4246     assert(b.front == 42);
4247 }
4248 
4249 /**
4250 Repeats the given forward range ad infinitum. If the original range is
4251 infinite (fact that would make `Cycle` the identity application),
4252 `Cycle` detects that and aliases itself to the range type
4253 itself. That works for non-forward ranges too.
4254 If the original range has random access, `Cycle` offers
4255 random access and also offers a constructor taking an initial position
4256 `index`. `Cycle` works with static arrays in addition to ranges,
4257 mostly for performance reasons.
4258 
4259 Note: The input range must not be empty.
4260 
4261 Tip: This is a great way to implement simple circular buffers.
4262 */
4263 struct Cycle(R)
4264 if (isForwardRange!R && !isInfinite!R)
4265 {
4266     static if (isRandomAccessRange!R && hasLength!R)
4267     {
4268         private R _original;
4269         private size_t _index;
4270 
4271         /// Range primitives
4272         this(R input, size_t index = 0)
4273         {
4274             _original = input;
4275             _index = index % _original.length;
4276         }
4277 
4278         /// ditto
4279         @property auto ref front()
4280         {
4281             return _original[_index];
4282         }
4283 
4284         static if (is(typeof((cast(const R)_original)[_index])))
4285         {
4286             /// ditto
4287             @property auto ref front() const
4288             {
4289                 return _original[_index];
4290             }
4291         }
4292 
4293         static if (hasAssignableElements!R)
4294         {
4295             /// ditto
4296             @property void front(ElementType!R val)
4297             {
4298                 import std.algorithm.mutation : move;
4299 
4300                 _original[_index] = move(val);
4301             }
4302         }
4303 
4304         /// ditto
4305         enum bool empty = false;
4306 
4307         /// ditto
4308         void popFront()
4309         {
4310             ++_index;
4311             if (_index >= _original.length)
4312                 _index = 0;
4313         }
4314 
4315         /// ditto
4316         auto ref opIndex(size_t n)
4317         {
4318             return _original[(n + _index) % _original.length];
4319         }
4320 
4321         static if (is(typeof((cast(const R)_original)[_index])) &&
4322                    is(typeof((cast(const R)_original).length)))
4323         {
4324             /// ditto
4325             auto ref opIndex(size_t n) const
4326             {
4327                 return _original[(n + _index) % _original.length];
4328             }
4329         }
4330 
4331         static if (hasAssignableElements!R)
4332         {
4333             /// ditto
4334             void opIndexAssign(ElementType!R val, size_t n)
4335             {
4336                 _original[(n + _index) % _original.length] = val;
4337             }
4338         }
4339 
4340         /// ditto
4341         @property Cycle save()
4342         {
4343             //No need to call _original.save, because Cycle never actually modifies _original
4344             return Cycle(_original, _index);
4345         }
4346 
4347         private static struct DollarToken {}
4348 
4349         /// ditto
4350         enum opDollar = DollarToken.init;
4351 
4352         static if (hasSlicing!R)
4353         {
4354             /// ditto
4355             auto opSlice(size_t i, size_t j)
4356             in
4357             {
4358                 assert(i <= j);
4359             }
4360             do
4361             {
4362                 return this[i .. $].takeExactly(j - i);
4363             }
4364 
4365             /// ditto
4366             auto opSlice(size_t i, DollarToken)
4367             {
4368                 return typeof(this)(_original, _index + i);
4369             }
4370         }
4371     }
4372     else
4373     {
4374         private R _original;
4375         private R _current;
4376 
4377         /// ditto
4378         this(R input)
4379         {
4380             _original = input;
4381             _current = input.save;
4382         }
4383 
4384         private this(R original, R current)
4385         {
4386             _original = original;
4387             _current = current;
4388         }
4389 
4390         /// ditto
4391         @property auto ref front()
4392         {
4393             return _current.front;
4394         }
4395 
4396         static if (is(typeof((cast(const R)_current).front)))
4397         {
4398             /// ditto
4399             @property auto ref front() const
4400             {
4401                 return _current.front;
4402             }
4403         }
4404 
4405         static if (hasAssignableElements!R)
4406         {
4407             /// ditto
4408             @property auto front(ElementType!R val)
4409             {
4410                 import std.algorithm.mutation : move;
4411 
4412                 return _current.front = move(val);
4413             }
4414         }
4415 
4416         /// ditto
4417         enum bool empty = false;
4418 
4419         /// ditto
4420         void popFront()
4421         {
4422             _current.popFront();
4423             if (_current.empty)
4424                 _current = _original.save;
4425         }
4426 
4427         /// ditto
4428         @property Cycle save()
4429         {
4430             //No need to call _original.save, because Cycle never actually modifies _original
4431             return Cycle(_original, _current.save);
4432         }
4433     }
4434 }
4435 
4436 /// ditto
4437 template Cycle(R)
4438 if (isInfinite!R)
4439 {
4440     alias Cycle = R;
4441 }
4442 
4443 /// ditto
4444 struct Cycle(R)
4445 if (isStaticArray!R)
4446 {
4447     private alias ElementType = typeof(R.init[0]);
4448     private ElementType* _ptr;
4449     private size_t _index;
4450 
4451 nothrow:
4452 
4453     /// Range primitives
4454     this(ref R input, size_t index = 0) @system
4455     {
4456         _ptr = input.ptr;
4457         _index = index % R.length;
4458     }
4459 
4460     /// ditto
4461     @property ref inout(ElementType) front() inout @safe
4462     {
4463         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4464         {
4465             return p[idx];
4466         }
4467         return trustedPtrIdx(_ptr, _index);
4468     }
4469 
4470     /// ditto
4471     enum bool empty = false;
4472 
4473     /// ditto
4474     void popFront() @safe
4475     {
4476         ++_index;
4477         if (_index >= R.length)
4478             _index = 0;
4479     }
4480 
4481     /// ditto
4482     ref inout(ElementType) opIndex(size_t n) inout @safe
4483     {
4484         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4485         {
4486             return p[idx % R.length];
4487         }
4488         return trustedPtrIdx(_ptr, n + _index);
4489     }
4490 
4491     /// ditto
4492     @property inout(Cycle) save() inout @safe
4493     {
4494         return this;
4495     }
4496 
4497     private static struct DollarToken {}
4498     /// ditto
4499     enum opDollar = DollarToken.init;
4500 
4501     /// ditto
4502     auto opSlice(size_t i, size_t j) @safe
4503     in
4504     {
4505         assert(
4506             i <= j,
4507             "Attempting to slice a Repeat with a larger first argument than the second."
4508         );
4509     }
4510     do
4511     {
4512         return this[i .. $].takeExactly(j - i);
4513     }
4514 
4515     /// ditto
4516     inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
4517     {
4518         static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
4519         {
4520             return cast(inout) Cycle(*cast(R*)(p), idx);
4521         }
4522         return trustedCtor(_ptr, _index + i);
4523     }
4524 }
4525 
4526 /// Ditto
4527 auto cycle(R)(R input)
4528 if (isInputRange!R)
4529 {
4530     static assert(isForwardRange!R || isInfinite!R,
4531         "Cycle requires a forward range argument unless it's statically known"
4532          ~ " to be infinite");
4533     assert(!input.empty, "Attempting to pass an empty input to cycle");
4534     static if (isInfinite!R) return input;
4535     else return Cycle!R(input);
4536 }
4537 
4538 ///
4539 @safe unittest
4540 {
4541     import std.algorithm.comparison : equal;
4542     import std.range : cycle, take;
4543 
4544     // Here we create an infinitive cyclic sequence from [1, 2]
4545     // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
4546     // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
4547     // and compare them with the expected values for equality.
4548     assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
4549 }
4550 
4551 /// Ditto
4552 Cycle!R cycle(R)(R input, size_t index = 0)
4553 if (isRandomAccessRange!R && !isInfinite!R)
4554 {
4555     assert(!input.empty, "Attempting to pass an empty input to cycle");
4556     return Cycle!R(input, index);
4557 }
4558 
4559 /// Ditto
4560 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
4561 if (isStaticArray!R)
4562 {
4563     return Cycle!R(input, index);
4564 }
4565 
4566 @safe nothrow unittest
4567 {
4568     import std.algorithm.comparison : equal;
4569     import std.internal.test.dummyrange : AllDummyRanges;
4570 
4571     static assert(isForwardRange!(Cycle!(uint[])));
4572 
4573     // Make sure ref is getting propagated properly.
4574     int[] nums = [1,2,3];
4575     auto c2 = cycle(nums);
4576     c2[3]++;
4577     assert(nums[0] == 2);
4578 
4579     immutable int[] immarr = [1, 2, 3];
4580 
4581     foreach (DummyType; AllDummyRanges)
4582     {
4583         static if (isForwardRange!DummyType)
4584         {
4585             DummyType dummy;
4586             auto cy = cycle(dummy);
4587             static assert(isForwardRange!(typeof(cy)));
4588             auto t = take(cy, 20);
4589             assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
4590 
4591             const cRange = cy;
4592             assert(cRange.front == 1);
4593 
4594             static if (hasAssignableElements!DummyType)
4595             {
4596                 {
4597                     cy.front = 66;
4598                     scope(exit) cy.front = 1;
4599                     assert(dummy.front == 66);
4600                 }
4601 
4602                 static if (isRandomAccessRange!DummyType)
4603                 {
4604                     {
4605                         cy[10] = 66;
4606                         scope(exit) cy[10] = 1;
4607                         assert(dummy.front == 66);
4608                     }
4609 
4610                     assert(cRange[10] == 1);
4611                 }
4612             }
4613 
4614             static if (hasSlicing!DummyType)
4615             {
4616                 auto slice = cy[5 .. 15];
4617                 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
4618                 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
4619 
4620                 auto infSlice = cy[7 .. $];
4621                 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
4622                 static assert(isInfinite!(typeof(infSlice)));
4623             }
4624         }
4625     }
4626 }
4627 
4628 @system nothrow unittest // For static arrays.
4629 {
4630     import std.algorithm.comparison : equal;
4631 
4632     int[3] a = [ 1, 2, 3 ];
4633     static assert(isStaticArray!(typeof(a)));
4634     auto c = cycle(a);
4635     assert(a.ptr == c._ptr);
4636     assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
4637     static assert(isForwardRange!(typeof(c)));
4638 
4639     // Test qualifiers on slicing.
4640     alias C = typeof(c);
4641     static assert(is(typeof(c[1 .. $]) == C));
4642     const cConst = c;
4643     static assert(is(typeof(cConst[1 .. $]) == const(C)));
4644 }
4645 
4646 @safe nothrow unittest // For infinite ranges
4647 {
4648     struct InfRange
4649     {
4650         void popFront() { }
4651         @property int front() { return 0; }
4652         enum empty = false;
4653         auto save() { return this; }
4654     }
4655     struct NonForwardInfRange
4656     {
4657         void popFront() { }
4658         @property int front() { return 0; }
4659         enum empty = false;
4660     }
4661 
4662     InfRange i;
4663     NonForwardInfRange j;
4664     auto c = cycle(i);
4665     assert(c == i);
4666     //make sure it can alias out even non-forward infinite ranges
4667     static assert(is(typeof(j.cycle) == typeof(j)));
4668 }
4669 
4670 @safe unittest
4671 {
4672     import std.algorithm.comparison : equal;
4673 
4674     int[5] arr = [0, 1, 2, 3, 4];
4675     auto cleD = cycle(arr[]); //Dynamic
4676     assert(equal(cleD[5 .. 10], arr[]));
4677 
4678     //n is a multiple of 5 worth about 3/4 of size_t.max
4679     auto n = size_t.max/4 + size_t.max/2;
4680     n -= n % 5;
4681 
4682     //Test index overflow
4683     foreach (_ ; 0 .. 10)
4684     {
4685         cleD = cleD[n .. $];
4686         assert(equal(cleD[5 .. 10], arr[]));
4687     }
4688 }
4689 
4690 @system @nogc nothrow unittest
4691 {
4692     import std.algorithm.comparison : equal;
4693 
4694     int[5] arr = [0, 1, 2, 3, 4];
4695     auto cleS = cycle(arr);   //Static
4696     assert(equal(cleS[5 .. 10], arr[]));
4697 
4698     //n is a multiple of 5 worth about 3/4 of size_t.max
4699     auto n = size_t.max/4 + size_t.max/2;
4700     n -= n % 5;
4701 
4702     //Test index overflow
4703     foreach (_ ; 0 .. 10)
4704     {
4705         cleS = cleS[n .. $];
4706         assert(equal(cleS[5 .. 10], arr[]));
4707     }
4708 }
4709 
4710 @system unittest
4711 {
4712     import std.algorithm.comparison : equal;
4713 
4714     int[1] arr = [0];
4715     auto cleS = cycle(arr);
4716     cleS = cleS[10 .. $];
4717     assert(equal(cleS[5 .. 10], 0.repeat(5)));
4718     assert(cleS.front == 0);
4719 }
4720 
4721 // https://issues.dlang.org/show_bug.cgi?id=10845
4722 @system unittest
4723 {
4724     import std.algorithm.comparison : equal;
4725     import std.algorithm.iteration : filter;
4726 
4727     auto a = inputRangeObject(iota(3).filter!"true");
4728     assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
4729 }
4730 
4731 // https://issues.dlang.org/show_bug.cgi?id=12177
4732 @safe unittest
4733 {
4734     static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
4735 }
4736 
4737 // https://issues.dlang.org/show_bug.cgi?id=13390
4738 @system unittest
4739 {
4740     import core.exception : AssertError;
4741     import std.exception : assertThrown;
4742     assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
4743 }
4744 
4745 // https://issues.dlang.org/show_bug.cgi?id=18657
4746 pure @safe unittest
4747 {
4748     import std.algorithm.comparison : equal;
4749     string s = "foo";
4750     auto r = refRange(&s).cycle.take(4);
4751     assert(equal(r.save, "foof"));
4752     assert(equal(r.save, "foof"));
4753 }
4754 
4755 private alias lengthType(R) = typeof(R.init.length.init);
4756 
4757 /**
4758    Iterate several ranges in lockstep. The element type is a proxy tuple
4759    that allows accessing the current element in the `n`th range by
4760    using `e[n]`.
4761 
4762    `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
4763    bundle its elements and uses the `opApply` protocol.
4764    `lockstep` allows reference access to the elements in
4765    `foreach` iterations.
4766 
4767     Params:
4768         sp = controls what `zip` will do if the ranges are different lengths
4769         ranges = the ranges to zip together
4770     Returns:
4771         At minimum, an input range. `Zip` offers the lowest range facilities
4772         of all components, e.g. it offers random access iff all ranges offer
4773         random access, and also offers mutation and swapping if all ranges offer
4774         it. Due to this, `Zip` is extremely powerful because it allows manipulating
4775         several ranges in lockstep.
4776     Throws:
4777         An `Exception` if all of the ranges are not the same length and
4778         `sp` is set to `StoppingPolicy.requireSameLength`.
4779 
4780     Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for
4781     the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This
4782     limitation is not shared by the anonymous range returned by the `zip`
4783     function when not given an explicit `StoppingPolicy` as an argument.
4784 */
4785 struct Zip(Ranges...)
4786 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4787 {
4788     import std.format : format; //for generic mixins
4789     import std.typecons : Tuple;
4790 
4791     alias R = Ranges;
4792     private R ranges;
4793     alias ElementType = Tuple!(staticMap!(.ElementType, R));
4794     private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
4795 
4796 /**
4797    Builds an object. Usually this is invoked indirectly by using the
4798    $(LREF zip) function.
4799  */
4800     this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
4801     {
4802         ranges[] = rs[];
4803         stoppingPolicy = s;
4804     }
4805 
4806 /**
4807    Returns `true` if the range is at end. The test depends on the
4808    stopping policy.
4809 */
4810     static if (allSatisfy!(isInfinite, R))
4811     {
4812         // BUG:  Doesn't propagate infiniteness if only some ranges are infinite
4813         //       and s == StoppingPolicy.longest.  This isn't fixable in the
4814         //       current design since StoppingPolicy is known only at runtime.
4815         enum bool empty = false;
4816     }
4817     else
4818     {
4819         ///
4820         @property bool empty()
4821         {
4822             import std.exception : enforce;
4823             import std.meta : anySatisfy;
4824 
4825             final switch (stoppingPolicy)
4826             {
4827             case StoppingPolicy.shortest:
4828                 foreach (i, Unused; R)
4829                 {
4830                     if (ranges[i].empty) return true;
4831                 }
4832                 return false;
4833             case StoppingPolicy.longest:
4834                 static if (anySatisfy!(isInfinite, R))
4835                 {
4836                     return false;
4837                 }
4838                 else
4839                 {
4840                     foreach (i, Unused; R)
4841                     {
4842                         if (!ranges[i].empty) return false;
4843                     }
4844                     return true;
4845                 }
4846             case StoppingPolicy.requireSameLength:
4847                 foreach (i, Unused; R[1 .. $])
4848                 {
4849                     enforce(ranges[0].empty ==
4850                             ranges[i + 1].empty,
4851                             "Inequal-length ranges passed to Zip");
4852                 }
4853                 return ranges[0].empty;
4854             }
4855             assert(false);
4856         }
4857     }
4858 
4859     static if (allSatisfy!(isForwardRange, R))
4860     {
4861         ///
4862         @property Zip save()
4863         {
4864             //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
4865             return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4866         }
4867     }
4868 
4869     private .ElementType!(R[i]) tryGetInit(size_t i)()
4870     {
4871         alias E = .ElementType!(R[i]);
4872         static if (!is(typeof({static E i;})))
4873             throw new Exception("Range with non-default constructable elements exhausted.");
4874         else
4875             return E.init;
4876     }
4877 
4878 /**
4879    Returns the current iterated element.
4880 */
4881     @property ElementType front()
4882     {
4883         @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
4884         //ElementType(tryGetFront!0, tryGetFront!1, ...)
4885         return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
4886     }
4887 
4888 /**
4889    Sets the front of all iterated ranges.
4890 */
4891     static if (allSatisfy!(hasAssignableElements, R))
4892     {
4893         @property void front(ElementType v)
4894         {
4895             foreach (i, Unused; R)
4896             {
4897                 if (!ranges[i].empty)
4898                 {
4899                     ranges[i].front = v[i];
4900                 }
4901             }
4902         }
4903     }
4904 
4905 /**
4906    Moves out the front.
4907 */
4908     static if (allSatisfy!(hasMobileElements, R))
4909     {
4910         ElementType moveFront()
4911         {
4912             @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4913             //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
4914             return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
4915         }
4916     }
4917 
4918 /**
4919    Returns the rightmost element.
4920 */
4921     static if (allSatisfy!(isBidirectionalRange, R))
4922     {
4923         @property ElementType back()
4924         {
4925             //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4926 
4927             @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
4928             //ElementType(tryGetBack!0, tryGetBack!1, ...)
4929             return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
4930         }
4931 
4932 /**
4933    Moves out the back.
4934 */
4935         static if (allSatisfy!(hasMobileElements, R))
4936         {
4937             ElementType moveBack()
4938             {
4939                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4940 
4941                 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();}
4942                 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
4943                 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
4944             }
4945         }
4946 
4947 /**
4948    Returns the current iterated element.
4949 */
4950         static if (allSatisfy!(hasAssignableElements, R))
4951         {
4952             @property void back(ElementType v)
4953             {
4954                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
4955                 //Not sure the call is even legal for StoppingPolicy.longest
4956 
4957                 foreach (i, Unused; R)
4958                 {
4959                     if (!ranges[i].empty)
4960                     {
4961                         ranges[i].back = v[i];
4962                     }
4963                 }
4964             }
4965         }
4966     }
4967 
4968 /**
4969    Advances to the next element in all controlled ranges.
4970 */
4971     void popFront()
4972     {
4973         import std.exception : enforce;
4974 
4975         final switch (stoppingPolicy)
4976         {
4977         case StoppingPolicy.shortest:
4978             foreach (i, Unused; R)
4979             {
4980                 assert(!ranges[i].empty);
4981                 ranges[i].popFront();
4982             }
4983             break;
4984         case StoppingPolicy.longest:
4985             foreach (i, Unused; R)
4986             {
4987                 if (!ranges[i].empty) ranges[i].popFront();
4988             }
4989             break;
4990         case StoppingPolicy.requireSameLength:
4991             foreach (i, Unused; R)
4992             {
4993                 enforce(!ranges[i].empty, "Invalid Zip object");
4994                 ranges[i].popFront();
4995             }
4996             break;
4997         }
4998     }
4999 
5000 /**
5001    Calls `popBack` for all controlled ranges.
5002 */
5003     static if (allSatisfy!(isBidirectionalRange, R))
5004     {
5005         void popBack()
5006         {
5007             //TODO: Fixme! In case of jaggedness, this is wrong.
5008             import std.exception : enforce;
5009 
5010             final switch (stoppingPolicy)
5011             {
5012             case StoppingPolicy.shortest:
5013                 foreach (i, Unused; R)
5014                 {
5015                     assert(!ranges[i].empty);
5016                     ranges[i].popBack();
5017                 }
5018                 break;
5019             case StoppingPolicy.longest:
5020                 foreach (i, Unused; R)
5021                 {
5022                     if (!ranges[i].empty) ranges[i].popBack();
5023                 }
5024                 break;
5025             case StoppingPolicy.requireSameLength:
5026                 foreach (i, Unused; R)
5027                 {
5028                     enforce(!ranges[i].empty, "Invalid Zip object");
5029                     ranges[i].popBack();
5030                 }
5031                 break;
5032             }
5033         }
5034     }
5035 
5036 /**
5037    Returns the length of this range. Defined only if all ranges define
5038    `length`.
5039 */
5040     static if (allSatisfy!(hasLength, R))
5041     {
5042         @property auto length()
5043         {
5044             static if (Ranges.length == 1)
5045                 return ranges[0].length;
5046             else
5047             {
5048                 if (stoppingPolicy == StoppingPolicy.requireSameLength)
5049                     return ranges[0].length;
5050 
5051                 //[min|max](ranges[0].length, ranges[1].length, ...)
5052                 import std.algorithm.comparison : min, max;
5053                 if (stoppingPolicy == StoppingPolicy.shortest)
5054                     return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5055                 else
5056                     return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5057             }
5058         }
5059 
5060         alias opDollar = length;
5061     }
5062 
5063 /**
5064    Returns a slice of the range. Defined only if all range define
5065    slicing.
5066 */
5067     static if (allSatisfy!(hasSlicing, R))
5068     {
5069         auto opSlice(size_t from, size_t to)
5070         {
5071             //Slicing an infinite range yields the type Take!R
5072             //For finite ranges, the type Take!R aliases to R
5073             alias ZipResult = Zip!(staticMap!(Take, R));
5074 
5075             //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
5076             return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
5077         }
5078     }
5079 
5080 /**
5081    Returns the `n`th element in the composite range. Defined if all
5082    ranges offer random access.
5083 */
5084     static if (allSatisfy!(isRandomAccessRange, R))
5085     {
5086         ElementType opIndex(size_t n)
5087         {
5088             //TODO: Fixme! This may create an out of bounds access
5089             //for StoppingPolicy.longest
5090 
5091             //ElementType(ranges[0][n], ranges[1][n], ...)
5092             return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
5093         }
5094 
5095 /**
5096    Assigns to the `n`th element in the composite range. Defined if
5097    all ranges offer random access.
5098 */
5099         static if (allSatisfy!(hasAssignableElements, R))
5100         {
5101             void opIndexAssign(ElementType v, size_t n)
5102             {
5103                 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
5104                 foreach (i, Range; R)
5105                 {
5106                     ranges[i][n] = v[i];
5107                 }
5108             }
5109         }
5110 
5111 /**
5112    Destructively reads the `n`th element in the composite
5113    range. Defined if all ranges offer random access.
5114 */
5115         static if (allSatisfy!(hasMobileElements, R))
5116         {
5117             ElementType moveAt(size_t n)
5118             {
5119                 //TODO: Fixme! This may create an out of bounds access
5120                 //for StoppingPolicy.longest
5121 
5122                 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
5123                 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
5124             }
5125         }
5126     }
5127 }
5128 
5129 /// Ditto
5130 auto zip(Ranges...)(Ranges ranges)
5131 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5132 {
5133     import std.meta : anySatisfy, templateOr;
5134     static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1)
5135     {
5136         return ZipShortest!(Ranges)(ranges);
5137     }
5138     else static if (allSatisfy!(isBidirectionalRange, Ranges))
5139     {
5140         static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)
5141             && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges)
5142             && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges)))
5143         {
5144             // If all the ranges are bidirectional, if possible slice them to
5145             // the same length to simplify the implementation.
5146             static assert(anySatisfy!(hasLength, Ranges));
5147             static foreach (i, Range; Ranges)
5148                 static if (hasLength!Range)
5149                 {
5150                     static if (!is(typeof(minLen) == size_t))
5151                         size_t minLen = ranges[i].length;
5152                     else
5153                     {{
5154                         const x = ranges[i].length;
5155                         if (x < minLen) minLen = x;
5156                     }}
5157                 }
5158             import std.format : format;
5159             static if (!anySatisfy!(isInfinite, Ranges))
5160                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5161                     `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length)));
5162             else
5163                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5164                     `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length)));
5165         }
5166         else static if (allSatisfy!(isRandomAccessRange, Ranges))
5167         {
5168             // We can't slice but we can still use random access to ensure
5169             // "back" is retrieving the same index for each range.
5170             return ZipShortest!(Ranges)(ranges);
5171         }
5172         else
5173         {
5174             // If bidirectional range operations would not be supported by
5175             // ZipShortest that might have actually been a bug since Zip
5176             // supported `back` without verifying that each range had the
5177             // same length, but for the sake of backwards compatibility
5178             // use the old Zip to continue supporting them.
5179             return Zip!Ranges(ranges);
5180         }
5181     }
5182     else
5183     {
5184         return ZipShortest!(Ranges)(ranges);
5185     }
5186 }
5187 
5188 ///
5189 @nogc nothrow pure @safe unittest
5190 {
5191     import std.algorithm.comparison : equal;
5192     import std.algorithm.iteration : map;
5193 
5194     // pairwise sum
5195     auto arr = only(0, 1, 2);
5196     auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
5197     assert(part1.equal(only(1, 3)));
5198 }
5199 
5200 ///
5201 nothrow pure @safe unittest
5202 {
5203     import std.conv : to;
5204 
5205     int[] a = [ 1, 2, 3 ];
5206     string[] b = [ "a", "b", "c" ];
5207     string[] result;
5208 
5209     foreach (tup; zip(a, b))
5210     {
5211         result ~= tup[0].to!string ~ tup[1];
5212     }
5213 
5214     assert(result == [ "1a", "2b", "3c" ]);
5215 
5216     size_t idx = 0;
5217     // unpacking tuple elements with foreach
5218     foreach (e1, e2; zip(a, b))
5219     {
5220         assert(e1 == a[idx]);
5221         assert(e2 == b[idx]);
5222         ++idx;
5223     }
5224 }
5225 
5226 /// `zip` is powerful - the following code sorts two arrays in parallel:
5227 nothrow pure @safe unittest
5228 {
5229     import std.algorithm.sorting : sort;
5230 
5231     int[] a = [ 1, 2, 3 ];
5232     string[] b = [ "a", "c", "b" ];
5233     zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
5234 
5235     assert(a == [ 3, 2, 1 ]);
5236     // b is sorted according to a's sorting
5237     assert(b == [ "b", "c", "a" ]);
5238 }
5239 
5240 /// Ditto
5241 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
5242 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5243 {
5244     return Zip!Ranges(ranges, sp);
5245 }
5246 
5247 /**
5248    Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop.
5249    By default stop at the end of the shortest of all ranges.
5250 */
5251 enum StoppingPolicy
5252 {
5253     /// Stop when the shortest range is exhausted
5254     shortest,
5255     /// Stop when the longest range is exhausted
5256     longest,
5257     /// Require that all ranges are equal
5258     requireSameLength,
5259 }
5260 
5261 ///
5262 pure @safe unittest
5263 {
5264     import std.algorithm.comparison : equal;
5265     import std.exception : assertThrown;
5266     import std.range.primitives;
5267     import std.typecons : tuple;
5268 
5269     auto a = [1, 2, 3];
5270     auto b = [4, 5, 6, 7];
5271 
5272     auto shortest = zip(StoppingPolicy.shortest, a, b);
5273     assert(shortest.equal([
5274         tuple(1, 4),
5275         tuple(2, 5),
5276         tuple(3, 6)
5277     ]));
5278 
5279     auto longest = zip(StoppingPolicy.longest, a, b);
5280     assert(longest.equal([
5281         tuple(1, 4),
5282         tuple(2, 5),
5283         tuple(3, 6),
5284         tuple(0, 7)
5285     ]));
5286 
5287     auto same = zip(StoppingPolicy.requireSameLength, a, b);
5288     same.popFrontN(3);
5289     assertThrown!Exception(same.popFront);
5290 }
5291 
5292 /+
5293 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest`
5294 except it properly implements `back` and `popBack` in the
5295 case of uneven ranges or disables those operations when
5296 it is not possible to guarantee they are correct.
5297 +/
5298 package template ZipShortest(Ranges...)
5299 if (Ranges.length && __traits(compiles,
5300     {
5301         static assert(allSatisfy!(isInputRange, Ranges));
5302     }))
5303 {
5304     alias ZipShortest = .ZipShortest!(
5305         Ranges.length == 1 || allSatisfy!(isInfinite, Ranges)
5306             ? Yes.allKnownSameLength
5307             : No.allKnownSameLength,
5308         Ranges);
5309 }
5310 /+ non-public, ditto +/
5311 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...)
5312 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5313 {
5314     import std.format : format; //for generic mixins
5315     import std.meta : anySatisfy, templateOr;
5316     import std.typecons : Tuple;
5317 
5318     deprecated("Use of an undocumented alias R.")
5319     alias R = Ranges; // Unused here but defined in case library users rely on it.
5320     private Ranges ranges;
5321     alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
5322 
5323     /+
5324        Builds an object. Usually this is invoked indirectly by using the
5325        $(LREF zip) function.
5326     +/
5327     this(Ranges rs)
5328     {
5329         ranges[] = rs[];
5330     }
5331 
5332     /+
5333        Returns `true` if the range is at end.
5334     +/
5335     static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges)
5336         : allSatisfy!(isInfinite, Ranges))
5337     {
5338         enum bool empty = false;
5339     }
5340     else
5341     {
5342         @property bool empty()
5343         {
5344             static if (allKnownSameLength)
5345             {
5346                 return ranges[0].empty;
5347             }
5348             else
5349             {
5350                 static foreach (i; 0 .. Ranges.length)
5351                 {
5352                     if (ranges[i].empty)
5353                         return true;
5354                 }
5355                 return false;
5356             }
5357         }
5358     }
5359 
5360     /+
5361        Forward range primitive. Only present if each constituent range is a
5362        forward range.
5363     +/
5364     static if (allSatisfy!(isForwardRange, Ranges))
5365     @property typeof(this) save()
5366     {
5367         return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length)));
5368     }
5369 
5370     /+
5371        Returns the current iterated element.
5372     +/
5373     @property ElementType front()
5374     {
5375         return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length)));
5376     }
5377 
5378     /+
5379        Sets the front of all iterated ranges. Only present if each constituent
5380        range has assignable elements.
5381     +/
5382     static if (allSatisfy!(hasAssignableElements, Ranges))
5383     @property void front()(ElementType v)
5384     {
5385         static foreach (i; 0 .. Ranges.length)
5386             ranges[i].front = v[i];
5387     }
5388 
5389     /+
5390        Moves out the front. Present if each constituent range has mobile elements.
5391     +/
5392     static if (allSatisfy!(hasMobileElements, Ranges))
5393     ElementType moveFront()()
5394     {
5395         return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length)));
5396     }
5397 
5398     private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges)
5399         && (allKnownSameLength
5400             || allSatisfy!(isRandomAccessRange, Ranges)
5401             // Could also add the case where there is one non-infinite bidirectional
5402             // range that defines `length` and all others are infinite random access
5403             // ranges. Adding this would require appropriate branches in
5404             // back/moveBack/popBack.
5405             );
5406 
5407     /+
5408        Returns the rightmost element. Present if all constituent ranges are
5409        bidirectional and either there is a compile-time guarantee that all
5410        ranges have the same length (in `allKnownSameLength`) or all ranges
5411        provide random access to elements.
5412     +/
5413     static if (isBackWellDefined)
5414     @property ElementType back()
5415     {
5416         static if (allKnownSameLength)
5417         {
5418             return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length)));
5419         }
5420         else
5421         {
5422             const backIndex = length - 1;
5423             return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length)));
5424         }
5425     }
5426 
5427     /+
5428        Moves out the back. Present if `back` is defined and
5429        each constituent range has mobile elements.
5430     +/
5431     static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges))
5432     ElementType moveBack()()
5433     {
5434         static if (allKnownSameLength)
5435         {
5436             return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length)));
5437         }
5438         else
5439         {
5440             const backIndex = length - 1;
5441             return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length)));
5442         }
5443     }
5444 
5445     /+
5446        Sets the rightmost element. Only present if `back` is defined and
5447        each constituent range has assignable elements.
5448     +/
5449     static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges))
5450     @property void back()(ElementType v)
5451     {
5452         static if (allKnownSameLength)
5453         {
5454             static foreach (i; 0 .. Ranges.length)
5455                 ranges[i].back = v[i];
5456         }
5457         else
5458         {
5459             const backIndex = length - 1;
5460             static foreach (i; 0 .. Ranges.length)
5461                 ranges[i][backIndex] = v[i];
5462         }
5463     }
5464 
5465     /+
5466        Calls `popFront` on each constituent range.
5467     +/
5468     void popFront()
5469     {
5470         static foreach (i; 0 .. Ranges.length)
5471             ranges[i].popFront();
5472     }
5473 
5474     /+
5475        Pops the rightmost element. Present if `back` is defined.
5476     +/
5477     static if (isBackWellDefined)
5478     void popBack()
5479     {
5480         static if (allKnownSameLength)
5481         {
5482             static foreach (i; 0 .. Ranges.length)
5483                 ranges[i].popBack;
5484         }
5485         else
5486         {
5487             const len = length;
5488             static foreach (i; 0 .. Ranges.length)
5489                 static if (!isInfinite!(Ranges[i]))
5490                     if (ranges[i].length == len)
5491                         ranges[i].popBack();
5492         }
5493     }
5494 
5495     /+
5496        Returns the length of this range. Defined if at least one
5497        constituent range defines `length` and the other ranges all also
5498        define `length` or are infinite, or if at least one constituent
5499        range defines `length` and there is a compile-time guarantee that
5500        all ranges have the same length (in `allKnownSameLength`).
5501     +/
5502     static if (allKnownSameLength
5503         ? anySatisfy!(hasLength, Ranges)
5504         : (anySatisfy!(hasLength, Ranges)
5505             && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
5506     {
5507         @property size_t length()
5508         {
5509            static foreach (i, Range; Ranges)
5510            {
5511                 static if (hasLength!Range)
5512                 {
5513                     static if (!is(typeof(minLen) == size_t))
5514                         size_t minLen = ranges[i].length;
5515                     else static if (!allKnownSameLength)
5516                     {{
5517                         const x = ranges[i].length;
5518                         if (x < minLen) minLen = x;
5519                     }}
5520                 }
5521             }
5522             return minLen;
5523         }
5524 
5525         alias opDollar = length;
5526     }
5527 
5528     /+
5529        Returns a slice of the range. Defined if all constituent ranges
5530        support slicing.
5531     +/
5532     static if (allSatisfy!(hasSlicing, Ranges))
5533     {
5534         // Note: we will know that all elements of the resultant range
5535         // will have the same length but we cannot change `allKnownSameLength`
5536         // because the `hasSlicing` predicate tests that the result returned
5537         // by `opSlice` has the same type as the receiver.
5538         auto opSlice()(size_t from, size_t to)
5539         {
5540             //(ranges[0][from .. to], ranges[1][from .. to], ...)
5541             enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length));
5542             static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs)))
5543                 return mixin(`typeof(this)`~sliceArgs);
5544             else
5545                 // The type is different anyway so we might as well
5546                 // explicitly set allKnownSameLength.
5547                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`
5548                     ~sliceArgs);
5549         }
5550     }
5551 
5552     /+
5553        Returns the `n`th element in the composite range. Defined if all
5554        constituent ranges offer random access.
5555     +/
5556     static if (allSatisfy!(isRandomAccessRange, Ranges))
5557     ElementType opIndex()(size_t n)
5558     {
5559         return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length)));
5560     }
5561 
5562     /+
5563        Sets the `n`th element in the composite range. Defined if all
5564        constituent ranges offer random access and have assignable elements.
5565     +/
5566     static if (allSatisfy!(isRandomAccessRange, Ranges)
5567         && allSatisfy!(hasAssignableElements, Ranges))
5568     void opIndexAssign()(ElementType v, size_t n)
5569     {
5570         static foreach (i; 0 .. Ranges.length)
5571             ranges[i][n] = v[i];
5572     }
5573 
5574     /+
5575        Destructively reads the `n`th element in the composite
5576        range. Defined if all constituent ranges offer random
5577        access and have mobile elements.
5578     +/
5579     static if (allSatisfy!(isRandomAccessRange, Ranges)
5580         && allSatisfy!(hasMobileElements, Ranges))
5581     ElementType moveAt()(size_t n)
5582     {
5583         return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length)));
5584     }
5585 }
5586 
5587 pure @system unittest
5588 {
5589     import std.algorithm.comparison : equal;
5590     import std.algorithm.iteration : filter, map;
5591     import std.algorithm.mutation : swap;
5592     import std.algorithm.sorting : sort;
5593 
5594     import std.exception : assertThrown, assertNotThrown;
5595     import std.typecons : tuple;
5596 
5597     int[] a = [ 1, 2, 3 ];
5598     float[] b = [ 1.0, 2.0, 3.0 ];
5599     foreach (e; zip(a, b))
5600     {
5601         assert(e[0] == e[1]);
5602     }
5603 
5604     swap(a[0], a[1]);
5605     {
5606         auto z = zip(a, b);
5607     }
5608     //swap(z.front(), z.back());
5609     sort!("a[0] < b[0]")(zip(a, b));
5610     assert(a == [1, 2, 3]);
5611     assert(b == [2.0, 1.0, 3.0]);
5612 
5613     auto z = zip(StoppingPolicy.requireSameLength, a, b);
5614     assertNotThrown(z.popBack());
5615     assertNotThrown(z.popBack());
5616     assertNotThrown(z.popBack());
5617     assert(z.empty);
5618     assertThrown(z.popBack());
5619 
5620     a = [ 1, 2, 3 ];
5621     b = [ 1.0, 2.0, 3.0 ];
5622     sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
5623     assert(a == [3, 2, 1]);
5624     assert(b == [3.0, 2.0, 1.0]);
5625 
5626     a = [];
5627     b = [];
5628     assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
5629 
5630     // Test infiniteness propagation.
5631     static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
5632 
5633     // Test stopping policies with both value and reference.
5634     auto a1 = [1, 2];
5635     auto a2 = [1, 2, 3];
5636     auto stuff = tuple(tuple(a1, a2),
5637             tuple(filter!"a"(a1), filter!"a"(a2)));
5638 
5639     alias FOO = Zip!(immutable(int)[], immutable(float)[]);
5640 
5641     foreach (t; stuff.expand)
5642     {
5643         auto arr1 = t[0];
5644         auto arr2 = t[1];
5645         auto zShortest = zip(arr1, arr2);
5646         assert(equal(map!"a[0]"(zShortest), [1, 2]));
5647         assert(equal(map!"a[1]"(zShortest), [1, 2]));
5648 
5649         try {
5650             auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
5651             foreach (elem; zSame) {}
5652             assert(0);
5653         } catch (Throwable) { /* It's supposed to throw.*/ }
5654 
5655         auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
5656         assert(!zLongest.ranges[0].empty);
5657         assert(!zLongest.ranges[1].empty);
5658 
5659         zLongest.popFront();
5660         zLongest.popFront();
5661         assert(!zLongest.empty);
5662         assert(zLongest.ranges[0].empty);
5663         assert(!zLongest.ranges[1].empty);
5664 
5665         zLongest.popFront();
5666         assert(zLongest.empty);
5667     }
5668 
5669     // https://issues.dlang.org/show_bug.cgi?id=8900
5670     assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
5671     assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
5672 
5673     // https://issues.dlang.org/show_bug.cgi?id=18524
5674     // moveBack instead performs moveFront
5675     {
5676         auto r = zip([1,2,3]);
5677         assert(r.moveBack()[0] == 3);
5678         assert(r.moveFront()[0] == 1);
5679     }
5680 
5681     // Doesn't work yet.  Issues w/ emplace.
5682     // static assert(is(Zip!(immutable int[], immutable float[])));
5683 
5684 
5685     // These unittests pass, but make the compiler consume an absurd amount
5686     // of RAM and time.  Therefore, they should only be run if explicitly
5687     // uncommented when making changes to Zip.  Also, running them using
5688     // make -fwin32.mak unittest makes the compiler completely run out of RAM.
5689     // You need to test just this module.
5690     /+
5691      foreach (DummyType1; AllDummyRanges)
5692      {
5693          DummyType1 d1;
5694          foreach (DummyType2; AllDummyRanges)
5695          {
5696              DummyType2 d2;
5697              auto r = zip(d1, d2);
5698              assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
5699              assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
5700 
5701              static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
5702              {
5703                  static assert(isForwardRange!(typeof(r)));
5704              }
5705 
5706              static if (isBidirectionalRange!DummyType1 &&
5707                      isBidirectionalRange!DummyType2) {
5708                  static assert(isBidirectionalRange!(typeof(r)));
5709              }
5710              static if (isRandomAccessRange!DummyType1 &&
5711                      isRandomAccessRange!DummyType2) {
5712                  static assert(isRandomAccessRange!(typeof(r)));
5713              }
5714          }
5715      }
5716     +/
5717 }
5718 
5719 nothrow pure @safe unittest
5720 {
5721     import std.algorithm.sorting : sort;
5722 
5723     auto a = [5,4,3,2,1];
5724     auto b = [3,1,2,5,6];
5725     auto z = zip(a, b);
5726 
5727     sort!"a[0] < b[0]"(z);
5728 
5729     assert(a == [1, 2, 3, 4, 5]);
5730     assert(b == [6, 5, 2, 1, 3]);
5731 }
5732 
5733 nothrow pure @safe unittest
5734 {
5735     import std.algorithm.comparison : equal;
5736     import std.typecons : tuple;
5737 
5738     auto LL = iota(1L, 1000L);
5739     auto z = zip(LL, [4]);
5740 
5741     assert(equal(z, [tuple(1L,4)]));
5742 
5743     auto LL2 = iota(0L, 500L);
5744     auto z2 = zip([7], LL2);
5745     assert(equal(z2, [tuple(7, 0L)]));
5746 }
5747 
5748 // Test for https://issues.dlang.org/show_bug.cgi?id=11196
5749 @safe pure unittest
5750 {
5751     import std.exception : assertThrown;
5752 
5753     static struct S { @disable this(); }
5754     assert(zip((S[5]).init[]).length == 5);
5755     assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
5756     assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
5757 }
5758 
5759 // https://issues.dlang.org/show_bug.cgi?id=12007
5760 @nogc nothrow @safe pure unittest
5761 {
5762     static struct R
5763     {
5764         enum empty = false;
5765         void popFront(){}
5766         int front(){return 1;} @property
5767         R save(){return this;} @property
5768         void opAssign(R) @disable;
5769     }
5770     R r;
5771     auto z = zip(r, r);
5772     assert(z.save == z);
5773 }
5774 
5775 nothrow pure @system unittest
5776 {
5777     import std.typecons : tuple;
5778 
5779     auto r1 = [0,1,2];
5780     auto r2 = [1,2,3];
5781     auto z1 = zip(refRange(&r1), refRange(&r2));
5782     auto z2 = z1.save;
5783     z1.popFront();
5784     assert(z1.front == tuple(1,2));
5785     assert(z2.front == tuple(0,1));
5786 }
5787 
5788 @nogc nothrow pure @safe unittest
5789 {
5790     // Test zip's `back` and `length` with non-equal ranges.
5791     static struct NonSliceableRandomAccess
5792     {
5793         private int[] a;
5794         @property ref front()
5795         {
5796             return a.front;
5797         }
5798         @property ref back()
5799         {
5800             return a.back;
5801         }
5802         ref opIndex(size_t i)
5803         {
5804             return a[i];
5805         }
5806         void popFront()
5807         {
5808             a.popFront();
5809         }
5810         void popBack()
5811         {
5812             a.popBack();
5813         }
5814         auto moveFront()
5815         {
5816             return a.moveFront();
5817         }
5818         auto moveBack()
5819         {
5820             return a.moveBack();
5821         }
5822         auto moveAt(size_t i)
5823         {
5824             return a.moveAt(i);
5825         }
5826         bool empty() const
5827         {
5828             return a.empty;
5829         }
5830         size_t length() const
5831         {
5832             return a.length;
5833         }
5834         typeof(this) save()
5835         {
5836             return this;
5837         }
5838     }
5839     static assert(isRandomAccessRange!NonSliceableRandomAccess);
5840     static assert(!hasSlicing!NonSliceableRandomAccess);
5841     static foreach (iteration; 0 .. 2)
5842     {{
5843         int[5] data = [101, 102, 103, 201, 202];
5844         static if (iteration == 0)
5845         {
5846             auto r1 = NonSliceableRandomAccess(data[0 .. 3]);
5847             auto r2 = NonSliceableRandomAccess(data[3 .. 5]);
5848         }
5849         else
5850         {
5851             auto r1 = data[0 .. 3];
5852             auto r2 = data[3 .. 5];
5853         }
5854         auto z = zip(r1, r2);
5855         static assert(isRandomAccessRange!(typeof(z)));
5856         assert(z.length == 2);
5857         assert(z.back[0] == 102 && z.back[1] == 202);
5858         z.back = typeof(z.back)(-102, -202);// Assign to back.
5859         assert(z.back[0] == -102 && z.back[1] == -202);
5860         z.popBack();
5861         assert(z.length == 1);
5862         assert(z.back[0] == 101 && z.back[1] == 201);
5863         z.front = typeof(z.front)(-101, -201);
5864         assert(z.moveBack() == typeof(z.back)(-101, -201));
5865         z.popBack();
5866         assert(z.empty);
5867     }}
5868 }
5869 
5870 @nogc nothrow pure @safe unittest
5871 {
5872     // Test opSlice on infinite `zip`.
5873     auto z = zip(repeat(1), repeat(2));
5874     assert(hasSlicing!(typeof(z)));
5875     auto slice = z[10 .. 20];
5876     assert(slice.length == 10);
5877     static assert(!is(typeof(z) == typeof(slice)));
5878 }
5879 
5880 /*
5881     Generate lockstep's opApply function as a mixin string.
5882     If withIndex is true prepend a size_t index to the delegate.
5883 */
5884 private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
5885 {
5886     import std.format : format;
5887 
5888     string[] params;
5889     string[] emptyChecks;
5890     string[] dgArgs;
5891     string[] popFronts;
5892     string indexDef;
5893     string indexInc;
5894 
5895     if (withIndex)
5896     {
5897         params ~= "size_t";
5898         dgArgs ~= "index";
5899         if (reverse)
5900         {
5901             indexDef = q{
5902                 size_t index = ranges[0].length-1;
5903                 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
5904                         "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
5905 
5906                 foreach (range; ranges[1..$])
5907                     enforce(range.length == ranges[0].length);
5908                 };
5909             indexInc = "--index;";
5910         }
5911         else
5912         {
5913             indexDef = "size_t index = 0;";
5914             indexInc = "++index;";
5915         }
5916     }
5917 
5918     foreach (idx, Range; Ranges)
5919     {
5920         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
5921         emptyChecks ~= format("!ranges[%s].empty", idx);
5922         if (reverse)
5923         {
5924             dgArgs ~= format("ranges[%s].back", idx);
5925             popFronts ~= format("ranges[%s].popBack();", idx);
5926         }
5927         else
5928         {
5929             dgArgs ~= format("ranges[%s].front", idx);
5930             popFronts ~= format("ranges[%s].popFront();", idx);
5931         }
5932     }
5933 
5934     string name = reverse ? "opApplyReverse" : "opApply";
5935 
5936     return format(
5937     q{
5938         int %s(scope int delegate(%s) dg)
5939         {
5940             import std.exception : enforce;
5941 
5942             auto ranges = _ranges;
5943             int res;
5944             %s
5945 
5946             while (%s)
5947             {
5948                 res = dg(%s);
5949                 if (res) break;
5950                 %s
5951                 %s
5952             }
5953 
5954             if (_stoppingPolicy == StoppingPolicy.requireSameLength)
5955             {
5956                 foreach (range; ranges)
5957                     enforce(range.empty);
5958             }
5959             return res;
5960         }
5961     }, name, params.join(", "), indexDef,
5962        emptyChecks.join(" && "), dgArgs.join(", "),
5963        popFronts.join("\n                "),
5964        indexInc);
5965 }
5966 
5967 /**
5968    Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
5969    $(LREF zip) it allows reference access to its elements. If only a single
5970    range is passed in, the `Lockstep` aliases itself away.  If the
5971    ranges are of different lengths and `s` == `StoppingPolicy.shortest`
5972    stop after the shortest range is empty.  If the ranges are of different
5973    lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
5974    exception.  `s` may not be `StoppingPolicy.longest`, and passing this
5975    will throw an exception.
5976 
5977    Iterating over `Lockstep` in reverse and with an index is only possible
5978    when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
5979    indexes. If an attempt is made at iterating in reverse when `s` ==
5980    `StoppingPolicy.shortest`, an exception will be thrown.
5981 
5982    By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
5983 
5984    Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be
5985    inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to
5986    a different implementation.
5987 
5988    See_Also: $(LREF zip)
5989 
5990        `lockstep` is similar to $(LREF zip), but `zip` bundles its
5991        elements and returns a range.
5992        `lockstep` also supports reference access.
5993        Use `zip` if you want to pass the result to a range function.
5994 */
5995 struct Lockstep(Ranges...)
5996 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
5997 {
5998     ///
5999     this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
6000     {
6001         import std.exception : enforce;
6002 
6003         _ranges = ranges;
6004         enforce(sp != StoppingPolicy.longest,
6005                 "Can't use StoppingPolicy.Longest on Lockstep.");
6006         _stoppingPolicy = sp;
6007     }
6008 
6009     mixin(lockstepMixin!Ranges(false, false));
6010     mixin(lockstepMixin!Ranges(true, false));
6011     static if (allSatisfy!(isBidirectionalRange, Ranges))
6012     {
6013         mixin(lockstepMixin!Ranges(false, true));
6014         static if (allSatisfy!(hasLength, Ranges))
6015         {
6016             mixin(lockstepMixin!Ranges(true, true));
6017         }
6018         else
6019         {
6020             mixin(lockstepReverseFailMixin!Ranges(true));
6021         }
6022     }
6023     else
6024     {
6025         mixin(lockstepReverseFailMixin!Ranges(false));
6026         mixin(lockstepReverseFailMixin!Ranges(true));
6027     }
6028 
6029 private:
6030     alias R = Ranges;
6031     R _ranges;
6032     StoppingPolicy _stoppingPolicy;
6033 }
6034 
6035 /// Ditto
6036 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
6037 if (allSatisfy!(isInputRange, Ranges))
6038 {
6039     return Lockstep!(Ranges)(ranges);
6040 }
6041 /// Ditto
6042 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
6043 if (allSatisfy!(isInputRange, Ranges))
6044 {
6045     static if (Ranges.length > 1)
6046         return Lockstep!Ranges(ranges, s);
6047     else
6048         return ranges[0];
6049 }
6050 
6051 ///
6052 @system unittest
6053 {
6054    auto arr1 = [1,2,3,4,5,100];
6055    auto arr2 = [6,7,8,9,10];
6056 
6057    foreach (ref a, b; lockstep(arr1, arr2))
6058    {
6059        a += b;
6060    }
6061 
6062    assert(arr1 == [7,9,11,13,15,100]);
6063 
6064    /// Lockstep also supports iterating with an index variable:
6065    foreach (index, a, b; lockstep(arr1, arr2))
6066    {
6067        assert(arr1[index] == a);
6068        assert(arr2[index] == b);
6069    }
6070 }
6071 
6072 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
6073 @system unittest
6074 {
6075     auto arr1 = [0, 1, 2, 3];
6076     auto arr2 = [4, 5, 6, 7];
6077 
6078     size_t n = arr1.length -1;
6079     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
6080     {
6081         assert(n == index);
6082         assert(index == a);
6083         assert(arr1[index] == a);
6084         assert(arr2[index] == b);
6085         n--;
6086     }
6087 
6088     auto arr3 = [4, 5];
6089     n = 1;
6090     foreach_reverse (a, b; lockstep(arr1, arr3))
6091     {
6092         assert(a == arr1[$-n] && b == arr3[$-n]);
6093         n++;
6094     }
6095 }
6096 
6097 @system unittest
6098 {
6099     import std.algorithm.iteration : filter;
6100     import std.conv : to;
6101 
6102     // The filters are to make these the lowest common forward denominator ranges,
6103     // i.e. w/o ref return, random access, length, etc.
6104     auto foo = filter!"a"([1,2,3,4,5]);
6105     immutable bar = [6f,7f,8f,9f,10f].idup;
6106     auto l = lockstep(foo, bar);
6107 
6108     // Should work twice.  These are forward ranges with implicit save.
6109     foreach (i; 0 .. 2)
6110     {
6111         uint[] res1;
6112         float[] res2;
6113 
6114         foreach (a, ref b; l)
6115         {
6116             res1 ~= a;
6117             res2 ~= b;
6118         }
6119 
6120         assert(res1 == [1,2,3,4,5]);
6121         assert(res2 == [6,7,8,9,10]);
6122         assert(bar == [6f,7f,8f,9f,10f]);
6123     }
6124 
6125     // Doc example.
6126     auto arr1 = [1,2,3,4,5];
6127     auto arr2 = [6,7,8,9,10];
6128 
6129     foreach (ref a, ref b; lockstep(arr1, arr2))
6130     {
6131         a += b;
6132     }
6133 
6134     assert(arr1 == [7,9,11,13,15]);
6135 
6136     // Make sure StoppingPolicy.requireSameLength doesn't throw.
6137     auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6138 
6139     int k = 1;
6140     foreach (a, b; ls)
6141     {
6142         assert(a - b == k);
6143         ++k;
6144     }
6145 
6146     // Make sure StoppingPolicy.requireSameLength throws.
6147     arr2.popBack();
6148     ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6149 
6150     try {
6151         foreach (a, b; ls) {}
6152         assert(0);
6153     } catch (Exception) {}
6154 
6155     // Just make sure 1-range case instantiates. This hangs the compiler
6156     // when no explicit stopping policy is specified due to
6157     // https://issues.dlang.org/show_bug.cgi?id=4652
6158     auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
6159     foreach (i, a; stuff)
6160     {
6161         assert(stuff[i] == a);
6162     }
6163 
6164     // Test with indexing.
6165     uint[] res1;
6166     float[] res2;
6167     size_t[] indices;
6168     foreach (i, a, b; lockstep(foo, bar))
6169     {
6170         indices ~= i;
6171         res1 ~= a;
6172         res2 ~= b;
6173     }
6174 
6175     assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
6176     assert(res1 == [1,2,3,4,5]);
6177     assert(res2 == [6f,7f,8f,9f,10f]);
6178 
6179     // Make sure we've worked around the relevant compiler bugs and this at least
6180     // compiles w/ >2 ranges.
6181     lockstep(foo, foo, foo);
6182 
6183     // Make sure it works with const.
6184     const(int[])[] foo2 = [[1, 2, 3]];
6185     const(int[])[] bar2 = [[4, 5, 6]];
6186     auto c = chain(foo2, bar2);
6187 
6188     foreach (f, b; lockstep(c, c)) {}
6189 
6190     // Regression 10468
6191     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
6192 }
6193 
6194 @system unittest
6195 {
6196     struct RvalueRange
6197     {
6198         int[] impl;
6199         @property bool empty() { return impl.empty; }
6200         @property int front() { return impl[0]; } // N.B. non-ref
6201         void popFront() { impl.popFront(); }
6202     }
6203     auto data1 = [ 1, 2, 3, 4 ];
6204     auto data2 = [ 5, 6, 7, 8 ];
6205     auto r1 = RvalueRange(data1);
6206     auto r2 = data2;
6207     foreach (a, ref b; lockstep(r1, r2))
6208     {
6209         a++;
6210         b++;
6211     }
6212     assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
6213     assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
6214 
6215     // Since r1 is by-value only, the compiler should reject attempts to
6216     // foreach over it with ref.
6217     static assert(!__traits(compiles, {
6218         foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
6219     }));
6220 }
6221 
6222 private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
6223 {
6224     import std.format : format;
6225     string[] params;
6226     string message;
6227 
6228     if (withIndex)
6229     {
6230         message = "Indexed reverse iteration with lockstep is only supported"
6231         ~"if all ranges are bidirectional and have a length.\n";
6232     }
6233     else
6234     {
6235         message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
6236     }
6237 
6238     if (withIndex)
6239     {
6240         params ~= "size_t";
6241     }
6242 
6243     foreach (idx, Range; Ranges)
6244     {
6245         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6246     }
6247 
6248     return format(
6249     q{
6250         int opApplyReverse()(scope int delegate(%s) dg)
6251         {
6252             static assert(false, "%s");
6253         }
6254     }, params.join(", "), message);
6255 }
6256 
6257 // For generic programming, make sure Lockstep!(Range) is well defined for a
6258 // single range.
6259 template Lockstep(Range)
6260 {
6261     alias Lockstep = Range;
6262 }
6263 
6264 /**
6265 Creates a mathematical sequence given the initial values and a
6266 recurrence function that computes the next value from the existing
6267 values. The sequence comes in the form of an infinite forward
6268 range. The type `Recurrence` itself is seldom used directly; most
6269 often, recurrences are obtained by calling the function $(D
6270 recurrence).
6271 
6272 When calling `recurrence`, the function that computes the next
6273 value is specified as a template argument, and the initial values in
6274 the recurrence are passed as regular arguments. For example, in a
6275 Fibonacci sequence, there are two initial values (and therefore a
6276 state size of 2) because computing the next Fibonacci value needs the
6277 past two values.
6278 
6279 The signature of this function should be:
6280 ----
6281 auto fun(R)(R state, size_t n)
6282 ----
6283 where `n` will be the index of the current value, and `state` will be an
6284 opaque state vector that can be indexed with array-indexing notation
6285 `state[i]`, where valid values of `i` range from $(D (n - 1)) to
6286 $(D (n - State.length)).
6287 
6288 If the function is passed in string form, the state has name `"a"`
6289 and the zero-based index in the recurrence has name `"n"`. The
6290 given string must return the desired value for `a[n]` given
6291 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
6292 state size is dictated by the number of arguments passed to the call
6293 to `recurrence`. The `Recurrence` struct itself takes care of
6294 managing the recurrence's state and shifting it appropriately.
6295  */
6296 struct Recurrence(alias fun, StateType, size_t stateSize)
6297 {
6298     import std.functional : binaryFun;
6299 
6300     StateType[stateSize] _state;
6301     size_t _n;
6302 
6303     this(StateType[stateSize] initial) { _state = initial; }
6304 
6305     void popFront()
6306     {
6307         static auto trustedCycle(ref typeof(_state) s) @trusted
6308         {
6309             return cycle(s);
6310         }
6311         // The cast here is reasonable because fun may cause integer
6312         // promotion, but needs to return a StateType to make its operation
6313         // closed.  Therefore, we have no other choice.
6314         _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
6315             trustedCycle(_state), _n + stateSize);
6316         ++_n;
6317     }
6318 
6319     @property StateType front()
6320     {
6321         return _state[_n % stateSize];
6322     }
6323 
6324     @property typeof(this) save()
6325     {
6326         return this;
6327     }
6328 
6329     enum bool empty = false;
6330 }
6331 
6332 ///
6333 pure @safe nothrow unittest
6334 {
6335     import std.algorithm.comparison : equal;
6336 
6337     // The Fibonacci numbers, using function in string form:
6338     // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
6339     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6340     assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
6341 
6342     // The factorials, using function in lambda form:
6343     auto fac = recurrence!((a,n) => a[n-1] * n)(1);
6344     assert(take(fac, 10).equal([
6345         1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
6346     ]));
6347 
6348     // The triangular numbers, using function in explicit form:
6349     static size_t genTriangular(R)(R state, size_t n)
6350     {
6351         return state[n-1] + n;
6352     }
6353     auto tri = recurrence!genTriangular(0);
6354     assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
6355 }
6356 
6357 /// Ditto
6358 Recurrence!(fun, CommonType!(State), State.length)
6359 recurrence(alias fun, State...)(State initial)
6360 {
6361     CommonType!(State)[State.length] state;
6362     foreach (i, Unused; State)
6363     {
6364         state[i] = initial[i];
6365     }
6366     return typeof(return)(state);
6367 }
6368 
6369 pure @safe nothrow unittest
6370 {
6371     import std.algorithm.comparison : equal;
6372 
6373     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6374     static assert(isForwardRange!(typeof(fib)));
6375 
6376     int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
6377     assert(equal(take(fib, 10), witness));
6378     foreach (e; take(fib, 10)) {}
6379     auto fact = recurrence!("n * a[n-1]")(1);
6380     assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
6381                             2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
6382     auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
6383     foreach (e; take(piapprox, 20)) {}
6384     // Thanks to yebblies for this test and the associated fix
6385     auto r = recurrence!"a[n-2]"(1, 2);
6386     witness = [1, 2, 1, 2, 1];
6387     assert(equal(take(r, 5), witness));
6388 }
6389 
6390 /**
6391    `Sequence` is similar to `Recurrence` except that iteration is
6392    presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
6393    closed form). This means that the `n`th element in the series is
6394    computable directly from the initial values and `n` itself. This
6395    implies that the interface offered by `Sequence` is a random-access
6396    range, as opposed to the regular `Recurrence`, which only offers
6397    forward iteration.
6398 
6399    The state of the sequence is stored as a `Tuple` so it can be
6400    heterogeneous.
6401 */
6402 struct Sequence(alias fun, State)
6403 {
6404 private:
6405     import std.functional : binaryFun;
6406 
6407     alias compute = binaryFun!(fun, "a", "n");
6408     alias ElementType = typeof(compute(State.init, cast(size_t) 1));
6409     State _state;
6410     size_t _n;
6411 
6412     static struct DollarToken{}
6413 
6414 public:
6415     this(State initial, size_t n = 0)
6416     {
6417         _state = initial;
6418         _n = n;
6419     }
6420 
6421     @property ElementType front()
6422     {
6423         return compute(_state, _n);
6424     }
6425 
6426     void popFront()
6427     {
6428         ++_n;
6429     }
6430 
6431     enum opDollar = DollarToken();
6432 
6433     auto opSlice(size_t lower, size_t upper)
6434     in
6435     {
6436         assert(
6437             upper >= lower,
6438             "Attempting to slice a Sequence with a larger first argument than the second."
6439         );
6440     }
6441     do
6442     {
6443         return typeof(this)(_state, _n + lower).take(upper - lower);
6444     }
6445 
6446     auto opSlice(size_t lower, DollarToken)
6447     {
6448         return typeof(this)(_state, _n + lower);
6449     }
6450 
6451     ElementType opIndex(size_t n)
6452     {
6453         return compute(_state, n + _n);
6454     }
6455 
6456     enum bool empty = false;
6457 
6458     @property Sequence save() { return this; }
6459 }
6460 
6461 /// Ditto
6462 auto sequence(alias fun, State...)(State args)
6463 {
6464     import std.typecons : Tuple, tuple;
6465     alias Return = Sequence!(fun, Tuple!State);
6466     return Return(tuple(args));
6467 }
6468 
6469 /// Odd numbers, using function in string form:
6470 pure @safe nothrow @nogc unittest
6471 {
6472     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6473     assert(odds.front == 1);
6474     odds.popFront();
6475     assert(odds.front == 3);
6476     odds.popFront();
6477     assert(odds.front == 5);
6478 }
6479 
6480 /// Triangular numbers, using function in lambda form:
6481 pure @safe nothrow @nogc unittest
6482 {
6483     auto tri = sequence!((a,n) => n*(n+1)/2)();
6484 
6485     // Note random access
6486     assert(tri[0] == 0);
6487     assert(tri[3] == 6);
6488     assert(tri[1] == 1);
6489     assert(tri[4] == 10);
6490     assert(tri[2] == 3);
6491 }
6492 
6493 /// Fibonacci numbers, using function in explicit form:
6494 @safe nothrow @nogc unittest
6495 {
6496     import std.math.exponential : pow;
6497     import std.math.rounding : round;
6498     import std.math.algebraic : sqrt;
6499     static ulong computeFib(S)(S state, size_t n)
6500     {
6501         // Binet's formula
6502         return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6503                                  state[2]));
6504     }
6505     auto fib = sequence!computeFib(
6506         (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
6507         (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
6508         sqrt(5.0));
6509 
6510     // Note random access with [] operator
6511     assert(fib[1] == 1);
6512     assert(fib[4] == 5);
6513     assert(fib[3] == 3);
6514     assert(fib[2] == 2);
6515     assert(fib[9] == 55);
6516 }
6517 
6518 pure @safe nothrow @nogc unittest
6519 {
6520     import std.typecons : Tuple, tuple;
6521     auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6522     static assert(isForwardRange!(typeof(y)));
6523 
6524     //@@BUG
6525     //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6526     //foreach (e; take(y, 15))
6527     {}                                 //writeln(e);
6528 
6529     auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6530         tuple(1, 2));
6531     for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6532     {
6533         assert(odds.front == odds[0]);
6534         assert(odds[0] == currentOdd);
6535         odds.popFront();
6536     }
6537 }
6538 
6539 pure @safe nothrow @nogc unittest
6540 {
6541     import std.algorithm.comparison : equal;
6542 
6543     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6544     static assert(hasSlicing!(typeof(odds)));
6545 
6546     //Note: don't use drop or take as the target of an equal,
6547     //since they'll both just forward to opSlice, making the tests irrelevant
6548 
6549     // static slicing tests
6550     assert(equal(odds[0 .. 5], only(1,  3,  5,  7,  9)));
6551     assert(equal(odds[3 .. 7], only(7,  9, 11, 13)));
6552 
6553     // relative slicing test, testing slicing is NOT agnostic of state
6554     auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6555     assert(equal(odds_less5[0 ..  3], only(11, 13, 15)));
6556     assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6557 
6558     //Infinite slicing tests
6559     odds = odds[10 .. $];
6560     assert(equal(odds.take(3), only(21, 23, 25)));
6561 }
6562 
6563 // https://issues.dlang.org/show_bug.cgi?id=5036
6564 pure @safe nothrow unittest
6565 {
6566     auto s = sequence!((a, n) => new int)(0);
6567     assert(s.front != s.front);  // no caching
6568 }
6569 
6570 // iota
6571 /**
6572    Creates a range of values that span the given starting and stopping
6573    values.
6574 
6575    Params:
6576    begin = The starting value.
6577    end = The value that serves as the stopping criterion. This value is not
6578         included in the range.
6579    step = The value to add to the current value at each iteration.
6580 
6581    Returns:
6582    A range that goes through the numbers `begin`, $(D begin + step),
6583    $(D begin + 2 * step), `...`, up to and excluding `end`.
6584 
6585    The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6586    0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6587    is returned. If $(D step == 0) then $(D begin == end) is an error.
6588 
6589    For built-in types, the range returned is a random access range. For
6590    user-defined types that support `++`, the range is an input
6591    range.
6592 
6593    An integral iota also supports `in` operator from the right. It takes
6594    the stepping into account, the integral won't be considered
6595    contained if it falls between two consecutive values of the range.
6596    `contains` does the same as in, but from lefthand side.
6597 
6598     Example:
6599     ---
6600     void main()
6601     {
6602         import std.stdio;
6603 
6604         // The following groups all produce the same output of:
6605         // 0 1 2 3 4
6606 
6607         foreach (i; 0 .. 5)
6608             writef("%s ", i);
6609         writeln();
6610 
6611         import std.range : iota;
6612         foreach (i; iota(0, 5))
6613             writef("%s ", i);
6614         writeln();
6615 
6616         writefln("%(%s %|%)", iota(0, 5));
6617 
6618         import std.algorithm.iteration : map;
6619         import std.algorithm.mutation : copy;
6620         import std.format;
6621         iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6622         writeln();
6623     }
6624     ---
6625 */
6626 auto iota(B, E, S)(B begin, E end, S step)
6627 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6628         && isIntegral!S)
6629 {
6630     import std.conv : unsigned;
6631 
6632     alias Value = CommonType!(Unqual!B, Unqual!E);
6633     alias StepType = Unqual!S;
6634 
6635     assert(step != 0 || begin == end);
6636 
6637     static struct Result
6638     {
6639         private Value current, last;
6640         private StepType step; // by convention, 0 if range is empty
6641 
6642         this(Value current, Value pastLast, StepType step)
6643         {
6644             if (current < pastLast && step > 0)
6645             {
6646                 // Iterating upward
6647                 assert(unsigned((pastLast - current) / step) <= size_t.max);
6648                 // Cast below can't fail because current < pastLast
6649                 this.last = cast(Value) (pastLast - 1);
6650                 this.last -= unsigned(this.last - current) % step;
6651             }
6652             else if (current > pastLast && step < 0)
6653             {
6654                 // Iterating downward
6655                 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6656                 // Cast below can't fail because current > pastLast
6657                 this.last = cast(Value) (pastLast + 1);
6658                 this.last += unsigned(current - this.last) % (0 - step);
6659             }
6660             else
6661             {
6662                 // Initialize an empty range
6663                 this.step = 0;
6664                 return;
6665             }
6666             this.step = step;
6667             this.current = current;
6668         }
6669 
6670         @property bool empty() const { return step == 0; }
6671         @property inout(Value) front() inout { assert(!empty); return current; }
6672         void popFront()
6673         {
6674             assert(!empty);
6675             if (current == last) step = 0;
6676             else current += step;
6677         }
6678 
6679         @property inout(Value) back() inout
6680         {
6681             assert(!empty);
6682             return last;
6683         }
6684         void popBack()
6685         {
6686             assert(!empty);
6687             if (current == last) step = 0;
6688             else last -= step;
6689         }
6690 
6691         @property auto save() { return this; }
6692 
6693         inout(Value) opIndex(ulong n) inout
6694         {
6695             assert(n < this.length);
6696 
6697             // Just cast to Value here because doing so gives overflow behavior
6698             // consistent with calling popFront() n times.
6699             return cast(inout Value) (current + step * n);
6700         }
6701         auto opBinaryRight(string op)(Value val) const
6702         if (op == "in")
6703         {
6704             if (empty) return false;
6705             //cast to avoid becoming unsigned
6706             auto supposedIndex = cast(StepType)(val - current) / step;
6707             return supposedIndex < length && supposedIndex * step + current == val;
6708         }
6709         auto contains(Value x){return x in this;}
6710         inout(Result) opSlice() inout { return this; }
6711         inout(Result) opSlice(ulong lower, ulong upper) inout
6712         {
6713             assert(upper >= lower && upper <= this.length);
6714 
6715             return cast(inout Result) Result(
6716                 cast(Value)(current + lower * step),
6717                 cast(Value)(current + upper * step),
6718                 step);
6719         }
6720         @property size_t length() const
6721         {
6722             if (step > 0)
6723                 return 1 + cast(size_t) (unsigned(last - current) / step);
6724             if (step < 0)
6725                 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6726             return 0;
6727         }
6728 
6729         alias opDollar = length;
6730     }
6731 
6732     return Result(begin, end, step);
6733 }
6734 
6735 /// Ditto
6736 auto iota(B, E)(B begin, E end)
6737 if (isFloatingPoint!(CommonType!(B, E)))
6738 {
6739     return iota(begin, end, CommonType!(B, E)(1));
6740 }
6741 
6742 /// Ditto
6743 auto iota(B, E)(B begin, E end)
6744 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6745 {
6746     import std.conv : unsigned;
6747 
6748     alias Value = CommonType!(Unqual!B, Unqual!E);
6749 
6750     static struct Result
6751     {
6752         private Value current, pastLast;
6753 
6754         this(Value current, Value pastLast)
6755         {
6756             if (current < pastLast)
6757             {
6758                 assert(unsigned(pastLast - current) <= size_t.max,
6759                     "`iota` range is too long");
6760 
6761                 this.current = current;
6762                 this.pastLast = pastLast;
6763             }
6764             else
6765             {
6766                 // Initialize an empty range
6767                 this.current = this.pastLast = current;
6768             }
6769         }
6770 
6771         @property bool empty() const { return current == pastLast; }
6772         @property inout(Value) front() inout
6773         {
6774             assert(!empty, "Attempt to access `front` of empty `iota` range");
6775             return current;
6776         }
6777         void popFront()
6778         {
6779             assert(!empty, "Attempt to `popFront` of empty `iota` range");
6780             ++current;
6781         }
6782 
6783         @property inout(Value) back() inout
6784         {
6785             assert(!empty, "Attempt to access `back` of empty `iota` range");
6786             return cast(inout(Value))(pastLast - 1);
6787         }
6788         void popBack()
6789         {
6790             assert(!empty, "Attempt to `popBack` of empty `iota` range");
6791             --pastLast;
6792         }
6793 
6794         @property auto save() { return this; }
6795 
6796         inout(Value) opIndex(size_t n) inout
6797         {
6798             assert(n < this.length,
6799                 "Attempt to read out-of-bounds index of `iota` range");
6800 
6801             // Just cast to Value here because doing so gives overflow behavior
6802             // consistent with calling popFront() n times.
6803             return cast(inout Value) (current + n);
6804         }
6805         auto opBinaryRight(string op)(Value val) const
6806         if (op == "in")
6807         {
6808             return current <= val && val < pastLast;
6809         }
6810         auto contains(Value x){return x in this;}
6811         inout(Result) opSlice() inout { return this; }
6812         inout(Result) opSlice(ulong lower, ulong upper) inout
6813         {
6814             assert(upper >= lower && upper <= this.length,
6815                 "Attempt to get out-of-bounds slice of `iota` range");
6816 
6817             return cast(inout Result) Result(cast(Value)(current + lower),
6818                                             cast(Value)(pastLast - (length - upper)));
6819         }
6820         @property size_t length() const
6821         {
6822             return cast(size_t)(pastLast - current);
6823         }
6824 
6825         alias opDollar = length;
6826     }
6827 
6828     return Result(begin, end);
6829 }
6830 
6831 /// Ditto
6832 auto iota(E)(E end)
6833 if (is(typeof(iota(E(0), end))))
6834 {
6835     E begin = E(0);
6836     return iota(begin, end);
6837 }
6838 
6839 /// Ditto
6840 // Specialization for floating-point types
6841 auto iota(B, E, S)(B begin, E end, S step)
6842 if (isFloatingPoint!(CommonType!(B, E, S)))
6843 in
6844 {
6845     assert(step != 0, "iota: step must not be 0");
6846     assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
6847 }
6848 do
6849 {
6850     alias Value = Unqual!(CommonType!(B, E, S));
6851     static struct Result
6852     {
6853         private Value start, step;
6854         private size_t index, count;
6855 
6856         this(Value start, Value end, Value step)
6857         {
6858             import std.conv : to;
6859 
6860             this.start = start;
6861             this.step = step;
6862             immutable fcount = (end - start) / step;
6863             count = to!size_t(fcount);
6864             auto pastEnd = start + count * step;
6865             if (step > 0)
6866             {
6867                 if (pastEnd < end) ++count;
6868                 assert(start + count * step >= end);
6869             }
6870             else
6871             {
6872                 if (pastEnd > end) ++count;
6873                 assert(start + count * step <= end);
6874             }
6875         }
6876 
6877         @property bool empty() const { return index == count; }
6878         @property Value front() const { assert(!empty); return start + step * index; }
6879         void popFront()
6880         {
6881             assert(!empty);
6882             ++index;
6883         }
6884         @property Value back() const
6885         {
6886             assert(!empty);
6887             return start + step * (count - 1);
6888         }
6889         void popBack()
6890         {
6891             assert(!empty);
6892             --count;
6893         }
6894 
6895         @property auto save() { return this; }
6896 
6897         Value opIndex(size_t n) const
6898         {
6899             assert(n < count);
6900             return start + step * (n + index);
6901         }
6902         inout(Result) opSlice() inout
6903         {
6904             return this;
6905         }
6906         inout(Result) opSlice(size_t lower, size_t upper) inout
6907         {
6908             assert(upper >= lower && upper <= count);
6909 
6910             Result ret = this;
6911             ret.index += lower;
6912             ret.count = upper - lower + ret.index;
6913             return cast(inout Result) ret;
6914         }
6915         @property size_t length() const
6916         {
6917             return count - index;
6918         }
6919 
6920         alias opDollar = length;
6921     }
6922 
6923     return Result(begin, end, step);
6924 }
6925 
6926 ///
6927 pure @safe unittest
6928 {
6929     import std.algorithm.comparison : equal;
6930     import std.math.operations : isClose;
6931 
6932     auto r = iota(0, 10, 1);
6933     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6934     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6935     assert(3 in r);
6936     assert(r.contains(3)); //Same as above
6937     assert(!(10 in r));
6938     assert(!(-8 in r));
6939     r = iota(0, 11, 3);
6940     assert(equal(r, [0, 3, 6, 9]));
6941     assert(r[2] == 6);
6942     assert(!(2 in r));
6943     auto rf = iota(0.0, 0.5, 0.1);
6944     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
6945 }
6946 
6947 pure nothrow @nogc @safe unittest
6948 {
6949     import std.traits : Signed;
6950    //float overloads use std.conv.to so can't be @nogc or nothrow
6951     alias ssize_t = Signed!size_t;
6952     assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
6953     assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
6954     assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
6955     assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
6956     assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
6957 }
6958 
6959 debug @system unittest
6960 {//check the contracts
6961     import core.exception : AssertError;
6962     import std.exception : assertThrown;
6963     assertThrown!AssertError(iota(1,2,0));
6964     assertThrown!AssertError(iota(0f,1f,0f));
6965     assertThrown!AssertError(iota(1f,0f,0.1f));
6966     assertThrown!AssertError(iota(0f,1f,-0.1f));
6967 }
6968 
6969 pure @system nothrow unittest
6970 {
6971     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6972     auto r1 = iota(a.ptr, a.ptr + a.length, 1);
6973     assert(r1.front == a.ptr);
6974     assert(r1.back == a.ptr + a.length - 1);
6975     assert(&a[4] in r1);
6976 }
6977 
6978 pure @safe nothrow @nogc unittest
6979 {
6980     assert(iota(1UL, 0UL).length == 0);
6981     assert(iota(1UL, 0UL, 1).length == 0);
6982     assert(iota(0, 1, 1).length == 1);
6983     assert(iota(1, 0, -1).length == 1);
6984     assert(iota(0, 1, -1).length == 0);
6985     assert(iota(ulong.max, 0).length == 0);
6986 }
6987 
6988 pure @safe unittest
6989 {
6990     import std.algorithm.comparison : equal;
6991     import std.algorithm.searching : count;
6992     import std.math.operations : isClose, nextUp, nextDown;
6993     import std.meta : AliasSeq;
6994 
6995     static assert(is(ElementType!(typeof(iota(0f))) == float));
6996 
6997     static assert(hasLength!(typeof(iota(0, 2))));
6998     auto r = iota(0, 10, 1);
6999     assert(r[$ - 1] == 9);
7000     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7001 
7002     auto rSlice = r[2 .. 8];
7003     assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
7004 
7005     rSlice.popFront();
7006     assert(rSlice[0] == rSlice.front);
7007     assert(rSlice.front == 3);
7008 
7009     rSlice.popBack();
7010     assert(rSlice[rSlice.length - 1] == rSlice.back);
7011     assert(rSlice.back == 6);
7012 
7013     rSlice = r[0 .. 4];
7014     assert(equal(rSlice, [0, 1, 2, 3]));
7015     assert(3 in rSlice);
7016     assert(!(4 in rSlice));
7017 
7018     auto rr = iota(10);
7019     assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7020 
7021     r = iota(0, -10, -1);
7022     assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
7023     rSlice = r[3 .. 9];
7024     assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
7025 
7026     r = iota(0, -6, -3);
7027     assert(equal(r, [0, -3][]));
7028     rSlice = r[1 .. 2];
7029     assert(equal(rSlice, [-3]));
7030 
7031     r = iota(0, -7, -3);
7032     assert(equal(r, [0, -3, -6][]));
7033     assert(0 in r);
7034     assert(-6 in r);
7035     rSlice = r[1 .. 3];
7036     assert(equal(rSlice, [-3, -6]));
7037     assert(!(0 in rSlice));
7038     assert(!(-2 in rSlice));
7039     assert(!(-5 in rSlice));
7040     assert(!(3 in rSlice));
7041     assert(!(-9 in rSlice));
7042 
7043     r = iota(0, 11, 3);
7044     assert(equal(r, [0, 3, 6, 9][]));
7045     assert(r[2] == 6);
7046     rSlice = r[1 .. 3];
7047     assert(equal(rSlice, [3, 6]));
7048 
7049     auto rf = iota(0.0, 0.5, 0.1);
7050     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
7051     assert(rf.length == 5);
7052 
7053     rf.popFront();
7054     assert(rf.length == 4);
7055 
7056     auto rfSlice = rf[1 .. 4];
7057     assert(rfSlice.length == 3);
7058     assert(isClose(rfSlice, [0.2, 0.3, 0.4]));
7059 
7060     rfSlice.popFront();
7061     assert(isClose(rfSlice[0], 0.3));
7062 
7063     rf.popFront();
7064     assert(rf.length == 3);
7065 
7066     rfSlice = rf[1 .. 3];
7067     assert(rfSlice.length == 2);
7068     assert(isClose(rfSlice, [0.3, 0.4]));
7069     assert(isClose(rfSlice[0], 0.3));
7070 
7071     // With something just above 0.5
7072     rf = iota(0.0, nextUp(0.5), 0.1);
7073     assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
7074     rf.popBack();
7075     assert(rf[rf.length - 1] == rf.back);
7076     assert(isClose(rf.back, 0.4));
7077     assert(rf.length == 5);
7078 
7079     // going down
7080     rf = iota(0.0, -0.5, -0.1);
7081     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
7082     rfSlice = rf[2 .. 5];
7083     assert(isClose(rfSlice, [-0.2, -0.3, -0.4]));
7084 
7085     rf = iota(0.0, nextDown(-0.5), -0.1);
7086     assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
7087 
7088     // iota of longs
7089     auto rl = iota(5_000_000L);
7090     assert(rl.length == 5_000_000L);
7091     assert(0 in rl);
7092     assert(4_000_000L in rl);
7093     assert(!(-4_000_000L in rl));
7094     assert(!(5_000_000L in rl));
7095 
7096     // iota of longs with steps
7097     auto iota_of_longs_with_steps = iota(50L, 101L, 10);
7098     assert(iota_of_longs_with_steps.length == 6);
7099     assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
7100 
7101     // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
7102     // Actually trying to consume it is the only way to find something is wrong
7103     // because the public properties are all correct.
7104     auto iota_zero_unsigned = iota(0, 0u, 3);
7105     assert(count(iota_zero_unsigned) == 0);
7106 
7107     // https://issues.dlang.org/show_bug.cgi?id=7982
7108     // unsigned reverse iota can be buggy if `.length` doesn't
7109     // take them into account
7110     assert(iota(10u, 0u, -1).length == 10);
7111     assert(iota(10u, 0u, -2).length == 5);
7112     assert(iota(uint.max, uint.max-10, -1).length == 10);
7113     assert(iota(uint.max, uint.max-10, -2).length == 5);
7114     assert(iota(uint.max, 0u, -1).length == uint.max);
7115 
7116     assert(20 in iota(20u, 10u, -2));
7117     assert(16 in iota(20u, 10u, -2));
7118     assert(!(15 in iota(20u, 10u, -2)));
7119     assert(!(10 in iota(20u, 10u, -2)));
7120     assert(!(uint.max in iota(20u, 10u, -1)));
7121     assert(!(int.min in iota(20u, 10u, -1)));
7122     assert(!(int.max in iota(20u, 10u, -1)));
7123 
7124 
7125     // https://issues.dlang.org/show_bug.cgi?id=8920
7126     static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
7127         int, uint, long, ulong))
7128     {{
7129         Type val;
7130         foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
7131         assert(val == 10);
7132     }}
7133 }
7134 
7135 pure @safe nothrow unittest
7136 {
7137     import std.algorithm.mutation : copy;
7138     auto idx = new size_t[100];
7139     copy(iota(0, idx.length), idx);
7140 }
7141 
7142 @safe unittest
7143 {
7144     import std.meta : AliasSeq;
7145     static foreach (range; AliasSeq!(iota(2, 27, 4),
7146                              iota(3, 9),
7147                              iota(2.7, 12.3, .1),
7148                              iota(3.2, 9.7)))
7149     {{
7150         const cRange = range;
7151         const e = cRange.empty;
7152         const f = cRange.front;
7153         const b = cRange.back;
7154         const i = cRange[2];
7155         const s1 = cRange[];
7156         const s2 = cRange[0 .. 3];
7157         const l = cRange.length;
7158     }}
7159 }
7160 
7161 @system unittest
7162 {
7163     //The ptr stuff can't be done at compile time, so we unfortunately end
7164     //up with some code duplication here.
7165     auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
7166 
7167     {
7168         const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
7169         const e = cRange.empty;
7170         const f = cRange.front;
7171         const b = cRange.back;
7172         const i = cRange[2];
7173         const s1 = cRange[];
7174         const s2 = cRange[0 .. 3];
7175         const l = cRange.length;
7176     }
7177 
7178     {
7179         const cRange = iota(arr.ptr, arr.ptr + arr.length);
7180         const e = cRange.empty;
7181         const f = cRange.front;
7182         const b = cRange.back;
7183         const i = cRange[2];
7184         const s1 = cRange[];
7185         const s2 = cRange[0 .. 3];
7186         const l = cRange.length;
7187     }
7188 }
7189 
7190 @nogc nothrow pure @safe unittest
7191 {
7192     {
7193         ushort start = 0, end = 10, step = 2;
7194         foreach (i; iota(start, end, step))
7195             static assert(is(typeof(i) == ushort));
7196     }
7197     {
7198         ubyte start = 0, end = 255, step = 128;
7199         uint x;
7200         foreach (i; iota(start, end, step))
7201         {
7202             static assert(is(typeof(i) == ubyte));
7203             ++x;
7204         }
7205         assert(x == 2);
7206     }
7207 }
7208 
7209 /* Generic overload that handles arbitrary types that support arithmetic
7210  * operations.
7211  *
7212  * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
7213  * as they can be incremented with `++` and compared with `<` or `==`.
7214  */
7215 /// ditto
7216 auto iota(B, E)(B begin, E end)
7217 if (!isIntegral!(CommonType!(B, E)) &&
7218     !isFloatingPoint!(CommonType!(B, E)) &&
7219     !isPointer!(CommonType!(B, E)) &&
7220     is(typeof((ref B b) { ++b; })) &&
7221     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
7222 {
7223     static struct Result
7224     {
7225         B current;
7226         E end;
7227 
7228         @property bool empty()
7229         {
7230             static if (is(typeof(B.init < E.init)))
7231                 return !(current < end);
7232             else static if (is(typeof(B.init != E.init)))
7233                 return current == end;
7234             else
7235                 static assert(0);
7236         }
7237         @property auto front() { return current; }
7238         void popFront()
7239         {
7240             assert(!empty);
7241             ++current;
7242         }
7243         @property auto save() { return this; }
7244     }
7245     return Result(begin, end);
7246 }
7247 
7248 @safe unittest
7249 {
7250     import std.algorithm.comparison : equal;
7251 
7252     // Test iota() for a type that only supports ++ and != but does not have
7253     // '<'-ordering.
7254     struct Cyclic(int wrapAround)
7255     {
7256         int current;
7257 
7258         this(int start) { current = start % wrapAround; }
7259 
7260         bool opEquals(Cyclic c) const { return current == c.current; }
7261         bool opEquals(int i) const { return current == i; }
7262         void opUnary(string op)() if (op == "++")
7263         {
7264             current = (current + 1) % wrapAround;
7265         }
7266     }
7267     alias Cycle5 = Cyclic!5;
7268 
7269     // Easy case
7270     auto i1 = iota(Cycle5(1), Cycle5(4));
7271     assert(i1.equal([1, 2, 3]));
7272 
7273     // Wraparound case
7274     auto i2 = iota(Cycle5(3), Cycle5(2));
7275     assert(i2.equal([3, 4, 0, 1 ]));
7276 }
7277 
7278 // https://issues.dlang.org/show_bug.cgi?id=23453
7279 @safe unittest
7280 {
7281     auto r = iota('a', 'z');
7282     static assert(isForwardRange!(typeof(r)));
7283 }
7284 
7285 /**
7286    Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
7287    (below).
7288 */
7289 enum TransverseOptions
7290 {
7291 /**
7292    When transversed, the elements of a range of ranges are assumed to
7293    have different lengths (e.g. a jagged array).
7294 */
7295     assumeJagged,                      //default
7296     /**
7297        The transversal enforces that the elements of a range of ranges have
7298        all the same length (e.g. an array of arrays, all having the same
7299        length). Checking is done once upon construction of the transversal
7300        range.
7301     */
7302         enforceNotJagged,
7303     /**
7304        The transversal assumes, without verifying, that the elements of a
7305        range of ranges have all the same length. This option is useful if
7306        checking was already done from the outside of the range.
7307     */
7308         assumeNotJagged,
7309 }
7310 
7311 ///
7312 @safe pure unittest
7313 {
7314     import std.algorithm.comparison : equal;
7315     import std.exception : assertThrown;
7316 
7317     auto arr = [[1, 2], [3, 4, 5]];
7318 
7319     auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
7320     assert(r1.equal([1, 3]));
7321 
7322     // throws on construction
7323     assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
7324 
7325     auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
7326     assert(r2.equal([1, 3]));
7327 
7328     // either assuming or checking for equal lengths makes
7329     // the result a random access range
7330     assert(r2[0] == 1);
7331     static assert(!__traits(compiles, r1[0]));
7332 }
7333 
7334 /**
7335    Given a range of ranges, iterate transversally through the first
7336    elements of each of the enclosed ranges.
7337 */
7338 struct FrontTransversal(Ror,
7339         TransverseOptions opt = TransverseOptions.assumeJagged)
7340 {
7341     alias RangeOfRanges = Unqual!(Ror);
7342     alias RangeType     = .ElementType!RangeOfRanges;
7343     alias ElementType   = .ElementType!RangeType;
7344 
7345     private void prime()
7346     {
7347         static if (opt == TransverseOptions.assumeJagged)
7348         {
7349             while (!_input.empty && _input.front.empty)
7350             {
7351                 _input.popFront();
7352             }
7353             static if (isBidirectionalRange!RangeOfRanges)
7354             {
7355                 while (!_input.empty && _input.back.empty)
7356                 {
7357                     _input.popBack();
7358                 }
7359             }
7360         }
7361     }
7362 
7363 /**
7364    Construction from an input.
7365 */
7366     this(RangeOfRanges input)
7367     {
7368         _input = input;
7369         prime();
7370         static if (opt == TransverseOptions.enforceNotJagged)
7371             // (isRandomAccessRange!RangeOfRanges
7372             //     && hasLength!RangeType)
7373         {
7374             import std.exception : enforce;
7375 
7376             if (empty) return;
7377             immutable commonLength = _input.front.length;
7378             foreach (e; _input)
7379             {
7380                 enforce(e.length == commonLength);
7381             }
7382         }
7383     }
7384 
7385 /**
7386    Forward range primitives.
7387 */
7388     static if (isInfinite!RangeOfRanges)
7389     {
7390         enum bool empty = false;
7391     }
7392     else
7393     {
7394         @property bool empty()
7395         {
7396             static if (opt != TransverseOptions.assumeJagged)
7397             {
7398                 if (!_input.empty)
7399                     return _input.front.empty;
7400             }
7401 
7402             return _input.empty;
7403         }
7404     }
7405 
7406     /// Ditto
7407     @property auto ref front()
7408     {
7409         assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
7410         return _input.front.front;
7411     }
7412 
7413     /// Ditto
7414     static if (hasMobileElements!RangeType)
7415     {
7416         ElementType moveFront()
7417         {
7418             return _input.front.moveFront();
7419         }
7420     }
7421 
7422     static if (hasAssignableElements!RangeType)
7423     {
7424         @property void front(ElementType val)
7425         {
7426             import std.algorithm.mutation : move;
7427 
7428             _input.front.front = move(val);
7429         }
7430     }
7431 
7432     /// Ditto
7433     void popFront()
7434     {
7435         assert(!empty, "Attempting to popFront an empty FrontTransversal");
7436         _input.popFront();
7437         prime();
7438     }
7439 
7440 /**
7441    Duplicates this `frontTransversal`. Note that only the encapsulating
7442    range of range will be duplicated. Underlying ranges will not be
7443    duplicated.
7444 */
7445     static if (isForwardRange!RangeOfRanges)
7446     {
7447         @property FrontTransversal save()
7448         {
7449             return FrontTransversal(_input.save);
7450         }
7451     }
7452 
7453     static if (isBidirectionalRange!RangeOfRanges)
7454     {
7455 /**
7456    Bidirectional primitives. They are offered if $(D
7457    isBidirectionalRange!RangeOfRanges).
7458 */
7459         @property auto ref back()
7460         {
7461             assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7462             return _input.back.front;
7463         }
7464         /// Ditto
7465         void popBack()
7466         {
7467             assert(!empty, "Attempting to popBack an empty FrontTransversal");
7468             _input.popBack();
7469             prime();
7470         }
7471 
7472         /// Ditto
7473         static if (hasMobileElements!RangeType)
7474         {
7475             ElementType moveBack()
7476             {
7477                 return _input.back.moveFront();
7478             }
7479         }
7480 
7481         static if (hasAssignableElements!RangeType)
7482         {
7483             @property void back(ElementType val)
7484             {
7485                 import std.algorithm.mutation : move;
7486 
7487                 _input.back.front = move(val);
7488             }
7489         }
7490     }
7491 
7492     static if (isRandomAccessRange!RangeOfRanges &&
7493             (opt == TransverseOptions.assumeNotJagged ||
7494                     opt == TransverseOptions.enforceNotJagged))
7495     {
7496 /**
7497    Random-access primitive. It is offered if $(D
7498    isRandomAccessRange!RangeOfRanges && (opt ==
7499    TransverseOptions.assumeNotJagged || opt ==
7500    TransverseOptions.enforceNotJagged)).
7501 */
7502         auto ref opIndex(size_t n)
7503         {
7504             return _input[n].front;
7505         }
7506 
7507         /// Ditto
7508         static if (hasMobileElements!RangeType)
7509         {
7510             ElementType moveAt(size_t n)
7511             {
7512                 return _input[n].moveFront();
7513             }
7514         }
7515         /// Ditto
7516         static if (hasAssignableElements!RangeType)
7517         {
7518             void opIndexAssign(ElementType val, size_t n)
7519             {
7520                 import std.algorithm.mutation : move;
7521 
7522                 _input[n].front = move(val);
7523             }
7524         }
7525         mixin ImplementLength!_input;
7526 
7527 /**
7528    Slicing if offered if `RangeOfRanges` supports slicing and all the
7529    conditions for supporting indexing are met.
7530 */
7531         static if (hasSlicing!RangeOfRanges)
7532         {
7533             typeof(this) opSlice(size_t lower, size_t upper)
7534             {
7535                 return typeof(this)(_input[lower .. upper]);
7536             }
7537         }
7538     }
7539 
7540     auto opSlice() { return this; }
7541 
7542 private:
7543     RangeOfRanges _input;
7544 }
7545 
7546 /// Ditto
7547 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7548     TransverseOptions opt = TransverseOptions.assumeJagged,
7549     RangeOfRanges)
7550 (RangeOfRanges rr)
7551 {
7552     return typeof(return)(rr);
7553 }
7554 
7555 ///
7556 pure @safe nothrow unittest
7557 {
7558     import std.algorithm.comparison : equal;
7559     int[][] x = new int[][2];
7560     x[0] = [1, 2];
7561     x[1] = [3, 4];
7562     auto ror = frontTransversal(x);
7563     assert(equal(ror, [ 1, 3 ][]));
7564 }
7565 
7566 @safe unittest
7567 {
7568     import std.algorithm.comparison : equal;
7569     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7570 
7571     static assert(is(FrontTransversal!(immutable int[][])));
7572 
7573     foreach (DummyType; AllDummyRanges)
7574     {
7575         auto dummies =
7576             [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7577 
7578         foreach (i, ref elem; dummies)
7579         {
7580             // Just violate the DummyRange abstraction to get what I want.
7581             elem.arr = elem.arr[i..$ - (3 - i)];
7582         }
7583 
7584         auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7585         static if (isForwardRange!DummyType)
7586         {
7587             static assert(isForwardRange!(typeof(ft)));
7588         }
7589 
7590         assert(equal(ft, [1, 2, 3, 4]));
7591 
7592         // Test slicing.
7593         assert(equal(ft[0 .. 2], [1, 2]));
7594         assert(equal(ft[1 .. 3], [2, 3]));
7595 
7596         assert(ft.front == ft.moveFront());
7597         assert(ft.back == ft.moveBack());
7598         assert(ft.moveAt(1) == ft[1]);
7599 
7600 
7601         // Test infiniteness propagation.
7602         static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7603 
7604         static if (DummyType.r == ReturnBy.Reference)
7605         {
7606             {
7607                 ft.front++;
7608                 scope(exit) ft.front--;
7609                 assert(dummies.front.front == 2);
7610             }
7611 
7612             {
7613                 ft.front = 5;
7614                 scope(exit) ft.front = 1;
7615                 assert(dummies[0].front == 5);
7616             }
7617 
7618             {
7619                 ft.back = 88;
7620                 scope(exit) ft.back = 4;
7621                 assert(dummies.back.front == 88);
7622             }
7623 
7624             {
7625                 ft[1] = 99;
7626                 scope(exit) ft[1] = 2;
7627                 assert(dummies[1].front == 99);
7628             }
7629         }
7630     }
7631 }
7632 
7633 // https://issues.dlang.org/show_bug.cgi?id=16363
7634 pure @safe nothrow unittest
7635 {
7636     import std.algorithm.comparison : equal;
7637 
7638     int[][] darr = [[0, 1], [4, 5]];
7639     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7640 
7641     assert(equal(ft, [0, 4]));
7642     static assert(isRandomAccessRange!(typeof(ft)));
7643 }
7644 
7645 // https://issues.dlang.org/show_bug.cgi?id=16442
7646 pure @safe nothrow unittest
7647 {
7648     int[][] arr = [[], []];
7649 
7650     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7651     assert(ft.empty);
7652 }
7653 
7654 // ditto
7655 pure @safe unittest
7656 {
7657     int[][] arr = [[], []];
7658 
7659     auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7660     assert(ft.empty);
7661 }
7662 
7663 /**
7664     Given a range of ranges, iterate transversally through the
7665     `n`th element of each of the enclosed ranges. This function
7666     is similar to `unzip` in other languages.
7667 
7668     Params:
7669         opt = Controls the assumptions the function makes about the lengths
7670         of the ranges
7671         rr = An input range of random access ranges
7672     Returns:
7673         At minimum, an input range. Range primitives such as bidirectionality
7674         and random access are given if the element type of `rr` provides them.
7675 */
7676 struct Transversal(Ror,
7677         TransverseOptions opt = TransverseOptions.assumeJagged)
7678 {
7679     private alias RangeOfRanges = Unqual!Ror;
7680     private alias InnerRange = ElementType!RangeOfRanges;
7681     private alias E = ElementType!InnerRange;
7682 
7683     private void prime()
7684     {
7685         static if (opt == TransverseOptions.assumeJagged)
7686         {
7687             while (!_input.empty && _input.front.length <= _n)
7688             {
7689                 _input.popFront();
7690             }
7691             static if (isBidirectionalRange!RangeOfRanges)
7692             {
7693                 while (!_input.empty && _input.back.length <= _n)
7694                 {
7695                     _input.popBack();
7696                 }
7697             }
7698         }
7699     }
7700 
7701 /**
7702    Construction from an input and an index.
7703 */
7704     this(RangeOfRanges input, size_t n)
7705     {
7706         _input = input;
7707         _n = n;
7708         prime();
7709         static if (opt == TransverseOptions.enforceNotJagged)
7710         {
7711             import std.exception : enforce;
7712 
7713             if (empty) return;
7714             immutable commonLength = _input.front.length;
7715             foreach (e; _input)
7716             {
7717                 enforce(e.length == commonLength);
7718             }
7719         }
7720     }
7721 
7722 /**
7723    Forward range primitives.
7724 */
7725     static if (isInfinite!(RangeOfRanges))
7726     {
7727         enum bool empty = false;
7728     }
7729     else
7730     {
7731         @property bool empty()
7732         {
7733             return _input.empty;
7734         }
7735     }
7736 
7737     /// Ditto
7738     @property auto ref front()
7739     {
7740         assert(!empty, "Attempting to fetch the front of an empty Transversal");
7741         return _input.front[_n];
7742     }
7743 
7744     /// Ditto
7745     static if (hasMobileElements!InnerRange)
7746     {
7747         E moveFront()
7748         {
7749             return _input.front.moveAt(_n);
7750         }
7751     }
7752 
7753     /// Ditto
7754     static if (hasAssignableElements!InnerRange)
7755     {
7756         @property void front(E val)
7757         {
7758             _input.front[_n] = val;
7759         }
7760     }
7761 
7762 
7763     /// Ditto
7764     void popFront()
7765     {
7766         assert(!empty, "Attempting to popFront an empty Transversal");
7767         _input.popFront();
7768         prime();
7769     }
7770 
7771     /// Ditto
7772     static if (isForwardRange!RangeOfRanges)
7773     {
7774         @property typeof(this) save()
7775         {
7776             auto ret = this;
7777             ret._input = _input.save;
7778             return ret;
7779         }
7780     }
7781 
7782     static if (isBidirectionalRange!RangeOfRanges)
7783     {
7784 /**
7785    Bidirectional primitives. They are offered if $(D
7786    isBidirectionalRange!RangeOfRanges).
7787 */
7788         @property auto ref back()
7789         {
7790             assert(!empty, "Attempting to fetch the back of an empty Transversal");
7791             return _input.back[_n];
7792         }
7793 
7794         /// Ditto
7795         void popBack()
7796         {
7797             assert(!empty, "Attempting to popBack an empty Transversal");
7798             _input.popBack();
7799             prime();
7800         }
7801 
7802         /// Ditto
7803         static if (hasMobileElements!InnerRange)
7804         {
7805             E moveBack()
7806             {
7807                 return _input.back.moveAt(_n);
7808             }
7809         }
7810 
7811         /// Ditto
7812         static if (hasAssignableElements!InnerRange)
7813         {
7814             @property void back(E val)
7815             {
7816                 _input.back[_n] = val;
7817             }
7818         }
7819 
7820     }
7821 
7822     static if (isRandomAccessRange!RangeOfRanges &&
7823             (opt == TransverseOptions.assumeNotJagged ||
7824                     opt == TransverseOptions.enforceNotJagged))
7825     {
7826 /**
7827    Random-access primitive. It is offered if $(D
7828    isRandomAccessRange!RangeOfRanges && (opt ==
7829    TransverseOptions.assumeNotJagged || opt ==
7830    TransverseOptions.enforceNotJagged)).
7831 */
7832         auto ref opIndex(size_t n)
7833         {
7834             return _input[n][_n];
7835         }
7836 
7837         /// Ditto
7838         static if (hasMobileElements!InnerRange)
7839         {
7840             E moveAt(size_t n)
7841             {
7842                 return _input[n].moveAt(_n);
7843             }
7844         }
7845 
7846         /// Ditto
7847         static if (hasAssignableElements!InnerRange)
7848         {
7849             void opIndexAssign(E val, size_t n)
7850             {
7851                 _input[n][_n] = val;
7852             }
7853         }
7854 
7855         mixin ImplementLength!_input;
7856 
7857 /**
7858    Slicing if offered if `RangeOfRanges` supports slicing and all the
7859    conditions for supporting indexing are met.
7860 */
7861         static if (hasSlicing!RangeOfRanges)
7862         {
7863             typeof(this) opSlice(size_t lower, size_t upper)
7864             {
7865                 return typeof(this)(_input[lower .. upper], _n);
7866             }
7867         }
7868     }
7869 
7870     auto opSlice() { return this; }
7871 
7872 private:
7873     RangeOfRanges _input;
7874     size_t _n;
7875 }
7876 
7877 /// Ditto
7878 Transversal!(RangeOfRanges, opt) transversal
7879 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
7880 (RangeOfRanges rr, size_t n)
7881 {
7882     return typeof(return)(rr, n);
7883 }
7884 
7885 ///
7886 @safe unittest
7887 {
7888     import std.algorithm.comparison : equal;
7889     int[][] x = new int[][2];
7890     x[0] = [1, 2];
7891     x[1] = [3, 4];
7892     auto ror = transversal(x, 1);
7893     assert(equal(ror, [ 2, 4 ]));
7894 }
7895 
7896 /// The following code does a full unzip
7897 @safe unittest
7898 {
7899     import std.algorithm.comparison : equal;
7900     import std.algorithm.iteration : map;
7901     int[][] y = [[1, 2, 3], [4, 5, 6]];
7902     auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
7903     assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
7904 }
7905 
7906 @safe unittest
7907 {
7908     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
7909 
7910     int[][] x = new int[][2];
7911     x[0] = [ 1, 2 ];
7912     x[1] = [3, 4];
7913     auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
7914     auto witness = [ 2, 4 ];
7915     uint i;
7916     foreach (e; ror) assert(e == witness[i++]);
7917     assert(i == 2);
7918     assert(ror.length == 2);
7919 
7920     static assert(is(Transversal!(immutable int[][])));
7921 
7922     // Make sure ref, assign is being propagated.
7923     {
7924         ror.front++;
7925         scope(exit) ror.front--;
7926         assert(x[0][1] == 3);
7927     }
7928     {
7929         ror.front = 5;
7930         scope(exit) ror.front = 2;
7931         assert(x[0][1] == 5);
7932         assert(ror.moveFront() == 5);
7933     }
7934     {
7935         ror.back = 999;
7936         scope(exit) ror.back = 4;
7937         assert(x[1][1] == 999);
7938         assert(ror.moveBack() == 999);
7939     }
7940     {
7941         ror[0] = 999;
7942         scope(exit) ror[0] = 2;
7943         assert(x[0][1] == 999);
7944         assert(ror.moveAt(0) == 999);
7945     }
7946 
7947     // Test w/o ref return.
7948     alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
7949     auto drs = [D.init, D.init];
7950     foreach (num; 0 .. 10)
7951     {
7952         auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
7953         assert(t[0] == t[1]);
7954         assert(t[1] == num + 1);
7955     }
7956 
7957     static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
7958 
7959     // Test slicing.
7960     auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
7961     auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
7962     assert(mat1[0] == 6);
7963     assert(mat1[1] == 10);
7964 }
7965 
7966 struct Transposed(RangeOfRanges,
7967     TransverseOptions opt = TransverseOptions.assumeJagged)
7968 if (isForwardRange!RangeOfRanges &&
7969     isInputRange!(ElementType!RangeOfRanges) &&
7970     hasAssignableElements!RangeOfRanges)
7971 {
7972     this(RangeOfRanges input)
7973     {
7974         this._input = input;
7975         static if (opt == TransverseOptions.enforceNotJagged)
7976         {
7977             import std.exception : enforce;
7978 
7979             if (empty) return;
7980             immutable commonLength = _input.front.length;
7981             foreach (e; _input)
7982             {
7983                 enforce(e.length == commonLength);
7984             }
7985         }
7986     }
7987 
7988     @property auto front()
7989     {
7990         import std.algorithm.iteration : filter, map;
7991         return _input.save
7992                      .filter!(a => !a.empty)
7993                      .map!(a => a.front);
7994     }
7995 
7996     void popFront()
7997     {
7998         // Advance the position of each subrange.
7999         auto r = _input.save;
8000         while (!r.empty)
8001         {
8002             auto e = r.front;
8003             if (!e.empty)
8004             {
8005                 e.popFront();
8006                 r.front = e;
8007             }
8008 
8009             r.popFront();
8010         }
8011     }
8012 
8013     static if (isRandomAccessRange!(ElementType!RangeOfRanges))
8014     {
8015         auto ref opIndex(size_t n)
8016         {
8017             return transversal!opt(_input, n);
8018         }
8019     }
8020 
8021     @property bool empty()
8022     {
8023         if (_input.empty) return true;
8024         foreach (e; _input.save)
8025         {
8026             if (!e.empty) return false;
8027         }
8028         return true;
8029     }
8030 
8031     auto opSlice() { return this; }
8032 
8033 private:
8034     RangeOfRanges _input;
8035 }
8036 
8037 @safe unittest
8038 {
8039     // Boundary case: transpose of empty range should be empty
8040     int[][] ror = [];
8041     assert(transposed(ror).empty);
8042 }
8043 
8044 // https://issues.dlang.org/show_bug.cgi?id=9507
8045 @safe unittest
8046 {
8047     import std.algorithm.comparison : equal;
8048 
8049     auto r = [[1,2], [3], [4,5], [], [6]];
8050     assert(r.transposed.equal!equal([
8051         [1, 3, 4, 6],
8052         [2, 5]
8053     ]));
8054 }
8055 
8056 // https://issues.dlang.org/show_bug.cgi?id=17742
8057 @safe unittest
8058 {
8059     import std.algorithm.iteration : map;
8060     import std.algorithm.comparison : equal;
8061     auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
8062     assert(ror[3][2] == 6);
8063     auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
8064     assert(result[2][3] == 6);
8065 
8066     auto x = [[1,2,3],[4,5,6]];
8067     auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
8068     assert(y.front.equal([1,4]));
8069     assert(y[0].equal([1,4]));
8070     assert(y[0][0] == 1);
8071     assert(y[1].equal([2,5]));
8072     assert(y[1][1] == 5);
8073 
8074     auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
8075     assert(yy.front.equal([1,4]));
8076     assert(yy[0].equal([1,4]));
8077     assert(yy[0][0] == 1);
8078     assert(yy[1].equal([2,5]));
8079     assert(yy[1][1] == 5);
8080 
8081     auto z = x.transposed; // assumeJagged
8082     assert(z.front.equal([1,4]));
8083     assert(z[0].equal([1,4]));
8084     assert(!is(typeof(z[0][0])));
8085 }
8086 
8087 @safe unittest
8088 {
8089     import std.exception : assertThrown;
8090 
8091     auto r = [[1,2], [3], [4,5], [], [6]];
8092     assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
8093 }
8094 
8095 /**
8096 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
8097 contains the $(I i)'th elements of the original subranges.
8098 
8099 Params:
8100     opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
8101     rr = Range of ranges
8102  */
8103 Transposed!(RangeOfRanges, opt) transposed
8104 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8105 (RangeOfRanges rr)
8106 if (isForwardRange!RangeOfRanges &&
8107     isInputRange!(ElementType!RangeOfRanges) &&
8108     hasAssignableElements!RangeOfRanges)
8109 {
8110     return Transposed!(RangeOfRanges, opt)(rr);
8111 }
8112 
8113 ///
8114 @safe unittest
8115 {
8116     import std.algorithm.comparison : equal;
8117     int[][] ror = [
8118         [1, 2, 3],
8119         [4, 5, 6]
8120     ];
8121     auto xp = transposed(ror);
8122     assert(equal!"a.equal(b)"(xp, [
8123         [1, 4],
8124         [2, 5],
8125         [3, 6]
8126     ]));
8127 }
8128 
8129 ///
8130 @safe unittest
8131 {
8132     int[][] x = new int[][2];
8133     x[0] = [1, 2];
8134     x[1] = [3, 4];
8135     auto tr = transposed(x);
8136     int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
8137     uint i;
8138 
8139     foreach (e; tr)
8140     {
8141         assert(array(e) == witness[i++]);
8142     }
8143 }
8144 
8145 // https://issues.dlang.org/show_bug.cgi?id=8764
8146 @safe unittest
8147 {
8148     import std.algorithm.comparison : equal;
8149     ulong[] t0 = [ 123 ];
8150 
8151     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
8152     assert(!is(typeof(transposed(t0[].chunks(1)))));
8153     assert(is(typeof(transposed(t0[].chunks(1).array()))));
8154 
8155     auto t1 = transposed(t0[].chunks(1).array());
8156     assert(equal!"a.equal(b)"(t1, [[123]]));
8157 }
8158 
8159 /**
8160 This struct takes two ranges, `source` and `indices`, and creates a view
8161 of `source` as if its elements were reordered according to `indices`.
8162 `indices` may include only a subset of the elements of `source` and
8163 may also repeat elements.
8164 
8165 `Source` must be a random access range.  The returned range will be
8166 bidirectional or random-access if `Indices` is bidirectional or
8167 random-access, respectively.
8168 */
8169 struct Indexed(Source, Indices)
8170 if (isRandomAccessRange!Source && isInputRange!Indices &&
8171     is(typeof(Source.init[ElementType!(Indices).init])))
8172 {
8173     this(Source source, Indices indices)
8174     {
8175         this._source = source;
8176         this._indices = indices;
8177     }
8178 
8179     /// Range primitives
8180     @property auto ref front()
8181     {
8182         assert(!empty, "Attempting to fetch the front of an empty Indexed");
8183         return _source[_indices.front];
8184     }
8185 
8186     /// Ditto
8187     void popFront()
8188     {
8189         assert(!empty, "Attempting to popFront an empty Indexed");
8190         _indices.popFront();
8191     }
8192 
8193     static if (isInfinite!Indices)
8194     {
8195         enum bool empty = false;
8196     }
8197     else
8198     {
8199         /// Ditto
8200         @property bool empty()
8201         {
8202             return _indices.empty;
8203         }
8204     }
8205 
8206     static if (isForwardRange!Indices)
8207     {
8208         /// Ditto
8209         @property typeof(this) save()
8210         {
8211             // Don't need to save _source because it's never consumed.
8212             return typeof(this)(_source, _indices.save);
8213         }
8214     }
8215 
8216     /// Ditto
8217     static if (hasAssignableElements!Source)
8218     {
8219         @property auto ref front(ElementType!Source newVal)
8220         {
8221             assert(!empty);
8222             return _source[_indices.front] = newVal;
8223         }
8224     }
8225 
8226 
8227     static if (hasMobileElements!Source)
8228     {
8229         /// Ditto
8230         auto moveFront()
8231         {
8232             assert(!empty);
8233             return _source.moveAt(_indices.front);
8234         }
8235     }
8236 
8237     static if (isBidirectionalRange!Indices)
8238     {
8239         /// Ditto
8240         @property auto ref back()
8241         {
8242             assert(!empty, "Attempting to fetch the back of an empty Indexed");
8243             return _source[_indices.back];
8244         }
8245 
8246         /// Ditto
8247         void popBack()
8248         {
8249            assert(!empty, "Attempting to popBack an empty Indexed");
8250            _indices.popBack();
8251         }
8252 
8253         /// Ditto
8254         static if (hasAssignableElements!Source)
8255         {
8256             @property auto ref back(ElementType!Source newVal)
8257             {
8258                 assert(!empty);
8259                 return _source[_indices.back] = newVal;
8260             }
8261         }
8262 
8263 
8264         static if (hasMobileElements!Source)
8265         {
8266             /// Ditto
8267             auto moveBack()
8268             {
8269                 assert(!empty);
8270                 return _source.moveAt(_indices.back);
8271             }
8272         }
8273     }
8274 
8275     mixin ImplementLength!_indices;
8276 
8277     static if (isRandomAccessRange!Indices)
8278     {
8279         /// Ditto
8280         auto ref opIndex(size_t index)
8281         {
8282             return _source[_indices[index]];
8283         }
8284 
8285         static if (hasSlicing!Indices)
8286         {
8287             /// Ditto
8288             typeof(this) opSlice(size_t a, size_t b)
8289             {
8290                 return typeof(this)(_source, _indices[a .. b]);
8291             }
8292         }
8293 
8294 
8295         static if (hasAssignableElements!Source)
8296         {
8297             /// Ditto
8298             auto opIndexAssign(ElementType!Source newVal, size_t index)
8299             {
8300                 return _source[_indices[index]] = newVal;
8301             }
8302         }
8303 
8304 
8305         static if (hasMobileElements!Source)
8306         {
8307             /// Ditto
8308             auto moveAt(size_t index)
8309             {
8310                 return _source.moveAt(_indices[index]);
8311             }
8312         }
8313     }
8314 
8315     // All this stuff is useful if someone wants to index an Indexed
8316     // without adding a layer of indirection.
8317 
8318     /**
8319     Returns the source range.
8320     */
8321     @property Source source()
8322     {
8323         return _source;
8324     }
8325 
8326     /**
8327     Returns the indices range.
8328     */
8329      @property Indices indices()
8330     {
8331         return _indices;
8332     }
8333 
8334     static if (isRandomAccessRange!Indices)
8335     {
8336         /**
8337         Returns the physical index into the source range corresponding to a
8338         given logical index.  This is useful, for example, when indexing
8339         an `Indexed` without adding another layer of indirection.
8340         */
8341         size_t physicalIndex(size_t logicalIndex)
8342         {
8343             return _indices[logicalIndex];
8344         }
8345 
8346         ///
8347         @safe unittest
8348         {
8349             auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8350             assert(ind.physicalIndex(0) == 1);
8351         }
8352     }
8353 
8354 private:
8355     Source _source;
8356     Indices _indices;
8357 
8358 }
8359 
8360 /// Ditto
8361 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
8362 {
8363     return typeof(return)(source, indices);
8364 }
8365 
8366 ///
8367 @safe unittest
8368 {
8369     import std.algorithm.comparison : equal;
8370     auto source = [1, 2, 3, 4, 5];
8371     auto indices = [4, 3, 1, 2, 0, 4];
8372     auto ind = indexed(source, indices);
8373     assert(equal(ind, [5, 4, 2, 3, 1, 5]));
8374     assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
8375 }
8376 
8377 @safe unittest
8378 {
8379     {
8380         auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8381         assert(ind.physicalIndex(0) == 1);
8382     }
8383 
8384     auto source = [1, 2, 3, 4, 5];
8385     auto indices = [4, 3, 1, 2, 0, 4];
8386     auto ind = indexed(source, indices);
8387 
8388     // When elements of indices are duplicated and Source has lvalue elements,
8389     // these are aliased in ind.
8390     ind[0]++;
8391     assert(ind[0] == 6);
8392     assert(ind[5] == 6);
8393 }
8394 
8395 @safe unittest
8396 {
8397     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
8398         propagatesRangeType, RangeType;
8399 
8400     foreach (DummyType; AllDummyRanges)
8401     {
8402         auto d = DummyType.init;
8403         auto r = indexed([1, 2, 3, 4, 5], d);
8404         static assert(propagatesRangeType!(DummyType, typeof(r)));
8405         static assert(propagatesLength!(DummyType, typeof(r)));
8406     }
8407 }
8408 
8409 /**
8410 This range iterates over fixed-sized chunks of size `chunkSize` of a
8411 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8412 `chunkSize` must be greater than zero.
8413 
8414 If `!isInfinite!Source` and `source.walkLength` is not evenly
8415 divisible by `chunkSize`, the back element of this range will contain
8416 fewer than `chunkSize` elements.
8417 
8418 If `Source` is a forward range, the resulting range will be forward ranges as
8419 well. Otherwise, the resulting chunks will be input ranges consuming the same
8420 input: iterating over `front` will shrink the chunk such that subsequent
8421 invocations of `front` will no longer return the full chunk, and calling
8422 `popFront` on the outer range will invalidate any lingering references to
8423 previous values of `front`.
8424 
8425 Params:
8426     source = Range from which the chunks will be selected
8427     chunkSize = Chunk size
8428 
8429 See_Also: $(LREF slide)
8430 
8431 Returns: Range of chunks.
8432 */
8433 struct Chunks(Source)
8434 if (isInputRange!Source)
8435 {
8436     static if (isForwardRange!Source)
8437     {
8438         /// Standard constructor
8439         this(Source source, size_t chunkSize)
8440         {
8441             assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8442             _source = source;
8443             _chunkSize = chunkSize;
8444         }
8445 
8446         /// Input range primitives. Always present.
8447         @property auto front()
8448         {
8449             assert(!empty, "Attempting to fetch the front of an empty Chunks");
8450             return _source.save.take(_chunkSize);
8451         }
8452 
8453         /// Ditto
8454         void popFront()
8455         {
8456             assert(!empty, "Attempting to popFront and empty Chunks");
8457             _source.popFrontN(_chunkSize);
8458         }
8459 
8460         static if (!isInfinite!Source)
8461             /// Ditto
8462             @property bool empty()
8463             {
8464                 return _source.empty;
8465             }
8466         else
8467             // undocumented
8468             enum empty = false;
8469 
8470         /// Forward range primitives. Only present if `Source` is a forward range.
8471         @property typeof(this) save()
8472         {
8473             return typeof(this)(_source.save, _chunkSize);
8474         }
8475 
8476         static if (hasLength!Source)
8477         {
8478             /// Length. Only if `hasLength!Source` is `true`
8479             @property size_t length()
8480             {
8481                 // Note: _source.length + _chunkSize may actually overflow.
8482                 // We cast to ulong to mitigate the problem on x86 machines.
8483                 // For x64 machines, we just suppose we'll never overflow.
8484                 // The "safe" code would require either an extra branch, or a
8485                 //   modulo operation, which is too expensive for such a rare case
8486                 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8487             }
8488             //Note: No point in defining opDollar here without slicing.
8489             //opDollar is defined below in the hasSlicing!Source section
8490         }
8491 
8492         static if (hasSlicing!Source)
8493         {
8494             //Used for various purposes
8495             private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8496 
8497             /**
8498             Indexing and slicing operations. Provided only if
8499             `hasSlicing!Source` is `true`.
8500              */
8501             auto opIndex(size_t index)
8502             {
8503                 immutable start = index * _chunkSize;
8504                 immutable end   = start + _chunkSize;
8505 
8506                 static if (isInfinite!Source)
8507                     return _source[start .. end];
8508                 else
8509                 {
8510                     import std.algorithm.comparison : min;
8511                     immutable len = _source.length;
8512                     assert(start < len, "chunks index out of bounds");
8513                     return _source[start .. min(end, len)];
8514                 }
8515             }
8516 
8517             /// Ditto
8518             static if (hasLength!Source)
8519                 typeof(this) opSlice(size_t lower, size_t upper)
8520                 {
8521                     import std.algorithm.comparison : min;
8522                     assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8523                     immutable len = _source.length;
8524                     return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8525                 }
8526             else static if (hasSliceToEnd)
8527                 //For slicing an infinite chunk, we need to slice the source to the end.
8528                 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8529                 {
8530                     assert(lower <= upper, "chunks slicing index out of bounds");
8531                     return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8532                 }
8533 
8534             static if (isInfinite!Source)
8535             {
8536                 static if (hasSliceToEnd)
8537                 {
8538                     private static struct DollarToken{}
8539                     DollarToken opDollar()
8540                     {
8541                         return DollarToken();
8542                     }
8543                     //Slice to dollar
8544                     typeof(this) opSlice(size_t lower, DollarToken)
8545                     {
8546                         return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8547                     }
8548                 }
8549             }
8550             else
8551             {
8552                 //Dollar token carries a static type, with no extra information.
8553                 //It can lazily transform into _source.length on algorithmic
8554                 //operations such as : chunks[$/2, $-1];
8555                 private static struct DollarToken
8556                 {
8557                     Chunks!Source* mom;
8558                     @property size_t momLength()
8559                     {
8560                         return mom.length;
8561                     }
8562                     alias momLength this;
8563                 }
8564                 DollarToken opDollar()
8565                 {
8566                     return DollarToken(&this);
8567                 }
8568 
8569                 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8570                 //1. Evaluate chunks.length
8571                 //2. Multiply by _chunksSize
8572                 //3. To finally just compare it (with min) to the original length of source (!)
8573                 //These overloads avoid that.
8574                 typeof(this) opSlice(DollarToken, DollarToken)
8575                 {
8576                     static if (hasSliceToEnd)
8577                         return chunks(_source[$ .. $], _chunkSize);
8578                     else
8579                     {
8580                         immutable len = _source.length;
8581                         return chunks(_source[len .. len], _chunkSize);
8582                     }
8583                 }
8584                 typeof(this) opSlice(size_t lower, DollarToken)
8585                 {
8586                     import std.algorithm.comparison : min;
8587                     assert(lower <= length, "chunks slicing index out of bounds");
8588                     static if (hasSliceToEnd)
8589                         return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8590                     else
8591                     {
8592                         immutable len = _source.length;
8593                         return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8594                     }
8595                 }
8596                 typeof(this) opSlice(DollarToken, size_t upper)
8597                 {
8598                     assert(upper == length, "chunks slicing index out of bounds");
8599                     return this[$ .. $];
8600                 }
8601             }
8602         }
8603 
8604         //Bidirectional range primitives
8605         static if (hasSlicing!Source && hasLength!Source)
8606         {
8607             /**
8608             Bidirectional range primitives. Provided only if both
8609             `hasSlicing!Source` and `hasLength!Source` are `true`.
8610              */
8611             @property auto back()
8612             {
8613                 assert(!empty, "back called on empty chunks");
8614                 immutable len = _source.length;
8615                 immutable start = (len - 1) / _chunkSize * _chunkSize;
8616                 return _source[start .. len];
8617             }
8618 
8619             /// Ditto
8620             void popBack()
8621             {
8622                 assert(!empty, "popBack() called on empty chunks");
8623                 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8624                 _source = _source[0 .. end];
8625             }
8626         }
8627 
8628     private:
8629         Source _source;
8630         size_t _chunkSize;
8631     }
8632     else // is input range only
8633     {
8634         import std.typecons : RefCounted;
8635 
8636         static struct Chunk
8637         {
8638             private RefCounted!Impl impl;
8639 
8640             @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8641             @property auto front() { return impl.r.front; }
8642             void popFront()
8643             {
8644                 assert(impl.curSizeLeft > 0 && !impl.r.empty);
8645                 impl.curSizeLeft--;
8646                 impl.r.popFront();
8647             }
8648         }
8649 
8650         static struct Impl
8651         {
8652             private Source r;
8653             private size_t chunkSize;
8654             private size_t curSizeLeft;
8655         }
8656 
8657         private RefCounted!Impl impl;
8658 
8659         private this(Source r, size_t chunkSize)
8660         {
8661             impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8662         }
8663 
8664         @property bool empty() { return impl.chunkSize == 0; }
8665         @property Chunk front() return { return Chunk(impl); }
8666 
8667         void popFront()
8668         {
8669             impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8670             if (!impl.r.empty)
8671                 impl.curSizeLeft = impl.chunkSize;
8672             else
8673                 impl.chunkSize = 0;
8674         }
8675 
8676         static assert(isInputRange!(typeof(this)));
8677     }
8678 }
8679 
8680 /// Ditto
8681 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8682 if (isInputRange!Source)
8683 {
8684     return typeof(return)(source, chunkSize);
8685 }
8686 
8687 ///
8688 @safe unittest
8689 {
8690     import std.algorithm.comparison : equal;
8691     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8692     auto chunks = chunks(source, 4);
8693     assert(chunks[0] == [1, 2, 3, 4]);
8694     assert(chunks[1] == [5, 6, 7, 8]);
8695     assert(chunks[2] == [9, 10]);
8696     assert(chunks.back == chunks[2]);
8697     assert(chunks.front == chunks[0]);
8698     assert(chunks.length == 3);
8699     assert(equal(retro(array(chunks)), array(retro(chunks))));
8700 }
8701 
8702 /// Non-forward input ranges are supported, but with limited semantics.
8703 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8704 {
8705     import std.algorithm.comparison : equal;
8706 
8707     int i;
8708 
8709     // The generator doesn't save state, so it cannot be a forward range.
8710     auto inputRange = generate!(() => ++i).take(10);
8711 
8712     // We can still process it in chunks, but it will be single-pass only.
8713     auto chunked = inputRange.chunks(2);
8714 
8715     assert(chunked.front.equal([1, 2]));
8716     assert(chunked.front.empty); // Iterating the chunk has consumed it
8717     chunked.popFront;
8718     assert(chunked.front.equal([3, 4]));
8719 }
8720 
8721 @system /*@safe*/ unittest
8722 {
8723     import std.algorithm.comparison : equal;
8724     import std.internal.test.dummyrange : ReferenceInputRange;
8725 
8726     auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
8727     auto r = new ReferenceInputRange!int(data).chunks(3);
8728     assert(r.equal!equal([
8729         [ 1, 2, 3 ],
8730         [ 4, 5, 6 ],
8731         [ 7, 8, 9 ],
8732         [ 10 ]
8733     ]));
8734 
8735     auto data2 = [ 1, 2, 3, 4, 5, 6 ];
8736     auto r2 = new ReferenceInputRange!int(data2).chunks(3);
8737     assert(r2.equal!equal([
8738         [ 1, 2, 3 ],
8739         [ 4, 5, 6 ]
8740     ]));
8741 
8742     auto data3 = [ 1, 2, 3, 4, 5 ];
8743     auto r3 = new ReferenceInputRange!int(data3).chunks(2);
8744     assert(r3.front.equal([1, 2]));
8745     r3.popFront();
8746     assert(!r3.empty);
8747     r3.popFront();
8748     assert(r3.front.equal([5]));
8749 }
8750 
8751 @safe unittest
8752 {
8753     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8754     auto chunks = chunks(source, 4);
8755     auto chunks2 = chunks.save;
8756     chunks.popFront();
8757     assert(chunks[0] == [5, 6, 7, 8]);
8758     assert(chunks[1] == [9, 10]);
8759     chunks2.popBack();
8760     assert(chunks2[1] == [5, 6, 7, 8]);
8761     assert(chunks2.length == 2);
8762 
8763     static assert(isRandomAccessRange!(typeof(chunks)));
8764 }
8765 
8766 @safe unittest
8767 {
8768     import std.algorithm.comparison : equal;
8769 
8770     //Extra toying with slicing and indexing.
8771     auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
8772     auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
8773 
8774     assert(chunks1.length == 5);
8775     assert(chunks2.length == 5);
8776     assert(chunks1[4] == [4]);
8777     assert(chunks2[4] == [4, 4]);
8778     assert(chunks1.back == [4]);
8779     assert(chunks2.back == [4, 4]);
8780 
8781     assert(chunks1[0 .. 1].equal([[0, 0]]));
8782     assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
8783     assert(chunks1[4 .. 5].equal([[4]]));
8784     assert(chunks2[4 .. 5].equal([[4, 4]]));
8785 
8786     assert(chunks1[0 .. 0].equal((int[][]).init));
8787     assert(chunks1[5 .. 5].equal((int[][]).init));
8788     assert(chunks2[5 .. 5].equal((int[][]).init));
8789 
8790     //Fun with opDollar
8791     assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
8792     assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
8793     assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
8794     assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
8795     assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
8796     assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
8797 
8798     assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
8799 }
8800 
8801 @safe unittest
8802 {
8803     import std.algorithm.comparison : equal;
8804     import std.algorithm.iteration : filter;
8805 
8806     //ForwardRange
8807     auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
8808     assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
8809 
8810     //InfiniteRange w/o RA
8811     auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
8812     assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
8813 
8814     //InfiniteRange w/ RA and slicing
8815     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
8816     auto oddsByPairs = odds.chunks(2);
8817     assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
8818 
8819     //Requires phobos#991 for Sequence to have slice to end
8820     static assert(hasSlicing!(typeof(odds)));
8821     assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
8822     assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
8823 }
8824 
8825 
8826 
8827 /**
8828 This range splits a `source` range into `chunkCount` chunks of
8829 approximately equal length. `Source` must be a forward range with
8830 known length.
8831 
8832 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
8833 The returned range will contain zero or more $(D source.length /
8834 chunkCount + 1) elements followed by $(D source.length / chunkCount)
8835 elements. If $(D source.length < chunkCount), some chunks will be empty.
8836 
8837 `chunkCount` must not be zero, unless `source` is also empty.
8838 */
8839 struct EvenChunks(Source)
8840 if (isForwardRange!Source && hasLength!Source)
8841 {
8842     /// Standard constructor
8843     this(Source source, size_t chunkCount)
8844     {
8845         assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
8846         _source = source;
8847         _chunkCount = chunkCount;
8848     }
8849 
8850     /// Forward range primitives. Always present.
8851     @property auto front()
8852     {
8853         assert(!empty, "Attempting to fetch the front of an empty evenChunks");
8854         return _source.save.take(_chunkPos(1));
8855     }
8856 
8857     /// Ditto
8858     void popFront()
8859     {
8860         assert(!empty, "Attempting to popFront an empty evenChunks");
8861         _source.popFrontN(_chunkPos(1));
8862         _chunkCount--;
8863     }
8864 
8865     /// Ditto
8866     @property bool empty()
8867     {
8868         return _chunkCount == 0;
8869     }
8870 
8871     /// Ditto
8872     @property typeof(this) save()
8873     {
8874         return typeof(this)(_source.save, _chunkCount);
8875     }
8876 
8877     /// Length
8878     @property size_t length() const
8879     {
8880         return _chunkCount;
8881     }
8882     //Note: No point in defining opDollar here without slicing.
8883     //opDollar is defined below in the hasSlicing!Source section
8884 
8885     static if (hasSlicing!Source)
8886     {
8887         /**
8888         Indexing, slicing and bidirectional operations and range primitives.
8889         Provided only if `hasSlicing!Source` is `true`.
8890          */
8891         auto opIndex(size_t index)
8892         {
8893             assert(index < _chunkCount, "evenChunks index out of bounds");
8894             return _source[_chunkPos(index) .. _chunkPos(index+1)];
8895         }
8896 
8897         /// Ditto
8898         typeof(this) opSlice(size_t lower, size_t upper)
8899         {
8900             assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
8901             return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
8902         }
8903 
8904         /// Ditto
8905         @property auto back()
8906         {
8907             assert(!empty, "back called on empty evenChunks");
8908             return _source[_chunkPos(_chunkCount - 1) .. _source.length];
8909         }
8910 
8911         /// Ditto
8912         void popBack()
8913         {
8914             assert(!empty, "popBack() called on empty evenChunks");
8915             _source = _source[0 .. _chunkPos(_chunkCount - 1)];
8916             _chunkCount--;
8917         }
8918     }
8919 
8920 private:
8921     Source _source;
8922     size_t _chunkCount;
8923 
8924     size_t _chunkPos(size_t i)
8925     {
8926         /*
8927             _chunkCount = 5, _source.length = 13:
8928 
8929                chunk0
8930                  |   chunk3
8931                  |     |
8932                  v     v
8933                 +-+-+-+-+-+   ^
8934                 |0|3|.| | |   |
8935                 +-+-+-+-+-+   | div
8936                 |1|4|.| | |   |
8937                 +-+-+-+-+-+   v
8938                 |2|5|.|
8939                 +-+-+-+
8940 
8941                 <----->
8942                   mod
8943 
8944                 <--------->
8945                 _chunkCount
8946 
8947             One column is one chunk.
8948             popFront and popBack pop the left-most
8949             and right-most column, respectively.
8950         */
8951 
8952         auto div = _source.length / _chunkCount;
8953         auto mod = _source.length % _chunkCount;
8954         auto pos = i <= mod
8955             ? i   * (div+1)
8956             : mod * (div+1) + (i-mod) * div
8957         ;
8958         //auto len = i < mod
8959         //    ? div+1
8960         //    : div
8961         //;
8962         return pos;
8963     }
8964 }
8965 
8966 /// Ditto
8967 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
8968 if (isForwardRange!Source && hasLength!Source)
8969 {
8970     return typeof(return)(source, chunkCount);
8971 }
8972 
8973 ///
8974 @safe unittest
8975 {
8976     import std.algorithm.comparison : equal;
8977     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8978     auto chunks = evenChunks(source, 3);
8979     assert(chunks[0] == [1, 2, 3, 4]);
8980     assert(chunks[1] == [5, 6, 7]);
8981     assert(chunks[2] == [8, 9, 10]);
8982 }
8983 
8984 @safe unittest
8985 {
8986     import std.algorithm.comparison : equal;
8987 
8988     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8989     auto chunks = evenChunks(source, 3);
8990     assert(chunks.back == chunks[2]);
8991     assert(chunks.front == chunks[0]);
8992     assert(chunks.length == 3);
8993     assert(equal(retro(array(chunks)), array(retro(chunks))));
8994 
8995     auto chunks2 = chunks.save;
8996     chunks.popFront();
8997     assert(chunks[0] == [5, 6, 7]);
8998     assert(chunks[1] == [8, 9, 10]);
8999     chunks2.popBack();
9000     assert(chunks2[1] == [5, 6, 7]);
9001     assert(chunks2.length == 2);
9002 
9003     static assert(isRandomAccessRange!(typeof(chunks)));
9004 }
9005 
9006 @safe unittest
9007 {
9008     import std.algorithm.comparison : equal;
9009 
9010     int[] source = [];
9011     auto chunks = source.evenChunks(0);
9012     assert(chunks.length == 0);
9013     chunks = source.evenChunks(3);
9014     assert(equal(chunks, [[], [], []]));
9015     chunks = [1, 2, 3].evenChunks(5);
9016     assert(equal(chunks, [[1], [2], [3], [], []]));
9017 }
9018 
9019 /**
9020 A fixed-sized sliding window iteration
9021 of size `windowSize` over a `source` range by a custom `stepSize`.
9022 
9023 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
9024 and the `windowSize` must be greater than zero.
9025 
9026 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
9027 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
9028 
9029 Params:
9030     f = Whether the last element has fewer elements than `windowSize`
9031         it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
9032     source = Range from which the slide will be selected
9033     windowSize = Sliding window size
9034     stepSize = Steps between the windows (by default 1)
9035 
9036 Returns: Range of all sliding windows with propagated bi-directionality,
9037          forwarding, random access, and slicing.
9038 
9039 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
9040       is only available when $(REF hasSlicing, std,range,primitives)
9041       and $(REF hasLength, std,range,primitives) are true.
9042 
9043 See_Also: $(LREF chunks)
9044 */
9045 auto slide(Flag!"withPartial" f = Yes.withPartial,
9046             Source)(Source source, size_t windowSize, size_t stepSize = 1)
9047 if (isForwardRange!Source)
9048 {
9049     return Slides!(f, Source)(source, windowSize, stepSize);
9050 }
9051 
9052 /// Iterate over ranges with windows
9053 @safe pure nothrow unittest
9054 {
9055     import std.algorithm.comparison : equal;
9056 
9057     assert([0, 1, 2, 3].slide(2).equal!equal(
9058         [[0, 1], [1, 2], [2, 3]]
9059     ));
9060 
9061     assert(5.iota.slide(3).equal!equal(
9062         [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
9063     ));
9064 }
9065 
9066 /// set a custom stepsize (default 1)
9067 @safe pure nothrow unittest
9068 {
9069     import std.algorithm.comparison : equal;
9070 
9071     assert(6.iota.slide(1, 2).equal!equal(
9072         [[0], [2], [4]]
9073     ));
9074 
9075     assert(6.iota.slide(2, 4).equal!equal(
9076         [[0, 1], [4, 5]]
9077     ));
9078 
9079     assert(iota(7).slide(2, 2).equal!equal(
9080         [[0, 1], [2, 3], [4, 5], [6]]
9081     ));
9082 
9083     assert(iota(12).slide(2, 4).equal!equal(
9084         [[0, 1], [4, 5], [8, 9]]
9085     ));
9086 }
9087 
9088 /// Allow the last slide to have fewer elements than windowSize
9089 @safe pure nothrow unittest
9090 {
9091     import std.algorithm.comparison : equal;
9092 
9093     assert(3.iota.slide!(No.withPartial)(4).empty);
9094     assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
9095         [[0, 1, 2]]
9096     ));
9097 }
9098 
9099 /// Count all the possible substrings of length 2
9100 @safe pure nothrow unittest
9101 {
9102     import std.algorithm.iteration : each;
9103 
9104     int[dstring] d;
9105     "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
9106     assert(d == ["AG"d: 2, "GA"d: 2]);
9107 }
9108 
9109 /// withPartial only has an effect if last element in the range doesn't have the full size
9110 @safe pure nothrow unittest
9111 {
9112     import std.algorithm.comparison : equal;
9113 
9114     assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
9115     assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
9116     assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9117 
9118     assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9119     assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9120     assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9121 }
9122 
9123 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
9124 if (isForwardRange!Source)
9125 {
9126 private:
9127     Source source;
9128     size_t windowSize;
9129     size_t stepSize;
9130 
9131     static if (hasLength!Source)
9132     {
9133         enum needsEndTracker = false;
9134     }
9135     else
9136     {
9137         // If there's no information about the length, track needs to be kept manually
9138         Source nextSource;
9139         enum needsEndTracker = true;
9140     }
9141 
9142     bool _empty;
9143 
9144     static if (hasSlicing!Source)
9145         enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
9146 
9147     static if (withPartial)
9148         bool hasShownPartialBefore;
9149 
9150 public:
9151     /// Standard constructor
9152     this(Source source, size_t windowSize, size_t stepSize)
9153     {
9154         assert(windowSize > 0, "windowSize must be greater than zero");
9155         assert(stepSize > 0, "stepSize must be greater than zero");
9156         this.source = source;
9157         this.windowSize = windowSize;
9158         this.stepSize = stepSize;
9159 
9160         static if (needsEndTracker)
9161         {
9162             // `nextSource` is used to "look one step into the future" and check for the end
9163             // this means `nextSource` is advanced by `stepSize` on every `popFront`
9164             nextSource = source.save;
9165             auto poppedElems = nextSource.popFrontN(windowSize);
9166         }
9167 
9168         if (source.empty)
9169         {
9170             _empty = true;
9171             return;
9172         }
9173 
9174         static if (withPartial)
9175         {
9176             static if (needsEndTracker)
9177             {
9178                 if (nextSource.empty)
9179                     hasShownPartialBefore = true;
9180             }
9181             else
9182             {
9183                 if (source.length <= windowSize)
9184                     hasShownPartialBefore = true;
9185             }
9186         }
9187         else
9188         {
9189             // empty source range is needed, s.t. length, slicing etc. works properly
9190             static if (needsEndTracker)
9191             {
9192                 if (poppedElems < windowSize)
9193                      _empty = true;
9194             }
9195             else
9196             {
9197                 if (source.length < windowSize)
9198                      _empty = true;
9199             }
9200         }
9201     }
9202 
9203     /// Forward range primitives. Always present.
9204     @property auto front()
9205     {
9206         assert(!empty, "Attempting to access front on an empty slide.");
9207         static if (hasSlicing!Source && hasLength!Source)
9208         {
9209             static if (withPartial)
9210             {
9211                 import std.algorithm.comparison : min;
9212                 return source[0 .. min(windowSize, source.length)];
9213             }
9214             else
9215             {
9216                 assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
9217                 return source[0 .. windowSize];
9218             }
9219         }
9220         else
9221         {
9222             static if (withPartial)
9223                 return source.save.take(windowSize);
9224             else
9225                 return source.save.takeExactly(windowSize);
9226         }
9227     }
9228 
9229     /// Ditto
9230     void popFront()
9231     {
9232         assert(!empty, "Attempting to call popFront() on an empty slide.");
9233         source.popFrontN(stepSize);
9234 
9235         if (source.empty)
9236         {
9237             _empty = true;
9238             return;
9239         }
9240 
9241         static if (withPartial)
9242         {
9243             if (hasShownPartialBefore)
9244                 _empty = true;
9245         }
9246 
9247         static if (needsEndTracker)
9248         {
9249             // Check the upcoming slide
9250             auto poppedElements = nextSource.popFrontN(stepSize);
9251             static if (withPartial)
9252             {
9253                 if (poppedElements < stepSize || nextSource.empty)
9254                     hasShownPartialBefore = true;
9255             }
9256             else
9257             {
9258                 if (poppedElements < stepSize)
9259                     _empty = true;
9260             }
9261         }
9262         else
9263         {
9264             static if (withPartial)
9265             {
9266                 if (source.length <= windowSize)
9267                     hasShownPartialBefore = true;
9268             }
9269             else
9270             {
9271                 if (source.length < windowSize)
9272                     _empty = true;
9273             }
9274         }
9275     }
9276 
9277     static if (!isInfinite!Source)
9278     {
9279         /// Ditto
9280         @property bool empty() const
9281         {
9282             return _empty;
9283         }
9284     }
9285     else
9286     {
9287         // undocumented
9288         enum empty = false;
9289     }
9290 
9291     /// Ditto
9292     @property typeof(this) save()
9293     {
9294         return typeof(this)(source.save, windowSize, stepSize);
9295     }
9296 
9297     static if (hasLength!Source)
9298     {
9299         // gaps between the last element and the end of the range
9300         private size_t gap()
9301         {
9302             /*
9303             * Note:
9304             * - In the following `end` is the exclusive end as used in opSlice
9305             * - For the trivial case with `stepSize = 1`  `end` is at `len`:
9306             *
9307             *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]]    (end = 4)
9308             *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]      (end = 4)
9309             *
9310             * - For the non-trivial cases, we need to calculate the gap
9311             *   between `len` and `end` - this is the number of missing elements
9312             *   from the input range:
9313             *
9314             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
9315             *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
9316             *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
9317             *
9318             *   As it can be seen `gap` can be at most `stepSize - 1`
9319             *   More generally the elements of the sliding window with
9320             *   `w = windowSize` and `s = stepSize` are:
9321             *
9322             *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
9323             *
9324             *  We can thus calculate the gap between the `end` and `len` as:
9325             *
9326             *     gap = len - (n * s + w) = len - w - (n * s)
9327             *
9328             *  As we aren't interested in exact value of `n`, but the best
9329             *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
9330             *
9331             *     gap = len - w - (s - s ... - s) = (len - w) % s
9332             *
9333             *  So for example:
9334             *
9335             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
9336             *      gap: (7 - 2) % 3 = 5 % 3 = 2
9337             *      end: 7 - 2 = 5
9338             *
9339             *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
9340             *      gap: (7 - 4) % 2 = 3 % 2 = 1
9341             *      end: 7 - 1 = 6
9342             */
9343             return (source.length - windowSize)  % stepSize;
9344         }
9345 
9346         private size_t numberOfFullFrames()
9347         {
9348             /**
9349             5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9350             7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (3)
9351             7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (2)
9352             6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5]         (2)
9353             7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (2)
9354 
9355             As the last window is only added iff its complete,
9356             we don't count the last window except if it's full due to integer rounding.
9357             */
9358             return 1 + (source.length - windowSize) / stepSize;
9359         }
9360 
9361         // Whether the last slide frame size is less than windowSize
9362         private bool hasPartialElements()
9363         {
9364             static if (withPartial)
9365                 return gap != 0 && source.length > numberOfFullFrames * stepSize;
9366             else
9367                 return 0;
9368         }
9369 
9370         /// Length. Only if `hasLength!Source` is `true`
9371         @property size_t length()
9372         {
9373             if (source.length < windowSize)
9374             {
9375                 static if (withPartial)
9376                     return source.length > 0;
9377                 else
9378                     return 0;
9379             }
9380             else
9381             {
9382                 /***
9383                   We bump the pointer by stepSize for every element.
9384                   If withPartial, we don't count the last element if its size
9385                   isn't windowSize
9386 
9387                   At most:
9388                       [p, p + stepSize, ..., p + stepSize * n]
9389 
9390                 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
9391                 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (4)
9392                 7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (3)
9393                 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6]      (3)
9394                 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (3)
9395                 */
9396                 return numberOfFullFrames + hasPartialElements;
9397             }
9398         }
9399     }
9400 
9401     static if (hasSlicing!Source)
9402     {
9403         /**
9404         Indexing and slicing operations. Provided only if
9405         `hasSlicing!Source` is `true`.
9406          */
9407         auto opIndex(size_t index)
9408         {
9409             immutable start = index * stepSize;
9410 
9411             static if (isInfinite!Source)
9412             {
9413                 immutable end = start + windowSize;
9414             }
9415             else
9416             {
9417                 import std.algorithm.comparison : min;
9418 
9419                 immutable len = source.length;
9420                 assert(start < len, "slide index out of bounds");
9421                 immutable end = min(start + windowSize, len);
9422             }
9423 
9424             return source[start .. end];
9425         }
9426 
9427         static if (!isInfinite!Source)
9428         {
9429             /// ditto
9430             typeof(this) opSlice(size_t lower, size_t upper)
9431             {
9432                 import std.algorithm.comparison : min;
9433 
9434                 assert(upper <= length, "slide slicing index out of bounds");
9435                 assert(lower <= upper, "slide slicing index out of bounds");
9436 
9437                 lower *= stepSize;
9438                 upper *= stepSize;
9439 
9440                 immutable len = source.length;
9441 
9442                 static if (withPartial)
9443                 {
9444                     import std.algorithm.comparison : max;
9445 
9446                     if (lower == upper)
9447                         return this[$ .. $];
9448 
9449                     /*
9450                     A) If `stepSize` >= `windowSize` => `rightPos = upper`
9451 
9452                        [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9453                          rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9454                          6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9455 
9456                     B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9457 
9458                        [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9459                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9460                          1.iota.slide(2) = [[0]]
9461 
9462                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9463                          1.iota.slide(2) = [[0, 1]]
9464 
9465                        More complex:
9466 
9467                        20.iota.slide(7, 6)[0 .. 2]
9468                          rightPos: (upper=2) * (stepSize=6) = 12.iota
9469                          12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9470 
9471                        Now we add up for the difference between `windowSize` and `stepSize`:
9472 
9473                          rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9474                          13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9475                     */
9476                     immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9477                 }
9478                 else
9479                 {
9480                     /*
9481                     After we have normalized `lower` and `upper` by `stepSize`,
9482                     we only need to look at the case of `stepSize=1`.
9483                     As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9484                     Notice that starting from `upper`,
9485                     we only need to move for `windowSize - 1` to the right:
9486 
9487                       - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9488                         rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9489 
9490                       - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9491                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9492 
9493                       - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9494                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9495                     */
9496                     immutable rightPos = min(upper + windowSize - 1, len);
9497                 }
9498 
9499                 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9500             }
9501         }
9502         else static if (hasSliceToEnd)
9503         {
9504             // For slicing an infinite chunk, we need to slice the source to the infinite end.
9505             auto opSlice(size_t lower, size_t upper)
9506             {
9507                 assert(lower <= upper, "slide slicing index out of bounds");
9508                 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9509                                     .takeExactly(upper - lower);
9510             }
9511         }
9512 
9513         static if (isInfinite!Source)
9514         {
9515             static if (hasSliceToEnd)
9516             {
9517                 private static struct DollarToken{}
9518                 DollarToken opDollar()
9519                 {
9520                     return DollarToken();
9521                 }
9522                 //Slice to dollar
9523                 typeof(this) opSlice(size_t lower, DollarToken)
9524                 {
9525                     return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9526                 }
9527             }
9528         }
9529         else
9530         {
9531             // Dollar token carries a static type, with no extra information.
9532             // It can lazily transform into source.length on algorithmic
9533             // operations such as : slide[$/2, $-1];
9534             private static struct DollarToken
9535             {
9536                 private size_t _length;
9537                 alias _length this;
9538             }
9539 
9540             DollarToken opDollar()
9541             {
9542                 return DollarToken(this.length);
9543             }
9544 
9545             // Optimized slice overloads optimized for using dollar.
9546             typeof(this) opSlice(DollarToken, DollarToken)
9547             {
9548                 static if (hasSliceToEnd)
9549                 {
9550                     return typeof(this)(source[$ .. $], windowSize, stepSize);
9551                 }
9552                 else
9553                 {
9554                     immutable len = source.length;
9555                     return typeof(this)(source[len .. len], windowSize, stepSize);
9556                 }
9557             }
9558 
9559             // Optimized slice overloads optimized for using dollar.
9560             typeof(this) opSlice(size_t lower, DollarToken)
9561             {
9562                 import std.algorithm.comparison : min;
9563                 assert(lower <= length, "slide slicing index out of bounds");
9564                 lower *= stepSize;
9565                 static if (hasSliceToEnd)
9566                 {
9567                     return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9568                 }
9569                 else
9570                 {
9571                     immutable len = source.length;
9572                     return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9573                 }
9574             }
9575 
9576             // Optimized slice overloads optimized for using dollar.
9577             typeof(this) opSlice(DollarToken, size_t upper)
9578             {
9579                 assert(upper == length, "slide slicing index out of bounds");
9580                 return this[$ .. $];
9581             }
9582         }
9583 
9584         // Bidirectional range primitives
9585         static if (!isInfinite!Source)
9586         {
9587             /**
9588             Bidirectional range primitives. Provided only if both
9589             `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9590              */
9591             @property auto back()
9592             {
9593                 import std.algorithm.comparison : max;
9594 
9595                 assert(!empty, "Attempting to access front on an empty slide");
9596 
9597                 immutable len = source.length;
9598 
9599                 static if (withPartial)
9600                 {
9601                     if (source.length <= windowSize)
9602                         return source[0 .. source.length];
9603 
9604                     if (hasPartialElements)
9605                         return source[numberOfFullFrames * stepSize .. len];
9606                 }
9607 
9608                 // check for underflow
9609                 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9610                 return source[start .. len - gap];
9611             }
9612 
9613             /// Ditto
9614             void popBack()
9615             {
9616                 assert(!empty, "Attempting to call popBack() on an empty slide");
9617 
9618                 // Move by stepSize
9619                 immutable end = source.length > stepSize ? source.length - stepSize : 0;
9620 
9621                 static if (withPartial)
9622                 {
9623                     if (hasShownPartialBefore || source.empty)
9624                     {
9625                         _empty = true;
9626                         return;
9627                     }
9628 
9629                     // pop by stepSize, except for the partial frame at the end
9630                     if (hasPartialElements)
9631                         source = source[0 .. source.length - gap];
9632                     else
9633                         source = source[0 .. end];
9634                 }
9635                 else
9636                 {
9637                     source = source[0 .. end];
9638                 }
9639 
9640                 if (source.length < windowSize)
9641                     _empty = true;
9642             }
9643         }
9644     }
9645 }
9646 
9647 // test @nogc
9648 @safe pure nothrow @nogc unittest
9649 {
9650     import std.algorithm.comparison : equal;
9651 
9652     static immutable res1 = [[0], [1], [2], [3]];
9653     assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9654 
9655     static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9656     assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9657 }
9658 
9659 // test different window sizes
9660 @safe pure nothrow unittest
9661 {
9662     import std.array : array;
9663     import std.algorithm.comparison : equal;
9664 
9665     assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9666     assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9667     assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9668     assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9669     assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9670     assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9671 
9672     assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9673     assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9674     assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9675     assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9676     assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9677     assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9678     assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9679 }
9680 
9681 // test combinations
9682 @safe pure nothrow unittest
9683 {
9684     import std.algorithm.comparison : equal;
9685     import std.typecons : tuple;
9686 
9687     alias t = tuple;
9688     auto list = [
9689         t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9690         t(t(1, 2), [[0], [2], [4]]),
9691         t(t(1, 3), [[0], [3]]),
9692         t(t(1, 4), [[0], [4]]),
9693         t(t(1, 5), [[0], [5]]),
9694         t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9695         t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9696         t(t(2, 3), [[0, 1], [3, 4]]),
9697         t(t(2, 4), [[0, 1], [4, 5]]),
9698         t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9699         t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9700         t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9701         t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9702         t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9703     ];
9704 
9705     static foreach (Partial; [Yes.withPartial, No.withPartial])
9706         foreach (e; list)
9707             assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9708 
9709     auto listSpecial = [
9710         t(t(2, 5), [[0, 1], [5]]),
9711         t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9712         t(t(3, 4), [[0, 1, 2], [4, 5]]),
9713         t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9714         t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9715         t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9716     ];
9717     foreach (e; listSpecial)
9718     {
9719         assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
9720         assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
9721     }
9722 }
9723 
9724 // test emptiness and copyability
9725 @safe pure nothrow unittest
9726 {
9727     import std.algorithm.comparison : equal;
9728     import std.algorithm.iteration : map;
9729 
9730     // check with empty input
9731     int[] d;
9732     assert(d.slide!(Yes.withPartial)(2).empty);
9733     assert(d.slide!(Yes.withPartial)(2, 2).empty);
9734 
9735     // is copyable?
9736     auto e = iota(5).slide!(Yes.withPartial)(2);
9737     e.popFront;
9738     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9739     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9740     assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
9741 }
9742 
9743 // test with strings
9744 @safe pure nothrow unittest
9745 {
9746     import std.algorithm.iteration : each;
9747 
9748     int[dstring] f;
9749     "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
9750     assert(f == ["AGA"d: 2, "GAG"d: 1]);
9751 
9752     int[dstring] g;
9753     "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
9754     assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
9755     g = null;
9756     "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
9757     assert(g == ["ABC"d:1, "DEF"d:1]);
9758 }
9759 
9760 // test with utf8 strings
9761 @safe unittest
9762 {
9763     import std.stdio;
9764     import std.algorithm.comparison : equal;
9765 
9766     assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."]));
9767     assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"]));
9768 
9769     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
9770     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
9771     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]);
9772     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]);
9773 }
9774 
9775 // test length
9776 @safe pure nothrow unittest
9777 {
9778     // Slides with fewer elements are empty or 1 for Yes.withPartial
9779     static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
9780     {{
9781         assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
9782         assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
9783         assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
9784     }}
9785 
9786     static immutable list = [
9787     //  iota   slide    expected
9788         [4,    2, 1,     3, 3],
9789         [5,    3, 1,     3, 3],
9790         [7,    2, 2,     4, 3],
9791         [12,   2, 4,     3, 3],
9792         [6,    1, 2,     3, 3],
9793         [6,    2, 4,     2, 2],
9794         [3,    2, 4,     1, 1],
9795         [5,    2, 1,     4, 4],
9796         [7,    2, 2,     4, 3],
9797         [7,    2, 3,     3, 2],
9798         [7,    3, 2,     3, 3],
9799         [7,    3, 3,     3, 2],
9800     ];
9801     foreach (e; list)
9802     {
9803         assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
9804         assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
9805     }
9806 }
9807 
9808 // test index and slicing
9809 @safe pure nothrow unittest
9810 {
9811     import std.algorithm.comparison : equal;
9812     import std.array : array;
9813 
9814     static foreach (Partial; [Yes.withPartial, No.withPartial])
9815     {
9816         foreach (s; [5, 7, 10, 15, 20])
9817         foreach (windowSize; 1 .. 10)
9818         foreach (stepSize; 1 .. 10)
9819         {
9820             auto r = s.iota.slide!Partial(windowSize, stepSize);
9821             auto arr = r.array;
9822             assert(r.length == arr.length);
9823 
9824             // test indexing
9825             foreach (i; 0 .. arr.length)
9826                 assert(r[i] == arr[i]);
9827 
9828             // test slicing
9829             foreach (i; 0 .. arr.length)
9830             {
9831                 foreach (j; i .. arr.length)
9832                     assert(r[i .. j].equal(arr[i .. j]));
9833 
9834                 assert(r[i .. $].equal(arr[i .. $]));
9835             }
9836 
9837             // test opDollar slicing
9838             assert(r[$/2 .. $].equal(arr[$/2 .. $]));
9839             assert(r[$ .. $].empty);
9840             if (arr.empty)
9841             {
9842                 assert(r[$ .. 0].empty);
9843                 assert(r[$/2 .. $].empty);
9844 
9845             }
9846         }
9847     }
9848 }
9849 
9850 // test with infinite ranges
9851 @safe pure nothrow unittest
9852 {
9853     import std.algorithm.comparison : equal;
9854 
9855     static foreach (Partial; [Yes.withPartial, No.withPartial])
9856     {{
9857         // InfiniteRange without RandomAccess
9858         auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
9859         assert(fibs.slide!Partial(2).take(2).equal!equal([[1,  1], [1,  2]]));
9860         assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
9861 
9862         // InfiniteRange with RandomAccess and slicing
9863         auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9864         auto oddsByPairs = odds.slide!Partial(2);
9865         assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
9866         assert(oddsByPairs[1].equal([3, 5]));
9867         assert(oddsByPairs[4].equal([9, 11]));
9868 
9869         static assert(hasSlicing!(typeof(odds)));
9870         assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
9871         assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
9872 
9873         auto oddsWithGaps = odds.slide!Partial(2, 4);
9874         assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
9875         assert(oddsWithGaps[2].equal([17, 19]));
9876         assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
9877         assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
9878     }}
9879 }
9880 
9881 // test reverse
9882 @safe pure nothrow unittest
9883 {
9884     import std.algorithm.comparison : equal;
9885 
9886     static foreach (Partial; [Yes.withPartial, No.withPartial])
9887     {{
9888         foreach (windowSize; 1 .. 15)
9889         foreach (stepSize; 1 .. 15)
9890         {
9891             auto r = 20.iota.slide!Partial(windowSize, stepSize);
9892             auto rArr = r.array.retro;
9893             auto rRetro = r.retro;
9894 
9895             assert(rRetro.length == rArr.length);
9896             assert(rRetro.equal(rArr));
9897             assert(rRetro.array.retro.equal(r));
9898         }
9899     }}
9900 }
9901 
9902 // test with dummy ranges
9903 @safe pure nothrow unittest
9904 {
9905     import std.algorithm.comparison : equal;
9906     import std.internal.test.dummyrange : AllDummyRanges;
9907     import std.meta : Filter;
9908 
9909     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9910     {{
9911         Range r;
9912 
9913         static foreach (Partial; [Yes.withPartial, No.withPartial])
9914         {
9915             assert(r.slide!Partial(1).equal!equal(
9916                 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
9917             ));
9918             assert(r.slide!Partial(2).equal!equal(
9919                 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
9920             ));
9921             assert(r.slide!Partial(3).equal!equal(
9922                 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
9923                 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
9924             ));
9925             assert(r.slide!Partial(6).equal!equal(
9926                 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
9927                 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
9928             ));
9929         }
9930 
9931         // special cases
9932         assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
9933         assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
9934         assert(r.slide!(No.withPartial)(15).empty);
9935         assert(r.slide!(No.withPartial)(15).walkLength == 0);
9936     }}
9937 }
9938 
9939 // test with dummy ranges
9940 @safe pure nothrow unittest
9941 {
9942     import std.algorithm.comparison : equal;
9943     import std.internal.test.dummyrange : AllDummyRanges;
9944     import std.meta : Filter;
9945     import std.typecons : tuple;
9946 
9947     alias t = tuple;
9948     static immutable list = [
9949     // iota   slide    expected
9950         t(6,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
9951         t(6,  t(4, 6), [[1, 2, 3, 4]]),
9952         t(6,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
9953         t(7,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
9954         t(7,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
9955         t(8,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
9956         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]]),
9957         t(8,  t(3, 4), [[1, 2, 3], [5, 6, 7]]),
9958         t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
9959     ];
9960 
9961     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9962     static foreach (Partial; [Yes.withPartial, No.withPartial])
9963     foreach (e; list)
9964         assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
9965 
9966     static immutable listSpecial = [
9967     // iota   slide    expected
9968         t(6,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
9969         t(7,  t(4, 5), [[1, 2, 3, 4], [6, 7]]),
9970         t(7,  t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
9971         t(7,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
9972         t(8,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
9973         t(8,  t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
9974         t(8,  t(3, 6), [[1, 2, 3], [7, 8]]),
9975         t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
9976         t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
9977     ];
9978     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9979     static foreach (Partial; [Yes.withPartial, No.withPartial])
9980     foreach (e; listSpecial)
9981     {
9982         Range r;
9983         assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
9984         assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
9985     }
9986 }
9987 
9988 // test reverse with dummy ranges
9989 @safe pure nothrow unittest
9990 {
9991     import std.algorithm.comparison : equal;
9992     import std.internal.test.dummyrange : AllDummyRanges;
9993     import std.meta : Filter, templateAnd;
9994     import std.typecons : tuple;
9995     alias t = tuple;
9996 
9997     static immutable list = [
9998     //   slide   expected
9999         t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
10000         t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
10001         t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
10002                  [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
10003         t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
10004         t(2, 4, [[9, 10], [5, 6], [1, 2]]),
10005     ];
10006 
10007     static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
10008     {{
10009         Range r;
10010         static foreach (Partial; [Yes.withPartial, No.withPartial])
10011         {
10012             foreach (e; list)
10013                 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
10014 
10015             // front = back
10016             foreach (windowSize; 1 .. 10)
10017             foreach (stepSize; 1 .. 10)
10018             {
10019                 auto slider = r.slide!Partial(windowSize, stepSize);
10020                 auto sliderRetro = slider.retro.array;
10021                 assert(slider.length == sliderRetro.length);
10022                 assert(sliderRetro.retro.equal!equal(slider));
10023             }
10024         }
10025 
10026         // special cases
10027         assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
10028         assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
10029     }}
10030 }
10031 
10032 // test different sliceable ranges
10033 @safe pure nothrow unittest
10034 {
10035     import std.algorithm.comparison : equal;
10036     import std.internal.test.dummyrange : AllDummyRanges;
10037     import std.meta : AliasSeq;
10038 
10039     struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
10040                                  Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
10041     {
10042         Range arr = 10.iota.array; // similar to DummyRange
10043         @property auto save() { return typeof(this)(arr); }
10044         @property auto front() { return arr[0]; }
10045         void popFront() { arr.popFront(); }
10046         auto opSlice(size_t i, size_t j)
10047         {
10048             // subslices can't be infinite
10049             return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
10050         }
10051 
10052         static if (withInfiniteness)
10053         {
10054             enum empty = false;
10055         }
10056         else
10057         {
10058             @property bool empty() { return arr.empty; }
10059             @property auto length() { return arr.length; }
10060         }
10061 
10062         static if (withOpDollar)
10063         {
10064             static if (withInfiniteness)
10065             {
10066                 struct Dollar {}
10067                 Dollar opDollar() const { return Dollar.init; }
10068 
10069                 // Slice to dollar
10070                 typeof(this) opSlice(size_t lower, Dollar)
10071                 {
10072                     return typeof(this)(arr[lower .. $]);
10073                 }
10074 
10075             }
10076             else
10077             {
10078                 alias opDollar = length;
10079             }
10080         }
10081     }
10082 
10083     import std.meta : Filter,  templateNot;
10084     alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
10085 
10086     static foreach (Partial; [Yes.withPartial, No.withPartial])
10087     {{
10088         static foreach (Range; SliceableDummyRanges)
10089         {{
10090             Range r;
10091             r.reinit;
10092             r.arr[] -= 1; // use a 0-based array (for clarity)
10093 
10094             assert(r.slide!Partial(2)[0].equal([0, 1]));
10095             assert(r.slide!Partial(2)[1].equal([1, 2]));
10096 
10097             // saveable
10098             auto s = r.slide!Partial(2);
10099             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10100             s.save.popFront;
10101             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10102 
10103             assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
10104         }}
10105 
10106         static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
10107         {{
10108             Range r;
10109             r.reinit;
10110             r.arr[] -= 1; // use a 0-based array (for clarity)
10111 
10112             assert(r.slide!(No.withPartial)(6).equal!equal(
10113                 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
10114                 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
10115             ));
10116             assert(r.slide!(No.withPartial)(16).empty);
10117 
10118             assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
10119             assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
10120             assert(r.slide!Partial(2)[$ .. $].empty);
10121 
10122             assert(r.slide!Partial(3).retro.equal!equal(
10123                 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
10124             ));
10125         }}
10126 
10127         alias T = int[];
10128 
10129         // separate checks for infinity
10130         auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
10131         assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
10132         assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
10133 
10134         auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
10135         assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
10136         assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
10137         assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
10138     }}
10139 }
10140 
10141 // https://issues.dlang.org/show_bug.cgi?id=19082
10142 @safe unittest
10143 {
10144     import std.algorithm.comparison : equal;
10145     import std.algorithm.iteration : map;
10146     assert([1].map!(x => x).slide(2).equal!equal([[1]]));
10147 }
10148 
10149 // https://issues.dlang.org/show_bug.cgi?id=19642
10150 @safe unittest
10151 {
10152     import std.algorithm.comparison : equal;
10153     import std.algorithm.iteration : splitter;
10154 
10155     assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]]));
10156 }
10157 
10158 // https://issues.dlang.org/show_bug.cgi?id=23976
10159 @safe unittest
10160 {
10161     import std.algorithm.comparison : equal;
10162     import std.algorithm.iteration : splitter;
10163 
10164     assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]]));
10165 }
10166 
10167 private struct OnlyResult(Values...)
10168 if (Values.length > 1)
10169 {
10170     private enum arity = Values.length;
10171 
10172     private alias UnqualValues = staticMap!(Unqual, Values);
10173 
10174     private this(return scope ref Values values)
10175     {
10176         ref @trusted unqual(T)(ref T x){return cast() x;}
10177 
10178         // TODO: this calls any possible copy constructors without qualifiers.
10179         // Find a way to initialize values using qualified copy constructors.
10180         static foreach (i; 0 .. Values.length)
10181         {
10182             this.values[i] = unqual(values[i]);
10183         }
10184         this.backIndex = arity;
10185     }
10186 
10187     bool empty() @property
10188     {
10189         return frontIndex >= backIndex;
10190     }
10191 
10192     CommonType!Values front() @property
10193     {
10194         assert(!empty, "Attempting to fetch the front of an empty Only range");
10195         return this[0];
10196     }
10197 
10198     void popFront()
10199     {
10200         assert(!empty, "Attempting to popFront an empty Only range");
10201         ++frontIndex;
10202     }
10203 
10204     CommonType!Values back() @property
10205     {
10206         assert(!empty, "Attempting to fetch the back of an empty Only range");
10207         return this[$ - 1];
10208     }
10209 
10210     void popBack()
10211     {
10212         assert(!empty, "Attempting to popBack an empty Only range");
10213         --backIndex;
10214     }
10215 
10216     OnlyResult save() @property
10217     {
10218         return this;
10219     }
10220 
10221     size_t length() const @property
10222     {
10223         return backIndex - frontIndex;
10224     }
10225 
10226     alias opDollar = length;
10227 
10228     @trusted CommonType!Values opIndex(size_t idx)
10229     {
10230         // when i + idx points to elements popped
10231         // with popBack
10232         assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
10233         final switch (frontIndex + idx)
10234             static foreach (i, T; Values)
10235             case i:
10236                 return cast(T) values[i];
10237     }
10238 
10239     OnlyResult opSlice()
10240     {
10241         return this;
10242     }
10243 
10244     OnlyResult opSlice(size_t from, size_t to)
10245     {
10246         OnlyResult result = this;
10247         result.frontIndex += from;
10248         result.backIndex = this.frontIndex + to;
10249         assert(
10250             from <= to,
10251             "Attempting to slice an Only range with a larger first argument than the second."
10252         );
10253         assert(
10254             to <= length,
10255             "Attempting to slice using an out of bounds index on an Only range"
10256         );
10257         return result;
10258     }
10259 
10260     private size_t frontIndex = 0;
10261     private size_t backIndex = 0;
10262 
10263     // https://issues.dlang.org/show_bug.cgi?id=10643
10264     version (none)
10265     {
10266         import std.traits : hasElaborateAssign;
10267         static if (hasElaborateAssign!T)
10268             private UnqualValues values;
10269         else
10270             private UnqualValues values = void;
10271     }
10272     else
10273         // These may alias to shared or immutable data. Do not let the user
10274         // to access these directly, and do not allow mutation without checking
10275         // the qualifier.
10276         private UnqualValues values;
10277 }
10278 
10279 // Specialize for single-element results
10280 private struct OnlyResult(T)
10281 {
10282     @property T front()
10283     {
10284         assert(!empty, "Attempting to fetch the front of an empty Only range");
10285         return fetchFront();
10286     }
10287     @property T back()
10288     {
10289         assert(!empty, "Attempting to fetch the back of an empty Only range");
10290         return fetchFront();
10291     }
10292     @property bool empty() const { return _empty; }
10293     @property size_t length() const { return !_empty; }
10294     @property auto save() { return this; }
10295     void popFront()
10296     {
10297         assert(!_empty, "Attempting to popFront an empty Only range");
10298         _empty = true;
10299     }
10300     void popBack()
10301     {
10302         assert(!_empty, "Attempting to popBack an empty Only range");
10303         _empty = true;
10304     }
10305     alias opDollar = length;
10306 
10307     private this()(return scope auto ref T value)
10308     {
10309         ref @trusted unqual(ref T x){return cast() x;}
10310         // TODO: this calls the possible copy constructor without qualifiers.
10311         // Find a way to initialize value using a qualified copy constructor.
10312         this._value = unqual(value);
10313         this._empty = false;
10314     }
10315 
10316     T opIndex(size_t i)
10317     {
10318         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
10319         return fetchFront();
10320     }
10321 
10322     OnlyResult opSlice()
10323     {
10324         return this;
10325     }
10326 
10327     OnlyResult opSlice(size_t from, size_t to)
10328     {
10329         assert(
10330             from <= to,
10331             "Attempting to slice an Only range with a larger first argument than the second."
10332         );
10333         assert(
10334             to <= length,
10335             "Attempting to slice using an out of bounds index on an Only range"
10336         );
10337         OnlyResult copy = this;
10338         copy._empty = _empty || from == to;
10339         return copy;
10340     }
10341 
10342     // This may alias to shared or immutable data. Do not let the user
10343     // to access this directly, and do not allow mutation without checking
10344     // the qualifier.
10345     private Unqual!T _value;
10346     private bool _empty = true;
10347     private @trusted T fetchFront()
10348     {
10349         return *cast(T*)&_value;
10350     }
10351 }
10352 
10353 /**
10354 Assemble `values` into a range that carries all its
10355 elements in-situ.
10356 
10357 Useful when a single value or multiple disconnected values
10358 must be passed to an algorithm expecting a range, without
10359 having to perform dynamic memory allocation.
10360 
10361 As copying the range means copying all elements, it can be
10362 safely returned from functions. For the same reason, copying
10363 the returned range may be expensive for a large number of arguments.
10364 
10365 Params:
10366     values = the values to assemble together
10367 
10368 Returns:
10369     A `RandomAccessRange` of the assembled values.
10370 
10371 See_Also: $(LREF chain) to chain ranges
10372  */
10373 auto only(Values...)(return scope Values values)
10374 if (!is(CommonType!Values == void))
10375 {
10376     return OnlyResult!Values(values);
10377 }
10378 
10379 /// ditto
10380 auto only()()
10381 {
10382     // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383
10383     struct EmptyElementType {}
10384     EmptyElementType[] result;
10385     return result;
10386 }
10387 
10388 ///
10389 @safe unittest
10390 {
10391     import std.algorithm.comparison : equal;
10392     import std.algorithm.iteration : filter, joiner, map;
10393     import std.algorithm.searching : findSplitBefore;
10394     import std.uni : isUpper;
10395 
10396     assert(equal(only('♡'), "♡"));
10397     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
10398 
10399     assert(only("one", "two", "three").joiner(" ").equal("one two three"));
10400 
10401     string title = "The D Programming Language";
10402     assert(title
10403         .filter!isUpper // take the upper case letters
10404         .map!only       // make each letter its own range
10405         .joiner(".")    // join the ranges together lazily
10406         .equal("T.D.P.L"));
10407 }
10408 
10409 // https://issues.dlang.org/show_bug.cgi?id=20314
10410 @safe unittest
10411 {
10412     import std.algorithm.iteration : joiner;
10413 
10414     const string s = "foo", t = "bar";
10415 
10416     assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
10417 }
10418 
10419 // Tests the zero-element result
10420 @safe unittest
10421 {
10422     import std.algorithm.comparison : equal;
10423 
10424     auto emptyRange = only();
10425 
10426     alias EmptyRange = typeof(emptyRange);
10427     static assert(isInputRange!EmptyRange);
10428     static assert(isForwardRange!EmptyRange);
10429     static assert(isBidirectionalRange!EmptyRange);
10430     static assert(isRandomAccessRange!EmptyRange);
10431     static assert(hasLength!EmptyRange);
10432     static assert(hasSlicing!EmptyRange);
10433 
10434     assert(emptyRange.empty);
10435     assert(emptyRange.length == 0);
10436     assert(emptyRange.equal(emptyRange[]));
10437     assert(emptyRange.equal(emptyRange.save));
10438     assert(emptyRange[0 .. 0].equal(emptyRange));
10439 }
10440 
10441 // Tests the single-element result
10442 @safe unittest
10443 {
10444     import std.algorithm.comparison : equal;
10445     import std.typecons : tuple;
10446     foreach (x; tuple(1, '1', 1.0, "1", [1]))
10447     {
10448         auto a = only(x);
10449         typeof(x)[] e = [];
10450         assert(a.front == x);
10451         assert(a.back == x);
10452         assert(!a.empty);
10453         assert(a.length == 1);
10454         assert(equal(a, a[]));
10455         assert(equal(a, a[0 .. 1]));
10456         assert(equal(a[0 .. 0], e));
10457         assert(equal(a[1 .. 1], e));
10458         assert(a[0] == x);
10459 
10460         auto b = a.save;
10461         assert(equal(a, b));
10462         a.popFront();
10463         assert(a.empty && a.length == 0 && a[].empty);
10464         b.popBack();
10465         assert(b.empty && b.length == 0 && b[].empty);
10466 
10467         alias A = typeof(a);
10468         static assert(isInputRange!A);
10469         static assert(isForwardRange!A);
10470         static assert(isBidirectionalRange!A);
10471         static assert(isRandomAccessRange!A);
10472         static assert(hasLength!A);
10473         static assert(hasSlicing!A);
10474     }
10475 
10476     auto imm = only!(immutable int)(1);
10477     immutable int[] imme = [];
10478     assert(imm.front == 1);
10479     assert(imm.back == 1);
10480     assert(!imm.empty);
10481     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10482     assert(imm.length == 1);
10483     assert(equal(imm, imm[]));
10484     assert(equal(imm, imm[0 .. 1]));
10485     assert(equal(imm[0 .. 0], imme));
10486     assert(equal(imm[1 .. 1], imme));
10487     assert(imm[0] == 1);
10488 }
10489 
10490 // Tests multiple-element results
10491 @safe unittest
10492 {
10493     import std.algorithm.comparison : equal;
10494     import std.algorithm.iteration : joiner;
10495     import std.meta : AliasSeq;
10496     static assert(!__traits(compiles, only(1, "1")));
10497 
10498     auto nums = only!(byte, uint, long)(1, 2, 3);
10499     static assert(is(ElementType!(typeof(nums)) == long));
10500     assert(nums.length == 3);
10501 
10502     foreach (i; 0 .. 3)
10503         assert(nums[i] == i + 1);
10504 
10505     auto saved = nums.save;
10506 
10507     foreach (i; 1 .. 4)
10508     {
10509         assert(nums.front == nums[0]);
10510         assert(nums.front == i);
10511         nums.popFront();
10512         assert(nums.length == 3 - i);
10513     }
10514 
10515     assert(nums.empty);
10516 
10517     assert(saved.equal(only(1, 2, 3)));
10518     assert(saved.equal(saved[]));
10519     assert(saved[0 .. 1].equal(only(1)));
10520     assert(saved[0 .. 2].equal(only(1, 2)));
10521     assert(saved[0 .. 3].equal(saved));
10522     assert(saved[1 .. 3].equal(only(2, 3)));
10523     assert(saved[2 .. 3].equal(only(3)));
10524     assert(saved[0 .. 0].empty);
10525     assert(saved[3 .. 3].empty);
10526 
10527     alias data = AliasSeq!("one", "two", "three", "four");
10528     static joined =
10529         ["one two", "one two three", "one two three four"];
10530     string[] joinedRange = joined;
10531 
10532     static foreach (argCount; 2 .. 5)
10533     {{
10534         auto values = only(data[0 .. argCount]);
10535         alias Values = typeof(values);
10536         static assert(is(ElementType!Values == string));
10537         static assert(isInputRange!Values);
10538         static assert(isForwardRange!Values);
10539         static assert(isBidirectionalRange!Values);
10540         static assert(isRandomAccessRange!Values);
10541         static assert(hasSlicing!Values);
10542         static assert(hasLength!Values);
10543 
10544         assert(values.length == argCount);
10545         assert(values[0 .. $].equal(values[0 .. values.length]));
10546         assert(values.joiner(" ").equal(joinedRange.front));
10547         joinedRange.popFront();
10548     }}
10549 
10550     assert(saved.retro.equal(only(3, 2, 1)));
10551     assert(saved.length == 3);
10552 
10553     assert(saved.back == 3);
10554     saved.popBack();
10555     assert(saved.length == 2);
10556     assert(saved.back == 2);
10557 
10558     assert(saved.front == 1);
10559     saved.popFront();
10560     assert(saved.length == 1);
10561     assert(saved.front == 2);
10562 
10563     saved.popBack();
10564     assert(saved.empty);
10565 
10566     auto imm = only!(immutable int, immutable int)(42, 24);
10567     alias Imm = typeof(imm);
10568     static assert(is(ElementType!Imm == immutable(int)));
10569     assert(!imm.empty);
10570     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10571     assert(imm.front == 42);
10572     imm.popFront();
10573     assert(imm.front == 24);
10574     imm.popFront();
10575     assert(imm.empty);
10576 
10577     static struct Test { int* a; }
10578     immutable(Test) test;
10579     cast(void) only(test, test); // Works with mutable indirection
10580 }
10581 
10582 // https://issues.dlang.org/show_bug.cgi?id=21129
10583 @safe unittest
10584 {
10585     auto range = () @safe {
10586         const(char)[5] staticStr = "Hello";
10587 
10588         // `only` must store a char[5] - not a char[]!
10589         return only(staticStr, " World");
10590     } ();
10591 
10592     assert(range.join == "Hello World");
10593 }
10594 
10595 // https://issues.dlang.org/show_bug.cgi?id=21129
10596 @safe unittest
10597 {
10598     struct AliasedString
10599     {
10600         const(char)[5] staticStr = "Hello";
10601 
10602         @property const(char)[] slice() const
10603         {
10604             return staticStr[];
10605         }
10606         alias slice this;
10607     }
10608 
10609     auto range = () @safe {
10610         auto hello = AliasedString();
10611 
10612         // a copy of AliasedString is stored in the range.
10613         return only(hello, " World");
10614     } ();
10615 
10616     assert(range.join == "Hello World");
10617 }
10618 
10619 // https://issues.dlang.org/show_bug.cgi?id=21022
10620 @safe pure nothrow unittest
10621 {
10622     struct S
10623     {
10624         int* mem;
10625     }
10626 
10627     immutable S x;
10628     immutable(S)[] arr;
10629     auto r1 = arr.chain(x.only, only(x, x));
10630 }
10631 
10632 /**
10633 Iterate over `range` with an attached index variable.
10634 
10635 Each element is a $(REF Tuple, std,typecons) containing the index
10636 and the element, in that order, where the index member is named `index`
10637 and the element member is named `value`.
10638 
10639 The index starts at `start` and is incremented by one on every iteration.
10640 
10641 Overflow:
10642     If `range` has length, then it is an error to pass a value for `start`
10643     so that `start + range.length` is bigger than `Enumerator.max`, thus
10644     it is ensured that overflow cannot happen.
10645 
10646     If `range` does not have length, and `popFront` is called when
10647     `front.index == Enumerator.max`, the index will overflow and
10648     continue from `Enumerator.min`.
10649 
10650 Params:
10651     range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
10652     start = the number to start the index counter from
10653 
10654 Returns:
10655     At minimum, an input range. All other range primitives are given in the
10656     resulting range if `range` has them. The exceptions are the bidirectional
10657     primitives, which are propagated only if `range` has length.
10658 
10659 Example:
10660 Useful for using `foreach` with an index loop variable:
10661 ----
10662     import std.stdio : stdin, stdout;
10663     import std.range : enumerate;
10664 
10665     foreach (lineNum, line; stdin.byLine().enumerate(1))
10666         stdout.writefln("line #%s: %s", lineNum, line);
10667 ----
10668 */
10669 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
10670 if (isIntegral!Enumerator && isInputRange!Range)
10671 in
10672 {
10673     static if (hasLength!Range)
10674     {
10675         // TODO: core.checkedint supports mixed signedness yet?
10676         import core.checkedint : adds, addu;
10677         import std.conv : ConvException, to;
10678         import std.traits : isSigned, Largest, Signed;
10679 
10680         alias LengthType = typeof(range.length);
10681         bool overflow;
10682         static if (isSigned!Enumerator && isSigned!LengthType)
10683             auto result = adds(start, range.length, overflow);
10684         else static if (isSigned!Enumerator)
10685         {
10686             alias signed_t = Largest!(Enumerator, Signed!LengthType);
10687             signed_t signedLength;
10688             //This is to trick the compiler because if length is enum
10689             //the compiler complains about unreachable code.
10690             auto getLength()
10691             {
10692                 return range.length;
10693             }
10694             //Can length fit in the signed type
10695             assert(getLength() < signed_t.max,
10696                 "a signed length type is required but the range's length() is too great");
10697             signedLength = range.length;
10698             auto result = adds(start, signedLength, overflow);
10699         }
10700         else
10701         {
10702             static if (isSigned!LengthType)
10703                 assert(range.length >= 0);
10704             auto result = addu(start, range.length, overflow);
10705         }
10706 
10707         assert(!overflow && result <= Enumerator.max);
10708     }
10709 }
10710 do
10711 {
10712     // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
10713     static struct Result
10714     {
10715         import std.typecons : Tuple;
10716 
10717         private:
10718         alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
10719         Range range;
10720         Unqual!Enumerator index;
10721 
10722         public:
10723         ElemType front() @property
10724         {
10725             assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
10726             return typeof(return)(index, range.front);
10727         }
10728 
10729         static if (isInfinite!Range)
10730             enum bool empty = false;
10731         else
10732         {
10733             bool empty() @property
10734             {
10735                 return range.empty;
10736             }
10737         }
10738 
10739         void popFront()
10740         {
10741             assert(!range.empty, "Attempting to popFront an empty enumerate");
10742             range.popFront();
10743             ++index; // When !hasLength!Range, overflow is expected
10744         }
10745 
10746         static if (isForwardRange!Range)
10747         {
10748             Result save() @property
10749             {
10750                 return typeof(return)(range.save, index);
10751             }
10752         }
10753 
10754         static if (hasLength!Range)
10755         {
10756             mixin ImplementLength!range;
10757 
10758             static if (isBidirectionalRange!Range)
10759             {
10760                 ElemType back() @property
10761                 {
10762                     assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
10763                     return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
10764                 }
10765 
10766                 void popBack()
10767                 {
10768                     assert(!range.empty, "Attempting to popBack an empty enumerate");
10769                     range.popBack();
10770                 }
10771             }
10772         }
10773 
10774         static if (isRandomAccessRange!Range)
10775         {
10776              ElemType opIndex(size_t i)
10777              {
10778                 return typeof(return)(cast(Enumerator)(index + i), range[i]);
10779              }
10780         }
10781 
10782         static if (hasSlicing!Range)
10783         {
10784             static if (hasLength!Range)
10785             {
10786                 Result opSlice(size_t i, size_t j)
10787                 {
10788                     return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
10789                 }
10790             }
10791             else
10792             {
10793                 static struct DollarToken {}
10794                 enum opDollar = DollarToken.init;
10795 
10796                 Result opSlice(size_t i, DollarToken)
10797                 {
10798                     return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
10799                 }
10800 
10801                 auto opSlice(size_t i, size_t j)
10802                 {
10803                     return this[i .. $].takeExactly(j - 1);
10804                 }
10805             }
10806         }
10807     }
10808 
10809     return Result(range, start);
10810 }
10811 
10812 /// Can start enumeration from a negative position:
10813 pure @safe nothrow unittest
10814 {
10815     import std.array : assocArray;
10816     import std.range : enumerate;
10817 
10818     bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
10819     assert(aa[-1]);
10820     assert(aa[0]);
10821     assert(aa[1]);
10822 }
10823 
10824 // Make sure passing qualified types works
10825 pure @safe nothrow unittest
10826 {
10827     char[4] v;
10828     immutable start = 2;
10829     v[2 .. $].enumerate(start);
10830 }
10831 
10832 pure @safe nothrow unittest
10833 {
10834     import std.internal.test.dummyrange : AllDummyRanges;
10835     import std.meta : AliasSeq;
10836     import std.typecons : tuple;
10837 
10838     static struct HasSlicing
10839     {
10840         typeof(this) front() @property { return typeof(this).init; }
10841         bool empty() @property { return true; }
10842         void popFront() {}
10843 
10844         typeof(this) opSlice(size_t, size_t)
10845         {
10846             return typeof(this)();
10847         }
10848     }
10849 
10850     static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
10851     {{
10852         alias R = typeof(enumerate(DummyType.init));
10853         static assert(isInputRange!R);
10854         static assert(isForwardRange!R == isForwardRange!DummyType);
10855         static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
10856         static assert(!hasAssignableElements!R);
10857 
10858         static if (hasLength!DummyType)
10859         {
10860             static assert(hasLength!R);
10861             static assert(isBidirectionalRange!R ==
10862                 isBidirectionalRange!DummyType);
10863         }
10864 
10865         static assert(hasSlicing!R == hasSlicing!DummyType);
10866     }}
10867 
10868     static immutable values = ["zero", "one", "two", "three"];
10869     auto enumerated = values[].enumerate();
10870     assert(!enumerated.empty);
10871     assert(enumerated.front == tuple(0, "zero"));
10872     assert(enumerated.back == tuple(3, "three"));
10873 
10874     typeof(enumerated) saved = enumerated.save;
10875     saved.popFront();
10876     assert(enumerated.front == tuple(0, "zero"));
10877     assert(saved.front == tuple(1, "one"));
10878     assert(saved.length == enumerated.length - 1);
10879     saved.popBack();
10880     assert(enumerated.back == tuple(3, "three"));
10881     assert(saved.back == tuple(2, "two"));
10882     saved.popFront();
10883     assert(saved.front == tuple(2, "two"));
10884     assert(saved.back == tuple(2, "two"));
10885     saved.popFront();
10886     assert(saved.empty);
10887 
10888     size_t control = 0;
10889     foreach (i, v; enumerated)
10890     {
10891         static assert(is(typeof(i) == size_t));
10892         static assert(is(typeof(v) == typeof(values[0])));
10893         assert(i == control);
10894         assert(v == values[i]);
10895         assert(tuple(i, v) == enumerated[i]);
10896         ++control;
10897     }
10898 
10899     assert(enumerated[0 .. $].front == tuple(0, "zero"));
10900     assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
10901 
10902     foreach (i; 0 .. 10)
10903     {
10904         auto shifted = values[0 .. 2].enumerate(i);
10905         assert(shifted.front == tuple(i, "zero"));
10906         assert(shifted[0] == shifted.front);
10907 
10908         auto next = tuple(i + 1, "one");
10909         assert(shifted[1] == next);
10910         shifted.popFront();
10911         assert(shifted.front == next);
10912         shifted.popFront();
10913         assert(shifted.empty);
10914     }
10915 
10916     static foreach (T; AliasSeq!(ubyte, byte, uint, int))
10917     {{
10918         auto inf = 42.repeat().enumerate(T.max);
10919         alias Inf = typeof(inf);
10920         static assert(isInfinite!Inf);
10921         static assert(hasSlicing!Inf);
10922 
10923         // test overflow
10924         assert(inf.front == tuple(T.max, 42));
10925         inf.popFront();
10926         assert(inf.front == tuple(T.min, 42));
10927 
10928         // test slicing
10929         inf = inf[42 .. $];
10930         assert(inf.front == tuple(T.min + 42, 42));
10931         auto window = inf[0 .. 2];
10932         assert(window.length == 1);
10933         assert(window.front == inf.front);
10934         window.popFront();
10935         assert(window.empty);
10936     }}
10937 }
10938 
10939 pure @safe unittest
10940 {
10941     import std.algorithm.comparison : equal;
10942     import std.meta : AliasSeq;
10943     static immutable int[] values = [0, 1, 2, 3, 4];
10944     static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
10945     {{
10946         auto enumerated = values.enumerate!T();
10947         static assert(is(typeof(enumerated.front.index) == T));
10948         assert(enumerated.equal(values[].zip(values)));
10949 
10950         foreach (T i; 0 .. 5)
10951         {
10952             auto subset = values[cast(size_t) i .. $];
10953             auto offsetEnumerated = subset.enumerate(i);
10954             static assert(is(typeof(enumerated.front.index) == T));
10955             assert(offsetEnumerated.equal(subset.zip(subset)));
10956         }
10957     }}
10958 }
10959 @nogc @safe unittest
10960 {
10961    const val = iota(1, 100).enumerate(1);
10962 }
10963 @nogc @safe unittest
10964 {
10965     import core.exception : AssertError;
10966     import std.exception : assertThrown;
10967     struct RangePayload {
10968         enum length = size_t.max;
10969         void popFront() {}
10970         int front() { return 0; }
10971         bool empty() { return true; }
10972     }
10973     RangePayload thePayload;
10974     //Assertion won't happen when contracts are disabled for -release.
10975     debug assertThrown!AssertError(enumerate(thePayload, -10));
10976 }
10977 // https://issues.dlang.org/show_bug.cgi?id=10939
10978 version (none)
10979 {
10980     // Re-enable (or remove) if 10939 is resolved.
10981     /+pure+/ @safe unittest // Impure because of std.conv.to
10982     {
10983         import core.exception : RangeError;
10984         import std.exception : assertNotThrown, assertThrown;
10985         import std.meta : AliasSeq;
10986 
10987         static immutable values = [42];
10988 
10989         static struct SignedLengthRange
10990         {
10991             immutable(int)[] _values = values;
10992 
10993             int front() @property { assert(false); }
10994             bool empty() @property { assert(false); }
10995             void popFront() { assert(false); }
10996 
10997             int length() @property
10998             {
10999                 return cast(int)_values.length;
11000             }
11001         }
11002 
11003         SignedLengthRange svalues;
11004         static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
11005         {
11006             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
11007             assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
11008             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
11009 
11010             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
11011             assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
11012             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
11013         }
11014 
11015         static foreach (Enumerator; AliasSeq!(byte, short, int))
11016         {
11017             assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
11018         }
11019 
11020         assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
11021     }
11022 }
11023 
11024 /**
11025   Returns true if `fn` accepts variables of type T1 and T2 in any order.
11026   The following code should compile:
11027   ---
11028   (ref T1 a, ref T2 b)
11029   {
11030     fn(a, b);
11031     fn(b, a);
11032   }
11033   ---
11034 */
11035 template isTwoWayCompatible(alias fn, T1, T2)
11036 {
11037     enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
11038         {
11039             cast(void) fn(a, b);
11040             cast(void) fn(b, a);
11041         }
11042     ));
11043 }
11044 
11045 ///
11046 @safe unittest
11047 {
11048     void func1(int a, int b);
11049     void func2(int a, float b);
11050 
11051     static assert(isTwoWayCompatible!(func1, int, int));
11052     static assert(isTwoWayCompatible!(func1, short, int));
11053     static assert(!isTwoWayCompatible!(func2, int, float));
11054 
11055     void func3(ref int a, ref int b);
11056     static assert( isTwoWayCompatible!(func3, int, int));
11057     static assert(!isTwoWayCompatible!(func3, short, int));
11058 }
11059 
11060 
11061 /**
11062    Policy used with the searching primitives `lowerBound`, $(D
11063    upperBound), and `equalRange` of $(LREF SortedRange) below.
11064  */
11065 enum SearchPolicy
11066 {
11067     /**
11068        Searches in a linear fashion.
11069     */
11070     linear,
11071 
11072     /**
11073        Searches with a step that is grows linearly (1, 2, 3,...)
11074        leading to a quadratic search schedule (indexes tried are 0, 1,
11075        3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
11076        the remaining interval is searched using binary search. The
11077        search is completed in $(BIGOH sqrt(n)) time. Use it when you
11078        are reasonably confident that the value is around the beginning
11079        of the range.
11080     */
11081     trot,
11082 
11083     /**
11084        Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
11085        galloping search algorithm), i.e. searches
11086        with a step that doubles every time, (1, 2, 4, 8, ...)  leading
11087        to an exponential search schedule (indexes tried are 0, 1, 3,
11088        7, 15, 31, 63,...) Once the search overshoots its target, the
11089        remaining interval is searched using binary search. A value is
11090        found in $(BIGOH log(n)) time.
11091     */
11092     gallop,
11093 
11094     /**
11095        Searches using a classic interval halving policy. The search
11096        starts in the middle of the range, and each search step cuts
11097        the range in half. This policy finds a value in $(BIGOH log(n))
11098        time but is less cache friendly than `gallop` for large
11099        ranges. The `binarySearch` policy is used as the last step
11100        of `trot`, `gallop`, `trotBackwards`, and $(D
11101        gallopBackwards) strategies.
11102     */
11103     binarySearch,
11104 
11105     /**
11106        Similar to `trot` but starts backwards. Use it when
11107        confident that the value is around the end of the range.
11108     */
11109     trotBackwards,
11110 
11111     /**
11112        Similar to `gallop` but starts backwards. Use it when
11113        confident that the value is around the end of the range.
11114     */
11115     gallopBackwards
11116 }
11117 
11118 ///
11119 @safe unittest
11120 {
11121     import std.algorithm.comparison : equal;
11122 
11123     auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
11124     auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
11125     assert(p1.equal([4, 5, 6, 7, 8, 9]));
11126 
11127     auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
11128     assert(p2.equal([0, 1, 2, 3]));
11129 }
11130 
11131 /**
11132    Options for $(LREF SortedRange) ranges (below).
11133 */
11134 enum SortedRangeOptions
11135 {
11136    /**
11137       Assume, that the range is sorted without checking.
11138    */
11139    assumeSorted,
11140 
11141    /**
11142       All elements of the range are checked to be sorted.
11143       The check is performed in O(n) time.
11144    */
11145    checkStrictly,
11146 
11147    /**
11148       Some elements of the range are checked to be sorted.
11149       For ranges with random order, this will almost surely
11150       detect, that it is not sorted. For almost sorted ranges
11151       it's more likely to fail. The checked elements are choosen
11152       in a deterministic manner, which makes this check reproducable.
11153       The check is performed in O(log(n)) time.
11154    */
11155    checkRoughly,
11156 }
11157 
11158 ///
11159 @safe pure unittest
11160 {
11161     // create a SortedRange, that's checked strictly
11162     SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
11163 }
11164 
11165 /**
11166    Represents a sorted range. In addition to the regular range
11167    primitives, supports additional operations that take advantage of the
11168    ordering, such as merge and binary search. To obtain a $(D
11169    SortedRange) from an unsorted range `r`, use
11170    $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
11171    corresponding `SortedRange`. To construct a `SortedRange` from a range
11172    `r` that is known to be already sorted, use $(LREF assumeSorted).
11173 
11174    Params:
11175        pred: The predicate used to define the sortedness
11176        opt: Controls how strongly the range is checked for sortedness.
11177             Will only be used for `RandomAccessRanges`.
11178             Will not be used in CTFE.
11179 */
11180 struct SortedRange(Range, alias pred = "a < b",
11181     SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11182 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
11183 {
11184     import std.functional : binaryFun;
11185 
11186     private alias predFun = binaryFun!pred;
11187     private bool geq(L, R)(L lhs, R rhs)
11188     {
11189         return !predFun(lhs, rhs);
11190     }
11191     private bool gt(L, R)(L lhs, R rhs)
11192     {
11193         return predFun(rhs, lhs);
11194     }
11195     private Range _input;
11196 
11197     // Undocummented because a clearer way to invoke is by calling
11198     // assumeSorted.
11199     this(Range input)
11200     {
11201         static if (opt == SortedRangeOptions.checkRoughly)
11202         {
11203             roughlyVerifySorted(input);
11204         }
11205         static if (opt == SortedRangeOptions.checkStrictly)
11206         {
11207             strictlyVerifySorted(input);
11208         }
11209         this._input = input;
11210     }
11211 
11212     // Assertion only.
11213     static if (opt == SortedRangeOptions.checkRoughly)
11214     private void roughlyVerifySorted(Range r)
11215     {
11216         if (!__ctfe)
11217         {
11218             static if (isRandomAccessRange!Range && hasLength!Range)
11219             {
11220                 import core.bitop : bsr;
11221                 import std.algorithm.sorting : isSorted;
11222                 import std.exception : enforce;
11223 
11224                 // Check the sortedness of the input
11225                 if (r.length < 2) return;
11226 
11227                 immutable size_t msb = bsr(r.length) + 1;
11228                 assert(msb > 0 && msb <= r.length);
11229                 immutable step = r.length / msb;
11230                 auto st = stride(r, step);
11231 
11232                 enforce(isSorted!pred(st), "Range is not sorted");
11233             }
11234         }
11235     }
11236 
11237     // Assertion only.
11238     static if (opt == SortedRangeOptions.checkStrictly)
11239     private void strictlyVerifySorted(Range r)
11240     {
11241         if (!__ctfe)
11242         {
11243             static if (isRandomAccessRange!Range && hasLength!Range)
11244             {
11245                 import std.algorithm.sorting : isSorted;
11246                 import std.exception : enforce;
11247 
11248                 enforce(isSorted!pred(r), "Range is not sorted");
11249             }
11250         }
11251     }
11252 
11253     /// Range primitives.
11254     @property bool empty()             //const
11255     {
11256         return this._input.empty;
11257     }
11258 
11259     /// Ditto
11260     static if (isForwardRange!Range)
11261     @property auto save()
11262     {
11263         // Avoid the constructor
11264         typeof(this) result = this;
11265         result._input = _input.save;
11266         return result;
11267     }
11268 
11269     /// Ditto
11270     @property auto ref front()
11271     {
11272         return _input.front;
11273     }
11274 
11275     /// Ditto
11276     void popFront()
11277     {
11278         _input.popFront();
11279     }
11280 
11281     /// Ditto
11282     static if (isBidirectionalRange!Range)
11283     {
11284         @property auto ref back()
11285         {
11286             return _input.back;
11287         }
11288 
11289         /// Ditto
11290         void popBack()
11291         {
11292             _input.popBack();
11293         }
11294     }
11295 
11296     /// Ditto
11297     static if (isRandomAccessRange!Range)
11298         auto ref opIndex(size_t i)
11299         {
11300             return _input[i];
11301         }
11302 
11303     /// Ditto
11304     static if (hasSlicing!Range)
11305         auto opSlice(size_t a, size_t b) return scope
11306         {
11307             assert(
11308                 a <= b,
11309                 "Attempting to slice a SortedRange with a larger first argument than the second."
11310             );
11311             typeof(this) result = this;
11312             result._input = _input[a .. b];// skip checking
11313             return result;
11314         }
11315 
11316     mixin ImplementLength!_input;
11317 
11318 /**
11319     Releases the controlled range and returns it.
11320 
11321     This does the opposite of $(LREF assumeSorted): instead of turning a range
11322     into a `SortedRange`, it extracts the original range back out of the `SortedRange`
11323     using $(REF, move, std,algorithm,mutation).
11324 */
11325     auto release() return scope
11326     {
11327         import std.algorithm.mutation : move;
11328         return move(_input);
11329     }
11330 
11331     ///
11332     static if (is(Range : int[]))
11333     @safe unittest
11334     {
11335         import std.algorithm.sorting : sort;
11336         int[3] data = [ 1, 2, 3 ];
11337         auto a = assumeSorted(data[]);
11338         assert(a == sort!"a < b"(data[]));
11339         int[] p = a.release();
11340         assert(p == [ 1, 2, 3 ]);
11341     }
11342 
11343     // Assuming a predicate "test" that returns 0 for a left portion
11344     // of the range and then 1 for the rest, returns the index at
11345     // which the first 1 appears. Used internally by the search routines.
11346     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11347     if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
11348     {
11349         size_t first = 0, count = _input.length;
11350         while (count > 0)
11351         {
11352             immutable step = count / 2, it = first + step;
11353             if (!test(_input[it], v))
11354             {
11355                 first = it + 1;
11356                 count -= step + 1;
11357             }
11358             else
11359             {
11360                 count = step;
11361             }
11362         }
11363         return first;
11364     }
11365 
11366     // Specialization for trot and gallop
11367     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11368     if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
11369         && isRandomAccessRange!Range)
11370     {
11371         if (empty || test(front, v)) return 0;
11372         immutable count = length;
11373         if (count == 1) return 1;
11374         size_t below = 0, above = 1, step = 2;
11375         while (!test(_input[above], v))
11376         {
11377             // Still too small, update below and increase gait
11378             below = above;
11379             immutable next = above + step;
11380             if (next >= count)
11381             {
11382                 // Overshot - the next step took us beyond the end. So
11383                 // now adjust next and simply exit the loop to do the
11384                 // binary search thingie.
11385                 above = count;
11386                 break;
11387             }
11388             // Still in business, increase step and continue
11389             above = next;
11390             static if (sp == SearchPolicy.trot)
11391                 ++step;
11392             else
11393                 step <<= 1;
11394         }
11395         return below + this[below .. above].getTransitionIndex!(
11396             SearchPolicy.binarySearch, test, V)(v);
11397     }
11398 
11399     // Specialization for trotBackwards and gallopBackwards
11400     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11401     if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
11402         && isRandomAccessRange!Range)
11403     {
11404         immutable count = length;
11405         if (empty || !test(back, v)) return count;
11406         if (count == 1) return 0;
11407         size_t below = count - 2, above = count - 1, step = 2;
11408         while (test(_input[below], v))
11409         {
11410             // Still too large, update above and increase gait
11411             above = below;
11412             if (below < step)
11413             {
11414                 // Overshot - the next step took us beyond the end. So
11415                 // now adjust next and simply fall through to do the
11416                 // binary search thingie.
11417                 below = 0;
11418                 break;
11419             }
11420             // Still in business, increase step and continue
11421             below -= step;
11422             static if (sp == SearchPolicy.trot)
11423                 ++step;
11424             else
11425                 step <<= 1;
11426         }
11427         return below + this[below .. above].getTransitionIndex!(
11428             SearchPolicy.binarySearch, test, V)(v);
11429     }
11430 
11431 // lowerBound
11432 /**
11433    This function uses a search with policy `sp` to find the
11434    largest left subrange on which $(D pred(x, value)) is `true` for
11435    all `x` (e.g., if `pred` is "less than", returns the portion of
11436    the range with elements strictly smaller than `value`). The search
11437    schedule and its complexity are documented in
11438    $(LREF SearchPolicy).
11439 */
11440     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11441     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11442          && hasSlicing!Range)
11443     {
11444         return this[0 .. getTransitionIndex!(sp, geq)(value)];
11445     }
11446 
11447     ///
11448     static if (is(Range : int[]))
11449     @safe unittest
11450     {
11451         import std.algorithm.comparison : equal;
11452         auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
11453         auto p = a.lowerBound(4);
11454         assert(equal(p, [ 0, 1, 2, 3 ]));
11455     }
11456 
11457 // upperBound
11458 /**
11459 This function searches with policy `sp` to find the largest right
11460 subrange on which $(D pred(value, x)) is `true` for all `x`
11461 (e.g., if `pred` is "less than", returns the portion of the range
11462 with elements strictly greater than `value`). The search schedule
11463 and its complexity are documented in $(LREF SearchPolicy).
11464 
11465 For ranges that do not offer random access, `SearchPolicy.linear`
11466 is the only policy allowed (and it must be specified explicitly lest it exposes
11467 user code to unexpected inefficiencies). For random-access searches, all
11468 policies are allowed, and `SearchPolicy.binarySearch` is the default.
11469 */
11470     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11471     if (isTwoWayCompatible!(predFun, ElementType!Range, V))
11472     {
11473         static assert(hasSlicing!Range || sp == SearchPolicy.linear,
11474             "Specify SearchPolicy.linear explicitly for "
11475             ~ typeof(this).stringof);
11476         static if (sp == SearchPolicy.linear)
11477         {
11478             for (; !_input.empty && !predFun(value, _input.front);
11479                  _input.popFront())
11480             {
11481             }
11482             return this;
11483         }
11484         else
11485         {
11486             return this[getTransitionIndex!(sp, gt)(value) .. length];
11487         }
11488     }
11489 
11490     ///
11491     static if (is(Range : int[]))
11492     @safe unittest
11493     {
11494         import std.algorithm.comparison : equal;
11495         auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
11496         auto p = a.upperBound(3);
11497         assert(equal(p, [4, 4, 5, 6]));
11498     }
11499 
11500 
11501 // equalRange
11502 /**
11503    Returns the subrange containing all elements `e` for which both $(D
11504    pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11505    if `pred` is "less than", returns the portion of the range with
11506    elements equal to `value`). Uses a classic binary search with
11507    interval halving until it finds a value that satisfies the condition,
11508    then uses `SearchPolicy.gallopBackwards` to find the left boundary
11509    and `SearchPolicy.gallop` to find the right boundary. These
11510    policies are justified by the fact that the two boundaries are likely
11511    to be near the first found value (i.e., equal ranges are relatively
11512    small). Completes the entire search in $(BIGOH log(n)) time.
11513 */
11514     auto equalRange(V)(V value)
11515     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11516         && isRandomAccessRange!Range)
11517     {
11518         size_t first = 0, count = _input.length;
11519         while (count > 0)
11520         {
11521             immutable step = count / 2;
11522             auto it = first + step;
11523             if (predFun(_input[it], value))
11524             {
11525                 // Less than value, bump left bound up
11526                 first = it + 1;
11527                 count -= step + 1;
11528             }
11529             else if (predFun(value, _input[it]))
11530             {
11531                 // Greater than value, chop count
11532                 count = step;
11533             }
11534             else
11535             {
11536                 // Equal to value, do binary searches in the
11537                 // leftover portions
11538                 // Gallop towards the left end as it's likely nearby
11539                 immutable left = first
11540                     + this[first .. it]
11541                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11542                 first += count;
11543                 // Gallop towards the right end as it's likely nearby
11544                 immutable right = first
11545                     - this[it + 1 .. first]
11546                     .upperBound!(SearchPolicy.gallop)(value).length;
11547                 return this[left .. right];
11548             }
11549         }
11550         return this.init;
11551     }
11552 
11553     ///
11554     static if (is(Range : int[]))
11555     @safe unittest
11556     {
11557         import std.algorithm.comparison : equal;
11558         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11559         auto r = a.assumeSorted.equalRange(3);
11560         assert(equal(r, [ 3, 3, 3 ]));
11561     }
11562 
11563 // trisect
11564 /**
11565 Returns a tuple `r` such that `r[0]` is the same as the result
11566 of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11567 equalRange(value)), and `r[2]` is the same as the result of $(D
11568 upperBound(value)). The call is faster than computing all three
11569 separately. Uses a search schedule similar to $(D
11570 equalRange). Completes the entire search in $(BIGOH log(n)) time.
11571 */
11572     auto trisect(V)(V value)
11573     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11574         && isRandomAccessRange!Range && hasLength!Range)
11575     {
11576         import std.typecons : tuple;
11577         size_t first = 0, count = _input.length;
11578         while (count > 0)
11579         {
11580             immutable step = count / 2;
11581             auto it = first + step;
11582             if (predFun(_input[it], value))
11583             {
11584                 // Less than value, bump left bound up
11585                 first = it + 1;
11586                 count -= step + 1;
11587             }
11588             else if (predFun(value, _input[it]))
11589             {
11590                 // Greater than value, chop count
11591                 count = step;
11592             }
11593             else
11594             {
11595                 // Equal to value, do binary searches in the
11596                 // leftover portions
11597                 // Gallop towards the left end as it's likely nearby
11598                 immutable left = first
11599                     + this[first .. it]
11600                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11601                 first += count;
11602                 // Gallop towards the right end as it's likely nearby
11603                 immutable right = first
11604                     - this[it + 1 .. first]
11605                     .upperBound!(SearchPolicy.gallop)(value).length;
11606                 return tuple(this[0 .. left], this[left .. right],
11607                         this[right .. length]);
11608             }
11609         }
11610         // No equal element was found
11611         return tuple(this[0 .. first], this.init, this[first .. length]);
11612     }
11613 
11614     ///
11615     static if (is(Range : int[]))
11616     @safe unittest
11617     {
11618         import std.algorithm.comparison : equal;
11619         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11620         auto r = assumeSorted(a).trisect(3);
11621         assert(equal(r[0], [ 1, 2 ]));
11622         assert(equal(r[1], [ 3, 3, 3 ]));
11623         assert(equal(r[2], [ 4, 4, 5, 6 ]));
11624     }
11625 
11626 // contains
11627 /**
11628 Returns `true` if and only if `value` can be found in $(D
11629 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
11630 evaluations of `pred`.
11631  */
11632 
11633     bool contains(V)(V value)
11634     if (isRandomAccessRange!Range)
11635     {
11636         if (empty) return false;
11637         immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
11638         if (i >= length) return false;
11639         return !predFun(value, _input[i]);
11640     }
11641 
11642 /**
11643 Like `contains`, but the value is specified before the range.
11644 */
11645     bool opBinaryRight(string op, V)(V value)
11646     if (op == "in" && isRandomAccessRange!Range)
11647     {
11648         return contains(value);
11649     }
11650 
11651 // groupBy
11652 /**
11653 Returns a range of subranges of elements that are equivalent according to the
11654 sorting relation.
11655  */
11656     auto groupBy()()
11657     {
11658         import std.algorithm.iteration : chunkBy;
11659         return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
11660     }
11661 }
11662 
11663 /// ditto
11664 template SortedRange(Range, alias pred = "a < b",
11665                      SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11666 if (isInstanceOf!(SortedRange, Range))
11667 {
11668     // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
11669     alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
11670 }
11671 
11672 ///
11673 @safe unittest
11674 {
11675     import std.algorithm.sorting : sort;
11676     auto a = [ 1, 2, 3, 42, 52, 64 ];
11677     auto r = assumeSorted(a);
11678     assert(r.contains(3));
11679     assert(!(32 in r));
11680     auto r1 = sort!"a > b"(a);
11681     assert(3 in r1);
11682     assert(!r1.contains(32));
11683     assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
11684 }
11685 
11686 /**
11687 `SortedRange` could accept ranges weaker than random-access, but it
11688 is unable to provide interesting functionality for them. Therefore,
11689 `SortedRange` is currently restricted to random-access ranges.
11690 
11691 No copy of the original range is ever made. If the underlying range is
11692 changed concurrently with its corresponding `SortedRange` in ways
11693 that break its sorted-ness, `SortedRange` will work erratically.
11694 */
11695 @safe unittest
11696 {
11697     import std.algorithm.mutation : swap;
11698     auto a = [ 1, 2, 3, 42, 52, 64 ];
11699     auto r = assumeSorted(a);
11700     assert(r.contains(42));
11701     swap(a[3], a[5]);         // illegal to break sortedness of original range
11702     assert(!r.contains(42));  // passes although it shouldn't
11703 }
11704 
11705 /**
11706 `SortedRange` can be searched with predicates that do not take
11707 two elements of the underlying range as arguments.
11708 
11709 This is useful, if a range of structs is sorted by a member and you
11710 want to search in that range by only providing a value for that member.
11711 
11712 */
11713 @safe unittest
11714 {
11715     import std.algorithm.comparison : equal;
11716     static struct S { int i; }
11717     static bool byI(A, B)(A a, B b)
11718     {
11719         static if (is(A == S))
11720             return a.i < b;
11721         else
11722             return a < b.i;
11723     }
11724     auto r = assumeSorted!byI([S(1), S(2), S(3)]);
11725     auto lessThanTwo = r.lowerBound(2);
11726     assert(equal(lessThanTwo, [S(1)]));
11727 }
11728 
11729 @safe unittest
11730 {
11731     import std.exception : assertThrown, assertNotThrown;
11732 
11733     assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
11734     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
11735 
11736     // these two checks are implementation depended
11737     assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
11738     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
11739 }
11740 
11741 @safe unittest
11742 {
11743     import std.algorithm.comparison : equal;
11744 
11745     auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
11746     auto r = assumeSorted(a).trisect(30);
11747     assert(equal(r[0], [ 10, 20 ]));
11748     assert(equal(r[1], [ 30, 30, 30 ]));
11749     assert(equal(r[2], [ 40, 40, 50, 60 ]));
11750 
11751     r = assumeSorted(a).trisect(35);
11752     assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
11753     assert(r[1].empty);
11754     assert(equal(r[2], [ 40, 40, 50, 60 ]));
11755 }
11756 
11757 @safe unittest
11758 {
11759     import std.algorithm.comparison : equal;
11760     auto a = [ "A", "AG", "B", "E", "F" ];
11761     auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
11762     assert(equal(r[0], [ "A", "AG" ]));
11763     assert(equal(r[1], [ "B" ]));
11764     assert(equal(r[2], [ "E", "F" ]));
11765     r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
11766     assert(r[0].empty);
11767     assert(equal(r[1], [ "A" ]));
11768     assert(equal(r[2], [ "AG", "B", "E", "F" ]));
11769 }
11770 
11771 @safe unittest
11772 {
11773     import std.algorithm.comparison : equal;
11774     static void test(SearchPolicy pol)()
11775     {
11776         auto a = [ 1, 2, 3, 42, 52, 64 ];
11777         auto r = assumeSorted(a);
11778         assert(equal(r.lowerBound(42), [1, 2, 3]));
11779 
11780         assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
11781         assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
11782         assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
11783         assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
11784         assert(equal(r.lowerBound!(pol)(3), [1, 2]));
11785         assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
11786         assert(equal(r.lowerBound!(pol)(420), a));
11787         assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
11788 
11789         assert(equal(r.upperBound!(pol)(42), [52, 64]));
11790         assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
11791         assert(equal(r.upperBound!(pol)(43), [52, 64]));
11792         assert(equal(r.upperBound!(pol)(51), [52, 64]));
11793         assert(equal(r.upperBound!(pol)(53), [64]));
11794         assert(equal(r.upperBound!(pol)(55), [64]));
11795         assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
11796         assert(equal(r.upperBound!(pol)(0), a));
11797     }
11798 
11799     test!(SearchPolicy.trot)();
11800     test!(SearchPolicy.gallop)();
11801     test!(SearchPolicy.trotBackwards)();
11802     test!(SearchPolicy.gallopBackwards)();
11803     test!(SearchPolicy.binarySearch)();
11804 }
11805 
11806 @safe unittest
11807 {
11808     // Check for small arrays
11809     int[] a;
11810     auto r = assumeSorted(a);
11811     a = [ 1 ];
11812     r = assumeSorted(a);
11813     a = [ 1, 2 ];
11814     r = assumeSorted(a);
11815     a = [ 1, 2, 3 ];
11816     r = assumeSorted(a);
11817 }
11818 
11819 @safe unittest
11820 {
11821     import std.algorithm.mutation : swap;
11822     auto a = [ 1, 2, 3, 42, 52, 64 ];
11823     auto r = assumeSorted(a);
11824     assert(r.contains(42));
11825     swap(a[3], a[5]);                  // illegal to break sortedness of original range
11826     assert(!r.contains(42));            // passes although it shouldn't
11827 }
11828 
11829 @betterC @nogc nothrow @safe unittest
11830 {
11831     static immutable(int)[] arr = [ 1, 2, 3 ];
11832     auto s = assumeSorted(arr);
11833 }
11834 
11835 @system unittest
11836 {
11837     import std.algorithm.comparison : equal;
11838     int[] arr = [100, 101, 102, 200, 201, 300];
11839     auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
11840     assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
11841 }
11842 
11843 // Test on an input range
11844 @system unittest
11845 {
11846     import std.conv : text;
11847     import std.file : exists, remove, tempDir;
11848     import std.path : buildPath;
11849     import std.stdio : File;
11850     import std.uuid : randomUUID;
11851     auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
11852                           "." ~ randomUUID().toString());
11853     auto f = File(name, "w");
11854     scope(exit) if (exists(name)) remove(name);
11855     // write a sorted range of lines to the file
11856     f.write("abc\ndef\nghi\njkl");
11857     f.close();
11858     f.open(name, "r");
11859     auto r = assumeSorted(f.byLine());
11860     auto r1 = r.upperBound!(SearchPolicy.linear)("def");
11861     assert(r1.front == "ghi", r1.front);
11862     f.close();
11863 }
11864 
11865 // https://issues.dlang.org/show_bug.cgi?id=19337
11866 @safe unittest
11867 {
11868     import std.algorithm.sorting : sort;
11869     auto a = [ 1, 2, 3, 42, 52, 64 ];
11870     a.sort.sort!"a > b";
11871 }
11872 
11873 /**
11874 Assumes `r` is sorted by predicate `pred` and returns the
11875 corresponding $(D SortedRange!(pred, R)) having `r` as support.
11876 To check for sorted-ness at
11877 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
11878  */
11879 auto assumeSorted(alias pred = "a < b", R)(R r)
11880 if (isInputRange!(Unqual!R))
11881 {
11882     // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
11883     static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
11884     {
11885         static if (isInputRange!R && __traits(isSame, pred, RPred))
11886             // If the predicate is the same and we don't need to cast away
11887             // constness for the result to be an input range.
11888             return r;
11889         else
11890             return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
11891     }
11892     else
11893     {
11894         return SortedRange!(Unqual!R, pred)(r);
11895     }
11896 }
11897 
11898 ///
11899 @safe unittest
11900 {
11901     import std.algorithm.comparison : equal;
11902 
11903     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
11904     auto p = assumeSorted(a);
11905 
11906     assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
11907     assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
11908     assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
11909     assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
11910 }
11911 
11912 @safe unittest
11913 {
11914     import std.algorithm.comparison : equal;
11915     static assert(isRandomAccessRange!(SortedRange!(int[])));
11916     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11917     auto p = assumeSorted(a).upperBound(3);
11918     assert(equal(p, [4, 4, 5, 6 ]));
11919     p = assumeSorted(a).upperBound(4.2);
11920     assert(equal(p, [ 5, 6 ]));
11921 
11922     // https://issues.dlang.org/show_bug.cgi?id=18933
11923     // don't create senselessly nested SortedRange types.
11924     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
11925     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
11926 }
11927 
11928 @safe unittest
11929 {
11930     import std.algorithm.comparison : equal;
11931     import std.conv : text;
11932 
11933     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11934     auto p = assumeSorted(a).equalRange(3);
11935     assert(equal(p, [ 3, 3, 3 ]), text(p));
11936     p = assumeSorted(a).equalRange(4);
11937     assert(equal(p, [ 4, 4 ]), text(p));
11938     p = assumeSorted(a).equalRange(2);
11939     assert(equal(p, [ 2 ]));
11940     p = assumeSorted(a).equalRange(0);
11941     assert(p.empty);
11942     p = assumeSorted(a).equalRange(7);
11943     assert(p.empty);
11944     p = assumeSorted(a).equalRange(3.0);
11945     assert(equal(p, [ 3, 3, 3]));
11946 }
11947 
11948 @safe unittest
11949 {
11950     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11951     if (a.length)
11952     {
11953         auto b = a[a.length / 2];
11954         //auto r = sort(a);
11955         //assert(r.contains(b));
11956     }
11957 }
11958 
11959 @safe unittest
11960 {
11961     auto a = [ 5, 7, 34, 345, 677 ];
11962     auto r = assumeSorted(a);
11963     a = null;
11964     r = assumeSorted(a);
11965     a = [ 1 ];
11966     r = assumeSorted(a);
11967 }
11968 
11969 // https://issues.dlang.org/show_bug.cgi?id=15003
11970 @nogc @safe unittest
11971 {
11972     static immutable a = [1, 2, 3, 4];
11973     auto r = a.assumeSorted;
11974 }
11975 
11976 /++
11977     Wrapper which effectively makes it possible to pass a range by reference.
11978     Both the original range and the RefRange will always have the exact same
11979     elements. Any operation done on one will affect the other. So, for instance,
11980     if it's passed to a function which would implicitly copy the original range
11981     if it were passed to it, the original range is $(I not) copied but is
11982     consumed as if it were a reference type.
11983 
11984     Note:
11985         `save` works as normal and operates on a new range, so if
11986         `save` is ever called on the `RefRange`, then no operations on the
11987         saved range will affect the original.
11988 
11989     Params:
11990         range = the range to construct the `RefRange` from
11991 
11992     Returns:
11993         A `RefRange`. If the given range is a class type
11994         (and thus is already a reference type), then the original
11995         range is returned rather than a `RefRange`.
11996   +/
11997 struct RefRange(R)
11998 if (isInputRange!R)
11999 {
12000 public:
12001 
12002     /++ +/
12003     this(R* range) @safe pure nothrow
12004     {
12005         _range = range;
12006     }
12007 
12008 
12009     /++
12010         This does not assign the pointer of `rhs` to this `RefRange`.
12011         Rather it assigns the range pointed to by `rhs` to the range pointed
12012         to by this `RefRange`. This is because $(I any) operation on a
12013         `RefRange` is the same is if it occurred to the original range. The
12014         one exception is when a `RefRange` is assigned `null` either
12015         directly or because `rhs` is `null`. In that case, `RefRange`
12016         no longer refers to the original range but is `null`.
12017       +/
12018     auto opAssign(RefRange rhs)
12019     {
12020         if (_range && rhs._range)
12021             *_range = *rhs._range;
12022         else
12023             _range = rhs._range;
12024 
12025         return this;
12026     }
12027 
12028     /++ +/
12029     void opAssign(typeof(null) rhs)
12030     {
12031         _range = null;
12032     }
12033 
12034 
12035     /++
12036         A pointer to the wrapped range.
12037       +/
12038     @property inout(R*) ptr() @safe inout pure nothrow
12039     {
12040         return _range;
12041     }
12042 
12043 
12044     version (StdDdoc)
12045     {
12046         /++ +/
12047         @property auto front() {assert(0);}
12048         /++ Ditto +/
12049         @property auto front() const {assert(0);}
12050         /++ Ditto +/
12051         @property auto front(ElementType!R value) {assert(0);}
12052     }
12053     else
12054     {
12055         @property auto front()
12056         {
12057             return (*_range).front;
12058         }
12059 
12060         static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
12061         {
12062             return (*_range).front;
12063         }
12064 
12065         static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
12066         {
12067             return (*_range).front = value;
12068         }
12069     }
12070 
12071 
12072     version (StdDdoc)
12073     {
12074         @property bool empty(); ///
12075         @property bool empty() const; ///Ditto
12076     }
12077     else static if (isInfinite!R)
12078         enum empty = false;
12079     else
12080     {
12081         @property bool empty()
12082         {
12083             return (*_range).empty;
12084         }
12085 
12086         static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
12087         {
12088             return (*_range).empty;
12089         }
12090     }
12091 
12092 
12093     /++ +/
12094     void popFront()
12095     {
12096         return (*_range).popFront();
12097     }
12098 
12099 
12100     version (StdDdoc)
12101     {
12102         /++
12103             Only defined if `isForwardRange!R` is `true`.
12104           +/
12105         @property auto save() {assert(0);}
12106         /++ Ditto +/
12107         @property auto save() const {assert(0);}
12108         /++ Ditto +/
12109         auto opSlice() {assert(0);}
12110         /++ Ditto +/
12111         auto opSlice() const {assert(0);}
12112     }
12113     else static if (isForwardRange!R)
12114     {
12115         import std.traits : isSafe;
12116         private alias S = typeof((*_range).save);
12117 
12118         static if (is(typeof((*cast(const R*)_range).save)))
12119             private alias CS = typeof((*cast(const R*)_range).save);
12120 
12121         static if (isSafe!((R* r) => (*r).save))
12122         {
12123             @property RefRange!S save() @trusted
12124             {
12125                 mixin(_genSave());
12126             }
12127 
12128             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
12129             {
12130                 mixin(_genSave());
12131             }
12132         }
12133         else
12134         {
12135             @property RefRange!S save()
12136             {
12137                 mixin(_genSave());
12138             }
12139 
12140             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
12141             {
12142                 mixin(_genSave());
12143             }
12144         }
12145 
12146         auto opSlice()()
12147         {
12148             return save;
12149         }
12150 
12151         auto opSlice()() const
12152         {
12153             return save;
12154         }
12155 
12156         private static string _genSave() @safe pure nothrow
12157         {
12158             return `import core.lifetime : emplace;` ~
12159                    `alias S = typeof((*_range).save);` ~
12160                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
12161                    `auto mem = new void[S.sizeof];` ~
12162                    `emplace!S(mem, cast(S)(*_range).save);` ~
12163                    `return RefRange!S(cast(S*) mem.ptr);`;
12164         }
12165 
12166         static assert(isForwardRange!RefRange);
12167     }
12168 
12169 
12170     version (StdDdoc)
12171     {
12172         /++
12173             Only defined if `isBidirectionalRange!R` is `true`.
12174           +/
12175         @property auto back() {assert(0);}
12176         /++ Ditto +/
12177         @property auto back() const {assert(0);}
12178         /++ Ditto +/
12179         @property auto back(ElementType!R value) {assert(0);}
12180     }
12181     else static if (isBidirectionalRange!R)
12182     {
12183         @property auto back()
12184         {
12185             return (*_range).back;
12186         }
12187 
12188         static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
12189         {
12190             return (*_range).back;
12191         }
12192 
12193         static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
12194         {
12195             return (*_range).back = value;
12196         }
12197     }
12198 
12199 
12200     /++ Ditto +/
12201     static if (isBidirectionalRange!R) void popBack()
12202     {
12203         return (*_range).popBack();
12204     }
12205 
12206 
12207     version (StdDdoc)
12208     {
12209         /++
12210             Only defined if `isRandomAccessRange!R` is `true`.
12211           +/
12212         auto ref opIndex(IndexType)(IndexType index) {assert(0);}
12213 
12214         /++ Ditto +/
12215         auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
12216     }
12217     else static if (isRandomAccessRange!R)
12218     {
12219         auto ref opIndex(IndexType)(IndexType index)
12220             if (is(typeof((*_range)[index])))
12221         {
12222             return (*_range)[index];
12223         }
12224 
12225         auto ref opIndex(IndexType)(IndexType index) const
12226             if (is(typeof((*cast(const R*)_range)[index])))
12227         {
12228             return (*_range)[index];
12229         }
12230     }
12231 
12232 
12233     /++
12234         Only defined if `hasMobileElements!R` and `isForwardRange!R` are
12235         `true`.
12236       +/
12237     static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
12238     {
12239         return (*_range).moveFront();
12240     }
12241 
12242 
12243     /++
12244         Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
12245         are `true`.
12246       +/
12247     static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
12248     {
12249         return (*_range).moveBack();
12250     }
12251 
12252 
12253     /++
12254         Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
12255         are `true`.
12256       +/
12257     static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
12258     {
12259         return (*_range).moveAt(index);
12260     }
12261 
12262 
12263     version (StdDdoc)
12264     {
12265         /// Only defined if `hasLength!R` is `true`.
12266         @property size_t length();
12267         /// ditto
12268         @property size_t length() const;
12269         /// Ditto
12270         alias opDollar = length;
12271     }
12272     else static if (hasLength!R)
12273     {
12274         @property auto length()
12275         {
12276             return (*_range).length;
12277         }
12278         static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
12279         {
12280             return (*_range).length;
12281         }
12282         alias opDollar = length;
12283     }
12284 
12285 
12286     version (StdDdoc)
12287     {
12288         /++
12289             Only defined if `hasSlicing!R` is `true`.
12290           +/
12291         auto opSlice(IndexType1, IndexType2)
12292                     (IndexType1 begin, IndexType2 end) {assert(0);}
12293 
12294         /++ Ditto +/
12295         auto opSlice(IndexType1, IndexType2)
12296                     (IndexType1 begin, IndexType2 end) const {assert(0);}
12297     }
12298     else static if (hasSlicing!R)
12299     {
12300         private alias T = typeof((*_range)[1 .. 2]);
12301         static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
12302         {
12303             private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
12304         }
12305 
12306         RefRange!T opSlice(IndexType1, IndexType2)
12307                     (IndexType1 begin, IndexType2 end)
12308             if (is(typeof((*_range)[begin .. end])))
12309         {
12310             mixin(_genOpSlice());
12311         }
12312 
12313         RefRange!CT opSlice(IndexType1, IndexType2)
12314                     (IndexType1 begin, IndexType2 end) const
12315             if (is(typeof((*cast(const R*)_range)[begin .. end])))
12316         {
12317             mixin(_genOpSlice());
12318         }
12319 
12320         private static string _genOpSlice() @safe pure nothrow
12321         {
12322             return `import core.lifetime : emplace;` ~
12323                    `alias S = typeof((*_range)[begin .. end]);` ~
12324                    `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
12325                    `auto mem = new void[S.sizeof];` ~
12326                    `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
12327                    `return RefRange!S(cast(S*) mem.ptr);`;
12328         }
12329     }
12330 
12331 
12332 private:
12333 
12334     R* _range;
12335 }
12336 
12337 /// Basic Example
12338 @system unittest
12339 {
12340     import std.algorithm.searching : find;
12341     ubyte[] buffer = [1, 9, 45, 12, 22];
12342     auto found1 = find(buffer, 45);
12343     assert(found1 == [45, 12, 22]);
12344     assert(buffer == [1, 9, 45, 12, 22]);
12345 
12346     auto wrapped1 = refRange(&buffer);
12347     auto found2 = find(wrapped1, 45);
12348     assert(*found2.ptr == [45, 12, 22]);
12349     assert(buffer == [45, 12, 22]);
12350 
12351     auto found3 = find(wrapped1.save, 22);
12352     assert(*found3.ptr == [22]);
12353     assert(buffer == [45, 12, 22]);
12354 
12355     string str = "hello world";
12356     auto wrappedStr = refRange(&str);
12357     assert(str.front == 'h');
12358     str.popFrontN(5);
12359     assert(str == " world");
12360     assert(wrappedStr.front == ' ');
12361     assert(*wrappedStr.ptr == " world");
12362 }
12363 
12364 /// opAssign Example.
12365 @system unittest
12366 {
12367     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12368     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12369     auto wrapped1 = refRange(&buffer1);
12370     auto wrapped2 = refRange(&buffer2);
12371     assert(wrapped1.ptr is &buffer1);
12372     assert(wrapped2.ptr is &buffer2);
12373     assert(wrapped1.ptr !is wrapped2.ptr);
12374     assert(buffer1 != buffer2);
12375 
12376     wrapped1 = wrapped2;
12377 
12378     //Everything points to the same stuff as before.
12379     assert(wrapped1.ptr is &buffer1);
12380     assert(wrapped2.ptr is &buffer2);
12381     assert(wrapped1.ptr !is wrapped2.ptr);
12382 
12383     //But buffer1 has changed due to the assignment.
12384     assert(buffer1 == [6, 7, 8, 9, 10]);
12385     assert(buffer2 == [6, 7, 8, 9, 10]);
12386 
12387     buffer2 = [11, 12, 13, 14, 15];
12388 
12389     //Everything points to the same stuff as before.
12390     assert(wrapped1.ptr is &buffer1);
12391     assert(wrapped2.ptr is &buffer2);
12392     assert(wrapped1.ptr !is wrapped2.ptr);
12393 
12394     //But buffer2 has changed due to the assignment.
12395     assert(buffer1 == [6, 7, 8, 9, 10]);
12396     assert(buffer2 == [11, 12, 13, 14, 15]);
12397 
12398     wrapped2 = null;
12399 
12400     //The pointer changed for wrapped2 but not wrapped1.
12401     assert(wrapped1.ptr is &buffer1);
12402     assert(wrapped2.ptr is null);
12403     assert(wrapped1.ptr !is wrapped2.ptr);
12404 
12405     //buffer2 is not affected by the assignment.
12406     assert(buffer1 == [6, 7, 8, 9, 10]);
12407     assert(buffer2 == [11, 12, 13, 14, 15]);
12408 }
12409 
12410 @system unittest
12411 {
12412     import std.algorithm.iteration : filter;
12413     {
12414         ubyte[] buffer = [1, 2, 3, 4, 5];
12415         auto wrapper = refRange(&buffer);
12416         auto p = wrapper.ptr;
12417         auto f = wrapper.front;
12418         wrapper.front = f;
12419         auto e = wrapper.empty;
12420         wrapper.popFront();
12421         auto s = wrapper.save;
12422         auto b = wrapper.back;
12423         wrapper.back = b;
12424         wrapper.popBack();
12425         auto i = wrapper[0];
12426         wrapper.moveFront();
12427         wrapper.moveBack();
12428         wrapper.moveAt(0);
12429         auto l = wrapper.length;
12430         auto sl = wrapper[0 .. 1];
12431         assert(wrapper[0 .. $].length == buffer[0 .. $].length);
12432     }
12433 
12434     {
12435         ubyte[] buffer = [1, 2, 3, 4, 5];
12436         const wrapper = refRange(&buffer);
12437         const p = wrapper.ptr;
12438         const f = wrapper.front;
12439         const e = wrapper.empty;
12440         const s = wrapper.save;
12441         const b = wrapper.back;
12442         const i = wrapper[0];
12443         const l = wrapper.length;
12444         const sl = wrapper[0 .. 1];
12445     }
12446 
12447     {
12448         ubyte[] buffer = [1, 2, 3, 4, 5];
12449         auto filtered = filter!"true"(buffer);
12450         auto wrapper = refRange(&filtered);
12451         auto p = wrapper.ptr;
12452         auto f = wrapper.front;
12453         wrapper.front = f;
12454         auto e = wrapper.empty;
12455         wrapper.popFront();
12456         auto s = wrapper.save;
12457         wrapper.moveFront();
12458     }
12459 
12460     {
12461         ubyte[] buffer = [1, 2, 3, 4, 5];
12462         auto filtered = filter!"true"(buffer);
12463         const wrapper = refRange(&filtered);
12464         const p = wrapper.ptr;
12465 
12466         //Cannot currently be const. filter needs to be updated to handle const.
12467         /+
12468         const f = wrapper.front;
12469         const e = wrapper.empty;
12470         const s = wrapper.save;
12471         +/
12472     }
12473 
12474     {
12475         string str = "hello world";
12476         auto wrapper = refRange(&str);
12477         auto p = wrapper.ptr;
12478         auto f = wrapper.front;
12479         auto e = wrapper.empty;
12480         wrapper.popFront();
12481         auto s = wrapper.save;
12482         auto b = wrapper.back;
12483         wrapper.popBack();
12484     }
12485 
12486     {
12487         // https://issues.dlang.org/show_bug.cgi?id=16534
12488         // opDollar should be defined if the wrapped range defines length.
12489         auto range = 10.iota.takeExactly(5);
12490         auto wrapper = refRange(&range);
12491         assert(wrapper.length == 5);
12492         assert(wrapper[0 .. $ - 1].length == 4);
12493     }
12494 }
12495 
12496 //Test assignment.
12497 @system unittest
12498 {
12499     ubyte[] buffer1 = [1, 2, 3, 4, 5];
12500     ubyte[] buffer2 = [6, 7, 8, 9, 10];
12501     RefRange!(ubyte[]) wrapper1;
12502     RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
12503     assert(wrapper1.ptr is null);
12504     assert(wrapper2.ptr is &buffer2);
12505 
12506     wrapper1 = refRange(&buffer1);
12507     assert(wrapper1.ptr is &buffer1);
12508 
12509     wrapper1 = wrapper2;
12510     assert(wrapper1.ptr is &buffer1);
12511     assert(buffer1 == buffer2);
12512 
12513     wrapper1 = RefRange!(ubyte[]).init;
12514     assert(wrapper1.ptr is null);
12515     assert(wrapper2.ptr is &buffer2);
12516     assert(buffer1 == buffer2);
12517     assert(buffer1 == [6, 7, 8, 9, 10]);
12518 
12519     wrapper2 = null;
12520     assert(wrapper2.ptr is null);
12521     assert(buffer2 == [6, 7, 8, 9, 10]);
12522 }
12523 
12524 @system unittest
12525 {
12526     import std.algorithm.comparison : equal;
12527     import std.algorithm.mutation : bringToFront;
12528     import std.algorithm.searching : commonPrefix, find, until;
12529     import std.algorithm.sorting : sort;
12530 
12531     //Test that ranges are properly consumed.
12532     {
12533         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12534         auto wrapper = refRange(&arr);
12535 
12536         assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12537         assert(arr == [41, 3, 40, 4, 42, 9]);
12538 
12539         assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12540         assert(arr == [40, 4, 42, 9]);
12541 
12542         assert(equal(until(wrapper, 42), [40, 4]));
12543         assert(arr == [42, 9]);
12544 
12545         assert(find(wrapper, 12).empty);
12546         assert(arr.empty);
12547     }
12548 
12549     {
12550         string str = "Hello, world-like object.";
12551         auto wrapper = refRange(&str);
12552 
12553         assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12554         assert(str == "llo, world-like object.");
12555 
12556         assert(equal(take(wrapper, 5), "llo, "));
12557         assert(str == "world-like object.");
12558     }
12559 
12560     //Test that operating on saved ranges does not consume the original.
12561     {
12562         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12563         auto wrapper = refRange(&arr);
12564         auto saved = wrapper.save;
12565         saved.popFrontN(3);
12566         assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12567         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12568     }
12569 
12570     {
12571         string str = "Hello, world-like object.";
12572         auto wrapper = refRange(&str);
12573         auto saved = wrapper.save;
12574         saved.popFrontN(13);
12575         assert(*saved.ptr == "like object.");
12576         assert(str == "Hello, world-like object.");
12577     }
12578 
12579     //Test that functions which use save work properly.
12580     {
12581         int[] arr = [1, 42];
12582         auto wrapper = refRange(&arr);
12583         assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12584     }
12585 
12586     {
12587         int[] arr = [4, 5, 6, 7, 1, 2, 3];
12588         auto wrapper = refRange(&arr);
12589         assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12590         assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12591     }
12592 
12593     //Test bidirectional functions.
12594     {
12595         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12596         auto wrapper = refRange(&arr);
12597 
12598         assert(wrapper.back == 9);
12599         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12600 
12601         wrapper.popBack();
12602         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12603     }
12604 
12605     {
12606         string str = "Hello, world-like object.";
12607         auto wrapper = refRange(&str);
12608 
12609         assert(wrapper.back == '.');
12610         assert(str == "Hello, world-like object.");
12611 
12612         wrapper.popBack();
12613         assert(str == "Hello, world-like object");
12614     }
12615 
12616     //Test random access functions.
12617     {
12618         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12619         auto wrapper = refRange(&arr);
12620 
12621         assert(wrapper[2] == 2);
12622         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12623 
12624         assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
12625         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12626     }
12627 
12628     //Test move functions.
12629     {
12630         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12631         auto wrapper = refRange(&arr);
12632 
12633         auto t1 = wrapper.moveFront();
12634         auto t2 = wrapper.moveBack();
12635         wrapper.front = t2;
12636         wrapper.back = t1;
12637         assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
12638 
12639         sort(wrapper.save);
12640         assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
12641     }
12642 }
12643 
12644 @system unittest
12645 {
12646     struct S
12647     {
12648         @property int front() @safe const pure nothrow { return 0; }
12649         enum bool empty = false;
12650         void popFront() @safe pure nothrow { }
12651         @property auto save() @safe pure nothrow return scope { return this; }
12652     }
12653 
12654     S s;
12655     auto wrapper = refRange(&s);
12656     static assert(isInfinite!(typeof(wrapper)));
12657 }
12658 
12659 @system unittest
12660 {
12661     class C
12662     {
12663         @property int front() @safe const pure nothrow { return 0; }
12664         @property bool empty() @safe const pure nothrow { return false; }
12665         void popFront() @safe pure nothrow { }
12666         @property auto save() @safe pure nothrow return scope { return this; }
12667     }
12668     static assert(isForwardRange!C);
12669 
12670     auto c = new C;
12671     auto cWrapper = refRange(&c);
12672     static assert(is(typeof(cWrapper) == C));
12673     assert(cWrapper is c);
12674 }
12675 
12676 // https://issues.dlang.org/show_bug.cgi?id=14373
12677 @system unittest
12678 {
12679     static struct R
12680     {
12681         @property int front() {return 0;}
12682         void popFront() {empty = true;}
12683         bool empty = false;
12684     }
12685     R r;
12686     refRange(&r).popFront();
12687     assert(r.empty);
12688 }
12689 
12690 // https://issues.dlang.org/show_bug.cgi?id=14575
12691 @system unittest
12692 {
12693     struct R
12694     {
12695         Object front;
12696         alias back = front;
12697         bool empty = false;
12698         void popFront() {empty = true;}
12699         alias popBack = popFront;
12700         @property R save() {return this;}
12701     }
12702     static assert(isBidirectionalRange!R);
12703     R r;
12704     auto rr = refRange(&r);
12705 
12706     struct R2
12707     {
12708         @property Object front() {return null;}
12709         @property const(Object) front() const {return null;}
12710         alias back = front;
12711         bool empty = false;
12712         void popFront() {empty = true;}
12713         alias popBack = popFront;
12714         @property R2 save() {return this;}
12715     }
12716     static assert(isBidirectionalRange!R2);
12717     R2 r2;
12718     auto rr2 = refRange(&r2);
12719 }
12720 
12721 /// ditto
12722 auto refRange(R)(R* range)
12723 if (isInputRange!R)
12724 {
12725     static if (!is(R == class))
12726         return RefRange!R(range);
12727     else
12728         return *range;
12729 }
12730 
12731 // https://issues.dlang.org/show_bug.cgi?id=9060
12732 @safe unittest
12733 {
12734     import std.algorithm.iteration : map, joiner, group;
12735     import std.algorithm.searching : until;
12736     // fix for std.algorithm
12737     auto r = map!(x => 0)([1]);
12738     chain(r, r);
12739     zip(r, r);
12740     roundRobin(r, r);
12741 
12742     struct NRAR {
12743         typeof(r) input;
12744         @property empty() { return input.empty; }
12745         @property front() { return input.front; }
12746         void popFront()   { input.popFront(); }
12747         @property save()  { return NRAR(input.save); }
12748     }
12749     auto n1 = NRAR(r);
12750     cycle(n1);  // non random access range version
12751 
12752     assumeSorted(r);
12753 
12754     // fix for std.range
12755     joiner([r], [9]);
12756 
12757     struct NRAR2 {
12758         NRAR input;
12759         @property empty() { return true; }
12760         @property front() { return input; }
12761         void popFront() { }
12762         @property save()  { return NRAR2(input.save); }
12763     }
12764     auto n2 = NRAR2(n1);
12765     joiner(n2);
12766 
12767     group(r);
12768 
12769     until(r, 7);
12770     static void foo(R)(R r) { until!(x => x > 7)(r); }
12771     foo(r);
12772 }
12773 
12774 private struct Bitwise(R)
12775 if (isInputRange!R && isIntegral!(ElementType!R))
12776 {
12777     import std.traits : Unsigned;
12778 private:
12779     alias ElemType = ElementType!R;
12780     alias UnsignedElemType = Unsigned!ElemType;
12781 
12782     R parent;
12783     enum bitsNum = ElemType.sizeof * 8;
12784     size_t maskPos = 1;
12785 
12786     static if (isBidirectionalRange!R)
12787     {
12788         size_t backMaskPos = bitsNum;
12789     }
12790 
12791 public:
12792     this()(auto ref R range)
12793     {
12794         parent = range;
12795     }
12796 
12797     static if (isInfinite!R)
12798     {
12799         enum empty = false;
12800     }
12801     else
12802     {
12803         /**
12804          * Check if the range is empty
12805          *
12806          * Returns: a boolean true or false
12807          */
12808         bool empty()
12809         {
12810             static if (hasLength!R)
12811             {
12812                 return length == 0;
12813             }
12814             else static if (isBidirectionalRange!R)
12815             {
12816                 if (parent.empty)
12817                 {
12818                     return true;
12819                 }
12820                 else
12821                 {
12822                     /*
12823                        If we have consumed the last element of the range both from
12824                        the front and the back, then the masks positions will overlap
12825                      */
12826                     return parent.save.dropOne.empty && (maskPos > backMaskPos);
12827                 }
12828             }
12829             else
12830             {
12831                 /*
12832                    If we consumed the last element of the range, but not all the
12833                    bits in the last element
12834                  */
12835                 return parent.empty;
12836             }
12837         }
12838     }
12839 
12840     bool front()
12841     {
12842         assert(!empty);
12843         return (parent.front & mask(maskPos)) != 0;
12844     }
12845 
12846     void popFront()
12847     {
12848         assert(!empty);
12849         ++maskPos;
12850         if (maskPos > bitsNum)
12851         {
12852             parent.popFront;
12853             maskPos = 1;
12854         }
12855     }
12856 
12857     static if (hasLength!R)
12858     {
12859         size_t length()
12860         {
12861             auto len = parent.length * bitsNum - (maskPos - 1);
12862             static if (isBidirectionalRange!R)
12863             {
12864                 len -= bitsNum - backMaskPos;
12865             }
12866             return len;
12867         }
12868 
12869         alias opDollar = length;
12870     }
12871 
12872     static if (isForwardRange!R)
12873     {
12874         typeof(this) save()
12875         {
12876             auto result = this;
12877             result.parent = parent.save;
12878             return result;
12879         }
12880     }
12881 
12882     static if (isBidirectionalRange!R)
12883     {
12884         bool back()
12885         {
12886             assert(!empty);
12887             return (parent.back & mask(backMaskPos)) != 0;
12888         }
12889 
12890         void popBack()
12891         {
12892             assert(!empty);
12893             --backMaskPos;
12894             if (backMaskPos == 0)
12895             {
12896                 parent.popBack;
12897                 backMaskPos = bitsNum;
12898             }
12899         }
12900     }
12901 
12902     static if (isRandomAccessRange!R)
12903     {
12904         /**
12905           Return the `n`th bit within the range
12906          */
12907         bool opIndex(size_t n)
12908         in
12909         {
12910             /*
12911                If it does not have the length property, it means that R is
12912                an infinite range
12913              */
12914             static if (hasLength!R)
12915             {
12916                 assert(n < length, "Index out of bounds");
12917             }
12918         }
12919         do
12920         {
12921             immutable size_t remainingBits = bitsNum - maskPos + 1;
12922             // If n >= maskPos, then the bit sign will be 1, otherwise 0
12923             immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12924             /*
12925                By truncating n with remainingBits bits we have skipped the
12926                remaining bits in parent[0], so we need to add 1 to elemIndex.
12927 
12928                Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
12929              */
12930             import core.bitop : bsf;
12931             immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12932 
12933             /*
12934                Since the indexing is from LSB to MSB, we need to index at the
12935                remainder of (n - remainingBits).
12936 
12937                Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
12938              */
12939             immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12940                              + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12941 
12942             return (parent[elemIndex] & mask(elemMaskPos)) != 0;
12943         }
12944 
12945         static if (hasAssignableElements!R)
12946         {
12947             /**
12948               Assigns `flag` to the `n`th bit within the range
12949              */
12950             void opIndexAssign(bool flag, size_t n)
12951                 in
12952                 {
12953                     static if (hasLength!R)
12954                     {
12955                         assert(n < length, "Index out of bounds");
12956                     }
12957                 }
12958             do
12959             {
12960                 import core.bitop : bsf;
12961 
12962                 immutable size_t remainingBits = bitsNum - maskPos + 1;
12963                 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12964                 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12965                 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12966                     + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12967 
12968                 auto elem = parent[elemIndex];
12969                 auto elemMask = mask(elemMaskPos);
12970                 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
12971                         + (flag ^ 1) * (elem & ~elemMask));
12972             }
12973         }
12974 
12975         Bitwise!R opSlice()
12976         {
12977             return this.save;
12978         }
12979 
12980         Bitwise!R opSlice(size_t start, size_t end)
12981         in
12982         {
12983             assert(start < end, "Invalid bounds: end <= start");
12984         }
12985         do
12986         {
12987             import core.bitop : bsf;
12988 
12989             size_t remainingBits = bitsNum - maskPos + 1;
12990             ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12991             immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
12992             immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
12993                                               + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
12994 
12995             immutable size_t sliceLen = end - start - 1;
12996             remainingBits = bitsNum - startElemMaskPos + 1;
12997             sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12998             immutable size_t endElemIndex = startElemIndex
12999                                           + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
13000             immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
13001                                             + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
13002 
13003             typeof(return) result;
13004             // Get the slice to be returned from the parent
13005             result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
13006             result.maskPos = startElemMaskPos;
13007             static if (isBidirectionalRange!R)
13008             {
13009                 result.backMaskPos = endElemMaskPos;
13010             }
13011             return result;
13012         }
13013     }
13014 
13015 private:
13016     auto mask(size_t maskPos)
13017     {
13018         return (1UL << (maskPos - 1UL));
13019     }
13020 }
13021 
13022 /**
13023 Bitwise adapter over an integral type range. Consumes the range elements bit by
13024 bit, from the least significant bit to the most significant bit.
13025 
13026 Params:
13027     R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
13028     range = range to consume bit by by
13029 
13030 Returns:
13031     A `Bitwise` input range with propagated forward, bidirectional
13032     and random access capabilities
13033 */
13034 auto bitwise(R)(auto ref R range)
13035 if (isInputRange!R && isIntegral!(ElementType!R))
13036 {
13037     return Bitwise!R(range);
13038 }
13039 
13040 ///
13041 @safe pure unittest
13042 {
13043     import std.algorithm.comparison : equal;
13044     import std.format : format;
13045 
13046     // 00000011 00001001
13047     ubyte[] arr = [3, 9];
13048     auto r = arr.bitwise;
13049 
13050     // iterate through it as with any other range
13051     assert(format("%(%d%)", r) == "1100000010010000");
13052     assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
13053 
13054     auto r2 = r[5 .. $];
13055     // set a bit
13056     r[2] = 1;
13057     assert(arr[0] == 7);
13058     assert(r[5] == r2[0]);
13059 }
13060 
13061 /// You can use bitwise to implement an uniform bool generator
13062 @safe unittest
13063 {
13064     import std.algorithm.comparison : equal;
13065     import std.random : rndGen;
13066 
13067     auto rb = rndGen.bitwise;
13068     static assert(isInfinite!(typeof(rb)));
13069 
13070     auto rb2 = rndGen.bitwise;
13071     // Don't forget that structs are passed by value
13072     assert(rb.take(10).equal(rb2.take(10)));
13073 }
13074 
13075 // Test nogc inference
13076 @safe @nogc unittest
13077 {
13078     static ubyte[] arr = [3, 9];
13079     auto bw = arr.bitwise;
13080     auto bw2 = bw[];
13081     auto bw3 = bw[8 .. $];
13082     bw3[2] = true;
13083 
13084     assert(arr[1] == 13);
13085     assert(bw[$ - 6]);
13086     assert(bw[$ - 6] == bw2[$ - 6]);
13087     assert(bw[$ - 6] == bw3[$ - 6]);
13088 }
13089 
13090 // Test all range types over all integral types
13091 @safe pure nothrow unittest
13092 {
13093     import std.meta : AliasSeq;
13094     import std.internal.test.dummyrange;
13095 
13096     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13097             long, ulong);
13098     foreach (IntegralType; IntegralTypes)
13099     {
13100         foreach (T; AllDummyRangesType!(IntegralType[]))
13101         {
13102             T a;
13103             auto bw = Bitwise!T(a);
13104 
13105             static if (isForwardRange!T)
13106             {
13107                 auto bwFwdSave = bw.save;
13108             }
13109 
13110             static if (isBidirectionalRange!T)
13111             {
13112                 auto bwBack = bw.save;
13113                 auto bwBackSave = bw.save;
13114             }
13115 
13116             static if (hasLength!T)
13117             {
13118                 auto bwLength = bw.length;
13119                 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
13120                 static if (isForwardRange!T)
13121                 {
13122                     assert(bw.length == bwFwdSave.length);
13123                 }
13124             }
13125 
13126             // Make sure front and back are not the mechanisms that modify the range
13127             long numCalls = 42;
13128             bool initialFrontValue;
13129 
13130             if (!bw.empty)
13131             {
13132                 initialFrontValue = bw.front;
13133             }
13134 
13135             while (!bw.empty && (--numCalls))
13136             {
13137                 bw.front;
13138                 assert(bw.front == initialFrontValue);
13139             }
13140 
13141             /*
13142                Check that empty works properly and that popFront does not get called
13143                more times than it should
13144              */
13145             numCalls = 0;
13146             while (!bw.empty)
13147             {
13148                 ++numCalls;
13149 
13150                 static if (hasLength!T)
13151                 {
13152                     assert(bw.length == bwLength);
13153                     --bwLength;
13154                 }
13155 
13156                 static if (isForwardRange!T)
13157                 {
13158                     assert(bw.front == bwFwdSave.front);
13159                     bwFwdSave.popFront();
13160                 }
13161 
13162                 static if (isBidirectionalRange!T)
13163                 {
13164                     assert(bwBack.front == bwBackSave.front);
13165                     bwBack.popBack();
13166                     bwBackSave.popBack();
13167                 }
13168                 bw.popFront();
13169             }
13170 
13171             auto rangeLen = numCalls / (IntegralType.sizeof * 8);
13172             assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
13173             assert(bw.empty);
13174             static if (isForwardRange!T)
13175             {
13176                 assert(bwFwdSave.empty);
13177             }
13178 
13179             static if (isBidirectionalRange!T)
13180             {
13181                 assert(bwBack.empty);
13182             }
13183         }
13184     }
13185 }
13186 
13187 // Test opIndex and opSlice
13188 @system unittest
13189 {
13190     import std.meta : AliasSeq;
13191     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13192             long, ulong);
13193     foreach (IntegralType; IntegralTypes)
13194     {
13195         size_t bitsNum = IntegralType.sizeof * 8;
13196 
13197         auto first = cast(IntegralType)(1);
13198 
13199         // 2 ^ (bitsNum - 1)
13200         auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
13201 
13202         IntegralType[] a = [first, second];
13203         auto bw = Bitwise!(IntegralType[])(a);
13204 
13205         // Check against lsb of a[0]
13206         assert(bw[0] == true);
13207         // Check against msb - 1 of a[1]
13208         assert(bw[2 * bitsNum - 2] == true);
13209 
13210         bw.popFront();
13211         assert(bw[2 * bitsNum - 3] == true);
13212 
13213         import std.exception : assertThrown;
13214 
13215         version (D_NoBoundsChecks) {}
13216         else
13217         {
13218             // Check out of bounds error
13219             assertThrown!Error(bw[2 * bitsNum - 1]);
13220         }
13221 
13222         bw[2] = true;
13223         assert(bw[2] == true);
13224         bw.popFront();
13225         assert(bw[1] == true);
13226 
13227         auto bw2 = bw[0 .. $ - 5];
13228         auto bw3 = bw2[];
13229         assert(bw2.length == (bw.length - 5));
13230         assert(bw2.length == bw3.length);
13231         bw2.popFront();
13232         assert(bw2.length != bw3.length);
13233     }
13234 }
13235 
13236 /*********************************
13237  * An OutputRange that discards the data it receives.
13238  */
13239 struct NullSink
13240 {
13241     void put(E)(scope const E) pure @safe @nogc nothrow {}
13242 }
13243 
13244 /// ditto
13245 auto ref nullSink()
13246 {
13247     static NullSink sink;
13248     return sink;
13249 }
13250 
13251 ///
13252 @safe nothrow unittest
13253 {
13254     import std.algorithm.iteration : map;
13255     import std.algorithm.mutation : copy;
13256     [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
13257 }
13258 
13259 ///
13260 @safe unittest
13261 {
13262     import std.csv : csvNextToken;
13263 
13264     string line = "a,b,c";
13265 
13266     // ignore the first column
13267     line.csvNextToken(nullSink, ',', '"');
13268     line.popFront;
13269 
13270     // look at the second column
13271     Appender!string app;
13272     line.csvNextToken(app, ',', '"');
13273     assert(app.data == "b");
13274 }
13275 
13276 @safe unittest
13277 {
13278     auto r = 10.iota
13279                 .tee(nullSink)
13280                 .dropOne;
13281 
13282     assert(r.front == 1);
13283 }
13284 
13285 /++
13286 
13287   Implements a "tee" style pipe, wrapping an input range so that elements of the
13288   range can be passed to a provided function or $(LREF OutputRange) as they are
13289   iterated over. This is useful for printing out intermediate values in a long
13290   chain of range code, performing some operation with side-effects on each call
13291   to `front` or `popFront`, or diverting the elements of a range into an
13292   auxiliary $(LREF OutputRange).
13293 
13294   It is important to note that as the resultant range is evaluated lazily,
13295   in the case of the version of `tee` that takes a function, the function
13296   will not actually be executed until the range is "walked" using functions
13297   that evaluate ranges, such as $(REF array, std,array) or
13298   $(REF fold, std,algorithm,iteration).
13299 
13300   Params:
13301   pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
13302   calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
13303   respectively, `fun`). Note that each `popFront()` call will mirror the
13304   old `front` value, not the new one. This means that the last value will
13305   not be forwarded if the range isn't iterated until empty. If
13306   `No.pipeOnPop`, only elements for which `front` does get called will be
13307   also sent to `outputRange`/`fun`. If `front` is called twice for the same
13308   element, it will still be sent only once. If this caching is undesired,
13309   consider using $(REF map, std,algorithm,iteration) instead.
13310   inputRange = The input range being passed through.
13311   outputRange = This range will receive elements of `inputRange` progressively
13312   as iteration proceeds.
13313   fun = This function will be called with elements of `inputRange`
13314   progressively as iteration proceeds.
13315 
13316   Returns:
13317   An input range that offers the elements of `inputRange`. Regardless of
13318   whether `inputRange` is a more powerful range (forward, bidirectional etc),
13319   the result is always an input range. Reading this causes `inputRange` to be
13320   iterated and returns its elements in turn. In addition, the same elements
13321   will be passed to `outputRange` or `fun` as well.
13322 
13323   See_Also: $(REF each, std,algorithm,iteration)
13324 +/
13325 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
13326 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
13327 {
13328     static struct Result
13329     {
13330         private R1 _input;
13331         private R2 _output;
13332         static if (!pipeOnPop)
13333         {
13334             private bool _frontAccessed;
13335         }
13336 
13337         mixin ImplementLength!_input;
13338 
13339         static if (isInfinite!R1)
13340         {
13341             enum bool empty = false;
13342         }
13343         else
13344         {
13345             @property bool empty() { return _input.empty; }
13346         }
13347 
13348         void popFront()
13349         {
13350             assert(!_input.empty, "Attempting to popFront an empty tee");
13351             static if (pipeOnPop)
13352             {
13353                 put(_output, _input.front);
13354             }
13355             else
13356             {
13357                 _frontAccessed = false;
13358             }
13359             _input.popFront();
13360         }
13361 
13362         @property auto ref front()
13363         {
13364             assert(!_input.empty, "Attempting to fetch the front of an empty tee");
13365             static if (!pipeOnPop)
13366             {
13367                 if (!_frontAccessed)
13368                 {
13369                     _frontAccessed = true;
13370                     put(_output, _input.front);
13371                 }
13372             }
13373             return _input.front;
13374         }
13375     }
13376 
13377     return Result(inputRange, outputRange);
13378 }
13379 
13380 /// Ditto
13381 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
13382 if (is(typeof(fun) == void) || isSomeFunction!fun)
13383 {
13384     import std.traits : isDelegate, isFunctionPointer;
13385     /*
13386         Distinguish between function literals and template lambdas
13387         when using either as an $(LREF OutputRange). Since a template
13388         has no type, typeof(template) will always return void.
13389         If it's a template lambda, it's first necessary to instantiate
13390         it with `ElementType!R1`.
13391     */
13392     static if (is(typeof(fun) == void))
13393         alias _fun = fun!(ElementType!R1);
13394     else
13395         alias _fun = fun;
13396 
13397     static if (isFunctionPointer!_fun || isDelegate!_fun)
13398     {
13399         return tee!pipeOnPop(inputRange, _fun);
13400     }
13401     else
13402     {
13403         return tee!pipeOnPop(inputRange, &_fun);
13404     }
13405 }
13406 
13407 ///
13408 @safe unittest
13409 {
13410     import std.algorithm.comparison : equal;
13411     import std.algorithm.iteration : filter, map;
13412 
13413     // Sum values while copying
13414     int[] values = [1, 4, 9, 16, 25];
13415     int sum = 0;
13416     auto newValues = values.tee!(a => sum += a).array;
13417     assert(equal(newValues, values));
13418     assert(sum == 1 + 4 + 9 + 16 + 25);
13419 
13420     // Count values that pass the first filter
13421     int count = 0;
13422     auto newValues4 = values.filter!(a => a < 10)
13423                             .tee!(a => count++)
13424                             .map!(a => a + 1)
13425                             .filter!(a => a < 10);
13426 
13427     //Fine, equal also evaluates any lazy ranges passed to it.
13428     //count is not 3 until equal evaluates newValues4
13429     assert(equal(newValues4, [2, 5]));
13430     assert(count == 3);
13431 }
13432 
13433 //
13434 @safe unittest
13435 {
13436     import std.algorithm.comparison : equal;
13437     import std.algorithm.iteration : filter, map;
13438 
13439     int[] values = [1, 4, 9, 16, 25];
13440 
13441     int count = 0;
13442     auto newValues = values.filter!(a => a < 10)
13443         .tee!(a => count++, No.pipeOnPop)
13444         .map!(a => a + 1)
13445         .filter!(a => a < 10);
13446 
13447     auto val = newValues.front;
13448     assert(count == 1);
13449     //front is only evaluated once per element
13450     val = newValues.front;
13451     assert(count == 1);
13452 
13453     //popFront() called, fun will be called
13454     //again on the next access to front
13455     newValues.popFront();
13456     newValues.front;
13457     assert(count == 2);
13458 
13459     int[] preMap = new int[](3), postMap = [];
13460     auto mappedValues = values.filter!(a => a < 10)
13461         //Note the two different ways of using tee
13462         .tee(preMap)
13463         .map!(a => a + 1)
13464         .tee!(a => postMap ~= a)
13465         .filter!(a => a < 10);
13466     assert(equal(mappedValues, [2, 5]));
13467     assert(equal(preMap, [1, 4, 9]));
13468     assert(equal(postMap, [2, 5, 10]));
13469 }
13470 
13471 //
13472 @safe unittest
13473 {
13474     import std.algorithm.comparison : equal;
13475     import std.algorithm.iteration : filter, map;
13476 
13477     char[] txt = "Line one, Line 2".dup;
13478 
13479     bool isVowel(dchar c)
13480     {
13481         import std.string : indexOf;
13482         return "AaEeIiOoUu".indexOf(c) != -1;
13483     }
13484 
13485     int vowelCount = 0;
13486     int shiftedCount = 0;
13487     auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
13488                                 .filter!(c => !isVowel(c))
13489                                 .map!(c => (c == ' ') ? c : c + 1)
13490                                 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
13491     assert(equal(removeVowels, "Mo o- Mo 3"));
13492     assert(vowelCount == 6);
13493     assert(shiftedCount == 3);
13494 }
13495 
13496 @safe unittest
13497 {
13498     // Manually stride to test different pipe behavior.
13499     void testRange(Range)(Range r)
13500     {
13501         const int strideLen = 3;
13502         int i = 0;
13503         ElementType!Range elem1;
13504         ElementType!Range elem2;
13505         while (!r.empty)
13506         {
13507             if (i % strideLen == 0)
13508             {
13509                 //Make sure front is only
13510                 //evaluated once per item
13511                 elem1 = r.front;
13512                 elem2 = r.front;
13513                 assert(elem1 == elem2);
13514             }
13515             r.popFront();
13516             i++;
13517         }
13518     }
13519 
13520     string txt = "abcdefghijklmnopqrstuvwxyz";
13521 
13522     int popCount = 0;
13523     auto pipeOnPop = txt.tee!(a => popCount++);
13524     testRange(pipeOnPop);
13525     assert(popCount == 26);
13526 
13527     int frontCount = 0;
13528     auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13529     testRange(pipeOnFront);
13530     assert(frontCount == 9);
13531 }
13532 
13533 @safe unittest
13534 {
13535     import std.algorithm.comparison : equal;
13536     import std.meta : AliasSeq;
13537 
13538     //Test diverting elements to an OutputRange
13539     string txt = "abcdefghijklmnopqrstuvwxyz";
13540 
13541     dchar[] asink1 = [];
13542     auto fsink = (dchar c) { asink1 ~= c; };
13543     auto result1 = txt.tee(fsink).array;
13544     assert(equal(txt, result1) && (equal(result1, asink1)));
13545 
13546     dchar[] _asink1 = [];
13547     auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13548     assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13549 
13550     dchar[] asink2 = new dchar[](txt.length);
13551     void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13552     auto result2 = txt.tee(&fsink2).array;
13553     assert(equal(txt, result2) && equal(result2, asink2));
13554 
13555     dchar[] asink3 = new dchar[](txt.length);
13556     auto result3 = txt.tee(asink3).array;
13557     assert(equal(txt, result3) && equal(result3, asink3));
13558 
13559     static foreach (CharType; AliasSeq!(char, wchar, dchar))
13560     {{
13561         auto appSink = appender!(CharType[])();
13562         auto appResult = txt.tee(appSink).array;
13563         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13564     }}
13565 
13566     static foreach (StringType; AliasSeq!(string, wstring, dstring))
13567     {{
13568         auto appSink = appender!StringType();
13569         auto appResult = txt.tee(appSink).array;
13570         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13571     }}
13572 }
13573 
13574 // https://issues.dlang.org/show_bug.cgi?id=13483
13575 @safe unittest
13576 {
13577     static void func1(T)(T x) {}
13578     void func2(int x) {}
13579 
13580     auto r = [1, 2, 3, 4].tee!func1.tee!func2;
13581 }
13582 
13583 /**
13584 Extends the length of the input range `r` by padding out the start of the
13585 range with the element `e`. The element `e` must be of a common type with
13586 the element type of the range `r` as defined by $(REF CommonType, std, traits).
13587 If `n` is less than the length of of `r`, then `r` is returned unmodified.
13588 
13589 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
13590 about length for strings, which is not the number of characters, or
13591 graphemes, but instead the number of encoding units. If you want to treat each
13592 grapheme as only one encoding unit long, then call
13593 $(REF byGrapheme, std, uni) before calling this function.
13594 
13595 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
13596 
13597 Params:
13598     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
13599     e = element to pad the range with
13600     n = the length to pad to
13601 
13602 Returns:
13603     A range containing the elements of the original range with the extra padding
13604 
13605 See Also:
13606     $(REF leftJustifier, std, string)
13607 */
13608 auto padLeft(R, E)(R r, E e, size_t n)
13609 if (
13610     ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
13611     !is(CommonType!(ElementType!R, E) == void)
13612 )
13613 {
13614     static if (hasLength!R)
13615         auto dataLength = r.length;
13616     else
13617         auto dataLength = r.save.walkLength(n);
13618 
13619     return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
13620 }
13621 
13622 ///
13623 @safe pure unittest
13624 {
13625     import std.algorithm.comparison : equal;
13626 
13627     assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
13628     assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
13629 
13630     assert("abc".padLeft('_', 6).equal("___abc"));
13631 }
13632 
13633 @safe pure nothrow unittest
13634 {
13635     import std.algorithm.comparison : equal;
13636     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
13637     import std.meta : AliasSeq;
13638 
13639     alias DummyRanges = AliasSeq!(
13640         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
13641         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
13642         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
13643         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
13644         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
13645         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
13646         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
13647         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
13648         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
13649         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
13650     );
13651 
13652     foreach (Range; DummyRanges)
13653     {
13654         Range r;
13655         assert(r
13656             .padLeft(0, 12)
13657             .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13658         );
13659     }
13660 }
13661 
13662 // Test nogc inference
13663 @safe @nogc pure unittest
13664 {
13665     import std.algorithm.comparison : equal;
13666 
13667     static immutable r1 = [1, 2, 3, 4];
13668     static immutable r2 = [0, 0, 1, 2, 3, 4];
13669     assert(r1.padLeft(0, 6).equal(r2));
13670 }
13671 
13672 /**
13673 Extend the length of the input range `r` by padding out the end of the range
13674 with the element `e`. The element `e` must be of a common type with the
13675 element type of the range `r` as defined by $(REF CommonType, std, traits).
13676 If `n` is less than the length of of `r`, then the contents of `r` are
13677 returned.
13678 
13679 The range primitives that the resulting range provides depends whether or not `r`
13680 provides them. Except the functions `back` and `popBack`, which also require
13681 the range to have a length as well as `back` and `popBack`
13682 
13683 Params:
13684     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
13685     e = element to pad the range with
13686     n = the length to pad to
13687 
13688 Returns:
13689     A range containing the elements of the original range with the extra padding
13690 
13691 See Also:
13692     $(REF rightJustifier, std, string)
13693 */
13694 auto padRight(R, E)(R r, E e, size_t n)
13695 if (
13696     isInputRange!R &&
13697     !isInfinite!R &&
13698     !is(CommonType!(ElementType!R, E) == void))
13699 {
13700     static struct Result
13701     {
13702         private:
13703         R data;
13704         E element;
13705         static if (hasLength!R)
13706         {
13707             size_t padLength;
13708         }
13709         else
13710         {
13711             size_t minLength;
13712             size_t consumed;
13713         }
13714 
13715         public:
13716         bool empty() @property
13717         {
13718             static if (hasLength!R)
13719             {
13720                 return data.empty && padLength == 0;
13721             }
13722             else
13723             {
13724                 return data.empty && consumed >= minLength;
13725             }
13726         }
13727 
13728         auto front() @property
13729         {
13730             assert(!empty, "Attempting to fetch the front of an empty padRight");
13731             return data.empty ? element : data.front;
13732         }
13733 
13734         void popFront()
13735         {
13736             assert(!empty, "Attempting to popFront an empty padRight");
13737 
13738             static if (hasLength!R)
13739             {
13740                 if (!data.empty)
13741                 {
13742                     data.popFront;
13743                 }
13744                 else
13745                 {
13746                     --padLength;
13747                 }
13748             }
13749             else
13750             {
13751                 ++consumed;
13752                 if (!data.empty)
13753                 {
13754                     data.popFront;
13755                 }
13756             }
13757         }
13758 
13759         static if (hasLength!R)
13760         {
13761             size_t length() @property
13762             {
13763                 return data.length + padLength;
13764             }
13765         }
13766 
13767         static if (isForwardRange!R)
13768         {
13769             auto save() @property
13770             {
13771                 typeof(this) result = this;
13772                 data = data.save;
13773                 return result;
13774             }
13775         }
13776 
13777         static if (isBidirectionalRange!R && hasLength!R)
13778         {
13779             auto back() @property
13780             {
13781                 assert(!empty, "Attempting to fetch the back of an empty padRight");
13782                 return padLength > 0 ? element : data.back;
13783             }
13784 
13785             void popBack()
13786             {
13787                 assert(!empty, "Attempting to popBack an empty padRight");
13788                 if (padLength > 0)
13789                 {
13790                     --padLength;
13791                 }
13792                 else
13793                 {
13794                     data.popBack;
13795                 }
13796             }
13797         }
13798 
13799         static if (isRandomAccessRange!R && hasLength!R)
13800         {
13801             E opIndex(size_t index)
13802             {
13803                 assert(index <= this.length, "Index out of bounds");
13804                 return index >= data.length ? element : data[index];
13805             }
13806         }
13807 
13808         static if (hasSlicing!R && hasLength!R)
13809         {
13810             auto opSlice(size_t a, size_t b)
13811             {
13812                 assert(
13813                     a <= b,
13814                     "Attempting to slice a padRight with a larger first argument than the second."
13815                 );
13816                 assert(
13817                     b <= length,
13818                     "Attempting to slice using an out of bounds index on a padRight"
13819                 );
13820                 return Result(
13821                     a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
13822                     element, b - a);
13823             }
13824 
13825             alias opDollar = length;
13826         }
13827 
13828         this(R r, E e, size_t n)
13829         {
13830             data = r;
13831             element = e;
13832             static if (hasLength!R)
13833             {
13834                 padLength = n > data.length ? n - data.length : 0;
13835             }
13836             else
13837             {
13838                 minLength = n;
13839             }
13840         }
13841 
13842         @disable this();
13843     }
13844 
13845     return Result(r, e, n);
13846 }
13847 
13848 ///
13849 @safe pure unittest
13850 {
13851     import std.algorithm.comparison : equal;
13852 
13853     assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
13854     assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
13855 
13856     assert("abc".padRight('_', 6).equal("abc___"));
13857 }
13858 
13859 pure @safe unittest
13860 {
13861     import std.algorithm.comparison : equal;
13862     import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
13863     import std.meta : AliasSeq;
13864 
13865     auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
13866     dchar padding = '_';
13867     assert(string_input_range.padRight(padding, 6).equal("abc___"));
13868 
13869     foreach (RangeType; AllDummyRanges)
13870     {
13871         RangeType r1;
13872         assert(r1
13873             .padRight(0, 12)
13874             .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13875         );
13876 
13877         // test if Result properly uses random access ranges
13878         static if (isRandomAccessRange!RangeType)
13879         {
13880             RangeType r3;
13881             assert(r3.padRight(0, 12)[0] == 1);
13882             assert(r3.padRight(0, 12)[2] == 3);
13883             assert(r3.padRight(0, 12)[9] == 10);
13884             assert(r3.padRight(0, 12)[10] == 0);
13885             assert(r3.padRight(0, 12)[11] == 0);
13886         }
13887 
13888         // test if Result properly uses slicing and opDollar
13889         static if (hasSlicing!RangeType)
13890         {
13891             RangeType r4;
13892             assert(r4
13893                 .padRight(0, 12)[0 .. 3]
13894                 .equal([1, 2, 3])
13895             );
13896             assert(r4
13897                 .padRight(0, 12)[0 .. 10]
13898                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13899             );
13900             assert(r4
13901                 .padRight(0, 12)[0 .. 11]
13902                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
13903             );
13904             assert(r4
13905                 .padRight(0, 12)[2 .. $]
13906                 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13907             );
13908             assert(r4
13909                 .padRight(0, 12)[0 .. $]
13910                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13911             );
13912         }
13913 
13914         // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
13915         RangeType r5;
13916         foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
13917     }
13918 }
13919 
13920 // Test nogc inference
13921 @safe @nogc pure unittest
13922 {
13923     import std.algorithm.comparison : equal;
13924 
13925     static immutable r1 = [1, 2, 3, 4];
13926     static immutable r2 = [1, 2, 3, 4, 0, 0];
13927     assert(r1.padRight(0, 6).equal(r2));
13928 }
13929 
13930 // Test back, popBack, and save
13931 @safe pure unittest
13932 {
13933     import std.algorithm.comparison : equal;
13934 
13935     auto r1 = [1, 2, 3, 4].padRight(0, 6);
13936     assert(r1.back == 0);
13937 
13938     r1.popBack;
13939     auto r2 = r1.save;
13940     assert(r1.equal([1, 2, 3, 4, 0]));
13941     assert(r2.equal([1, 2, 3, 4, 0]));
13942 
13943     r1.popBackN(2);
13944     assert(r1.back == 3);
13945     assert(r1.length == 3);
13946     assert(r2.length == 5);
13947     assert(r2.equal([1, 2, 3, 4, 0]));
13948 
13949     r2.popFront;
13950     assert(r2.length == 4);
13951     assert(r2[0] == 2);
13952     assert(r2[1] == 3);
13953     assert(r2[2] == 4);
13954     assert(r2[3] == 0);
13955     assert(r2.equal([2, 3, 4, 0]));
13956 
13957     r2.popBack;
13958     assert(r2.equal([2, 3, 4]));
13959 
13960     auto r3 = [1, 2, 3, 4].padRight(0, 6);
13961     size_t len = 0;
13962     while (!r3.empty)
13963     {
13964         ++len;
13965         r3.popBack;
13966     }
13967     assert(len == 6);
13968 }
13969 
13970 // https://issues.dlang.org/show_bug.cgi?id=19042
13971 @safe pure unittest
13972 {
13973     import std.algorithm.comparison : equal;
13974 
13975     assert([2, 5, 13].padRight(42, 10).chunks(5)
13976            .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
13977 
13978     assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
13979 }
13980 
13981 /**
13982 This simplifies a commonly used idiom in phobos for accepting any kind of string
13983 parameter. The type `R` can for example be a simple string, chained string using
13984 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
13985 characters.
13986 
13987 Only finite length character ranges are allowed with this constraint.
13988 
13989 This template is equivalent to:
13990 ---
13991 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
13992 ---
13993 
13994 See_Also:
13995 $(REF isInputRange, std,range,primitives),
13996 $(REF isInfinite, std,range,primitives),
13997 $(LREF isSomeChar),
13998 $(REF ElementEncodingType, std,range,primitives)
13999 */
14000 template isSomeFiniteCharInputRange(R)
14001 {
14002     import std.traits : isSomeChar;
14003 
14004     enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
14005         && isSomeChar!(ElementEncodingType!R);
14006 }
14007 
14008 ///
14009 @safe unittest
14010 {
14011     import std.path : chainPath;
14012     import std.range : chain;
14013 
14014     void someLibraryMethod(R)(R argument)
14015     if (isSomeFiniteCharInputRange!R)
14016     {
14017         // implementation detail, would iterate over each character of argument
14018     }
14019 
14020     someLibraryMethod("simple strings work");
14021     someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
14022     someLibraryMethod(chainPath("chained", "paths", "work"));
14023     // you can also use custom structs implementing a char range
14024 }
14025