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;
236 
237 import std.internal.attributes : betterC;
238 import std.meta : allSatisfy, 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                     source.back = val;
317                 }
318 
319                 @property void back(ElementType!R val)
320                 {
321                     source.front = val;
322                 }
323             }
324 
325             static if (isRandomAccessRange!(R) && hasLength!(R))
326             {
327                 auto ref opIndex(size_t n) { return source[retroIndex(n)]; }
328 
329                 static if (hasAssignableElements!R)
330                 {
331                     void opIndexAssign(ElementType!R val, size_t n)
332                     {
333                         source[retroIndex(n)] = val;
334                     }
335                 }
336 
337                 static if (is(typeof(source.moveAt(0))))
338                 {
339                     ElementType!R moveAt(size_t index)
340                     {
341                         return source.moveAt(retroIndex(index));
342                     }
343                 }
344 
345                 static if (hasSlicing!R)
346                     typeof(this) opSlice(size_t a, size_t b)
347                     {
348                         return typeof(this)(source[source.length - b .. source.length - a]);
349                     }
350             }
351 
352             static if (hasLength!R)
353             {
354                 @property auto length()
355                 {
356                     return source.length;
357                 }
358 
359                 alias opDollar = length;
360             }
361         }
362 
363         return Result!()(r);
364     }
365 }
366 
367 
368 ///
369 pure @safe nothrow @nogc unittest
370 {
371     import std.algorithm.comparison : equal;
372     int[5] a = [ 1, 2, 3, 4, 5 ];
373     int[5] b = [ 5, 4, 3, 2, 1 ];
374     assert(equal(retro(a[]), b[]));
375     assert(retro(a[]).source is a[]);
376     assert(retro(retro(a[])) is a[]);
377 }
378 
379 pure @safe nothrow unittest
380 {
381     import std.algorithm.comparison : equal;
382     static assert(isBidirectionalRange!(typeof(retro("hello"))));
383     int[] a;
384     static assert(is(typeof(a) == typeof(retro(retro(a)))));
385     assert(retro(retro(a)) is a);
386     static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
387     void test(int[] input, int[] witness)
388     {
389         auto r = retro(input);
390         assert(r.front == witness.front);
391         assert(r.back == witness.back);
392         assert(equal(r, witness));
393     }
394     test([ 1 ], [ 1 ]);
395     test([ 1, 2 ], [ 2, 1 ]);
396     test([ 1, 2, 3 ], [ 3, 2, 1 ]);
397     test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
398     test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
399     test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
400 
401     immutable foo = [1,2,3].idup;
402     auto r = retro(foo);
403     assert(equal(r, [3, 2, 1]));
404 }
405 
406 pure @safe nothrow unittest
407 {
408     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
409         ReturnBy;
410 
411     foreach (DummyType; AllDummyRanges)
412     {
413         static if (!isBidirectionalRange!DummyType)
414         {
415             static assert(!__traits(compiles, Retro!DummyType));
416         }
417         else
418         {
419             DummyType dummyRange;
420             dummyRange.reinit();
421 
422             auto myRetro = retro(dummyRange);
423             static assert(propagatesRangeType!(typeof(myRetro), DummyType));
424             assert(myRetro.front == 10);
425             assert(myRetro.back == 1);
426             assert(myRetro.moveFront() == 10);
427             assert(myRetro.moveBack() == 1);
428 
429             static if (isRandomAccessRange!DummyType && hasLength!DummyType)
430             {
431                 assert(myRetro[0] == myRetro.front);
432                 assert(myRetro.moveAt(2) == 8);
433 
434                 static if (DummyType.r == ReturnBy.Reference)
435                 {
436                     {
437                         myRetro[9]++;
438                         scope(exit) myRetro[9]--;
439                         assert(dummyRange[0] == 2);
440                         myRetro.front++;
441                         scope(exit) myRetro.front--;
442                         assert(myRetro.front == 11);
443                         myRetro.back++;
444                         scope(exit) myRetro.back--;
445                         assert(myRetro.back == 3);
446                     }
447 
448                     {
449                         myRetro.front = 0xFF;
450                         scope(exit) myRetro.front = 10;
451                         assert(dummyRange.back == 0xFF);
452 
453                         myRetro.back = 0xBB;
454                         scope(exit) myRetro.back = 1;
455                         assert(dummyRange.front == 0xBB);
456 
457                         myRetro[1] = 11;
458                         scope(exit) myRetro[1] = 8;
459                         assert(dummyRange[8] == 11);
460                     }
461                 }
462             }
463         }
464     }
465 }
466 
467 pure @safe nothrow @nogc unittest
468 {
469     import std.algorithm.comparison : equal;
470     auto LL = iota(1L, 4L);
471     auto r = retro(LL);
472     long[3] excepted = [3, 2, 1];
473     assert(equal(r, excepted[]));
474 }
475 
476 // https://issues.dlang.org/show_bug.cgi?id=12662
477 pure @safe nothrow @nogc unittest
478 {
479     int[3] src = [1,2,3];
480     int[] data = src[];
481     foreach_reverse (x; data) {}
482     foreach (x; data.retro) {}
483 }
484 
485 
486 /**
487 Iterates range `r` with stride `n`. If the range is a
488 random-access range, moves by indexing into the range; otherwise,
489 moves by successive calls to `popFront`. Applying stride twice to
490 the same range results in a stride with a step that is the
491 product of the two applications. It is an error for `n` to be 0.
492 
493 Params:
494     r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over
495     n = the number of elements to skip over
496 
497 Returns:
498     At minimum, an input range. The resulting range will adopt the
499     range primitives of the underlying range as long as
500     $(REF hasLength, std,range,primitives) is `true`.
501  */
502 auto stride(Range)(Range r, size_t n)
503 if (isInputRange!(Unqual!Range))
504 in
505 {
506     assert(n != 0, "stride cannot have step zero.");
507 }
508 do
509 {
510     import std.algorithm.comparison : min;
511 
512     static if (is(typeof(stride(r.source, n)) == Range))
513     {
514         // stride(stride(r, n1), n2) is stride(r, n1 * n2)
515         return stride(r.source, r._n * n);
516     }
517     else
518     {
519         static struct Result
520         {
521             private alias R = Unqual!Range;
522             public R source;
523             private size_t _n;
524 
525             // Chop off the slack elements at the end
526             static if (hasLength!R &&
527                     (isRandomAccessRange!R && hasSlicing!R
528                             || isBidirectionalRange!R))
529                 private void eliminateSlackElements()
530                 {
531                     auto slack = source.length % _n;
532 
533                     if (slack)
534                     {
535                         slack--;
536                     }
537                     else if (!source.empty)
538                     {
539                         slack = min(_n, source.length) - 1;
540                     }
541                     else
542                     {
543                         slack = 0;
544                     }
545                     if (!slack) return;
546                     static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
547                     {
548                         source = source[0 .. source.length - slack];
549                     }
550                     else static if (isBidirectionalRange!R)
551                     {
552                         foreach (i; 0 .. slack)
553                         {
554                             source.popBack();
555                         }
556                     }
557                 }
558 
559             static if (isForwardRange!R)
560             {
561                 @property auto save()
562                 {
563                     return Result(source.save, _n);
564                 }
565             }
566 
567             static if (isInfinite!R)
568             {
569                 enum bool empty = false;
570             }
571             else
572             {
573                 @property bool empty()
574                 {
575                     return source.empty;
576                 }
577             }
578 
579             @property auto ref front()
580             {
581                 return source.front;
582             }
583 
584             static if (is(typeof(.moveFront(source))))
585             {
586                 ElementType!R moveFront()
587                 {
588                     return source.moveFront();
589                 }
590             }
591 
592             static if (hasAssignableElements!R)
593             {
594                 @property void front(ElementType!R val)
595                 {
596                     source.front = val;
597                 }
598             }
599 
600             void popFront()
601             {
602                 source.popFrontN(_n);
603             }
604 
605             static if (isBidirectionalRange!R && hasLength!R)
606             {
607                 void popBack()
608                 {
609                     popBackN(source, _n);
610                 }
611 
612                 @property auto ref back()
613                 {
614                     eliminateSlackElements();
615                     return source.back;
616                 }
617 
618                 static if (is(typeof(.moveBack(source))))
619                 {
620                     ElementType!R moveBack()
621                     {
622                         eliminateSlackElements();
623                         return source.moveBack();
624                     }
625                 }
626 
627                 static if (hasAssignableElements!R)
628                 {
629                     @property void back(ElementType!R val)
630                     {
631                         eliminateSlackElements();
632                         source.back = val;
633                     }
634                 }
635             }
636 
637             static if (isRandomAccessRange!R && hasLength!R)
638             {
639                 auto ref opIndex(size_t n)
640                 {
641                     return source[_n * n];
642                 }
643 
644                 /**
645                    Forwards to $(D moveAt(source, n)).
646                 */
647                 static if (is(typeof(source.moveAt(0))))
648                 {
649                     ElementType!R moveAt(size_t n)
650                     {
651                         return source.moveAt(_n * n);
652                     }
653                 }
654 
655                 static if (hasAssignableElements!R)
656                 {
657                     void opIndexAssign(ElementType!R val, size_t n)
658                     {
659                         source[_n * n] = val;
660                     }
661                 }
662             }
663 
664             static if (hasSlicing!R && hasLength!R)
665                 typeof(this) opSlice(size_t lower, size_t upper)
666                 {
667                     assert(upper >= lower && upper <= length);
668                     immutable translatedUpper = (upper == 0) ? 0 :
669                         (upper * _n - (_n - 1));
670                     immutable translatedLower = min(lower * _n, translatedUpper);
671 
672                     assert(translatedLower <= translatedUpper);
673 
674                     return typeof(this)(source[translatedLower .. translatedUpper], _n);
675                 }
676 
677             static if (hasLength!R)
678             {
679                 @property auto length()
680                 {
681                     return (source.length + _n - 1) / _n;
682                 }
683 
684                 alias opDollar = length;
685             }
686         }
687         return Result(r, n);
688     }
689 }
690 
691 ///
692 pure @safe nothrow unittest
693 {
694     import std.algorithm.comparison : equal;
695 
696     int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
697     assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
698     assert(stride(stride(a, 2), 3) == stride(a, 6));
699 }
700 
701 pure @safe nothrow @nogc unittest
702 {
703     import std.algorithm.comparison : equal;
704 
705     int[4] testArr = [1,2,3,4];
706     static immutable result = [1, 3];
707     assert(equal(testArr[].stride(2), result));
708 }
709 
710 debug pure nothrow @system unittest
711 {//check the contract
712     int[4] testArr = [1,2,3,4];
713     bool passed = false;
714     scope (success) assert(passed);
715     import core.exception : AssertError;
716     //std.exception.assertThrown won't do because it can't infer nothrow
717     // https://issues.dlang.org/show_bug.cgi?id=12647
718     try
719     {
720         auto unused = testArr[].stride(0);
721     }
722     catch (AssertError unused)
723     {
724         passed = true;
725     }
726 }
727 
728 pure @safe nothrow unittest
729 {
730     import std.algorithm.comparison : equal;
731     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
732         ReturnBy;
733 
734     static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
735     void test(size_t n, int[] input, int[] witness)
736     {
737         assert(equal(stride(input, n), witness));
738     }
739     test(1, [], []);
740     int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
741     assert(stride(stride(arr, 2), 3) is stride(arr, 6));
742     test(1, arr, arr);
743     test(2, arr, [1, 3, 5, 7, 9]);
744     test(3, arr, [1, 4, 7, 10]);
745     test(4, arr, [1, 5, 9]);
746 
747     // Test slicing.
748     auto s1 = stride(arr, 1);
749     assert(equal(s1[1 .. 4], [2, 3, 4]));
750     assert(s1[1 .. 4].length == 3);
751     assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
752     assert(s1[1 .. 5].length == 4);
753     assert(s1[0 .. 0].empty);
754     assert(s1[3 .. 3].empty);
755     // assert(s1[$ .. $].empty);
756     assert(s1[s1.opDollar .. s1.opDollar].empty);
757 
758     auto s2 = stride(arr, 2);
759     assert(equal(s2[0 .. 2], [1,3]));
760     assert(s2[0 .. 2].length == 2);
761     assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
762     assert(s2[1 .. 5].length == 4);
763     assert(s2[0 .. 0].empty);
764     assert(s2[3 .. 3].empty);
765     // assert(s2[$ .. $].empty);
766     assert(s2[s2.opDollar .. s2.opDollar].empty);
767 
768     // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035
769     auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
770     auto col = stride(m, 4);
771     assert(equal(col, [1, 1, 1]));
772     assert(equal(retro(col), [1, 1, 1]));
773 
774     immutable int[] immi = [ 1, 2, 3 ];
775     static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
776 
777     // Check for infiniteness propagation.
778     static assert(isInfinite!(typeof(stride(repeat(1), 3))));
779 
780     foreach (DummyType; AllDummyRanges)
781     {
782         DummyType dummyRange;
783         dummyRange.reinit();
784 
785         auto myStride = stride(dummyRange, 4);
786 
787         // Should fail if no length and bidirectional b/c there's no way
788         // to know how much slack we have.
789         static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
790         {
791             static assert(propagatesRangeType!(typeof(myStride), DummyType));
792         }
793         assert(myStride.front == 1);
794         assert(myStride.moveFront() == 1);
795         assert(equal(myStride, [1, 5, 9]));
796 
797         static if (hasLength!DummyType)
798         {
799             assert(myStride.length == 3);
800         }
801 
802         static if (isBidirectionalRange!DummyType && hasLength!DummyType)
803         {
804             assert(myStride.back == 9);
805             assert(myStride.moveBack() == 9);
806         }
807 
808         static if (isRandomAccessRange!DummyType && hasLength!DummyType)
809         {
810             assert(myStride[0] == 1);
811             assert(myStride[1] == 5);
812             assert(myStride.moveAt(1) == 5);
813             assert(myStride[2] == 9);
814 
815             static assert(hasSlicing!(typeof(myStride)));
816         }
817 
818         static if (DummyType.r == ReturnBy.Reference)
819         {
820             // Make sure reference is propagated.
821 
822             {
823                 myStride.front++;
824                 scope(exit) myStride.front--;
825                 assert(dummyRange.front == 2);
826             }
827             {
828                 myStride.front = 4;
829                 scope(exit) myStride.front = 1;
830                 assert(dummyRange.front == 4);
831             }
832 
833             static if (isBidirectionalRange!DummyType && hasLength!DummyType)
834             {
835                 {
836                     myStride.back++;
837                     scope(exit) myStride.back--;
838                     assert(myStride.back == 10);
839                 }
840                 {
841                     myStride.back = 111;
842                     scope(exit) myStride.back = 9;
843                     assert(myStride.back == 111);
844                 }
845 
846                 static if (isRandomAccessRange!DummyType)
847                 {
848                     {
849                         myStride[1]++;
850                         scope(exit) myStride[1]--;
851                         assert(dummyRange[4] == 6);
852                     }
853                     {
854                         myStride[1] = 55;
855                         scope(exit) myStride[1] = 5;
856                         assert(dummyRange[4] == 55);
857                     }
858                 }
859             }
860         }
861     }
862 }
863 
864 pure @safe nothrow unittest
865 {
866     import std.algorithm.comparison : equal;
867 
868     auto LL = iota(1L, 10L);
869     auto s = stride(LL, 3);
870     assert(equal(s, [1L, 4L, 7L]));
871 }
872 
873 /**
874 Spans multiple ranges in sequence. The function `chain` takes any
875 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
876 ranges may be different, but they must have the same element type. The
877 result is a range that offers the `front`, `popFront`, and $(D
878 empty) primitives. If all input ranges offer random access and $(D
879 length), `Chain` offers them as well.
880 
881 If only one range is offered to `Chain` or `chain`, the $(D
882 Chain) type exits the picture by aliasing itself directly to that
883 range's type.
884 
885 Params:
886     rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together
887 
888 Returns:
889     An input range at minimum. If all of the ranges in `rs` provide
890     a range primitive, the returned range will also provide that range
891     primitive.
892 
893 See_Also: $(LREF only) to chain values to a range
894  */
895 auto chain(Ranges...)(Ranges rs)
896 if (Ranges.length > 0 &&
897     allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
898     !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
899 {
900     static if (Ranges.length == 1)
901     {
902         return rs[0];
903     }
904     else
905     {
906         static struct Result
907         {
908         private:
909             alias R = staticMap!(Unqual, Ranges);
910             alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
911             private template sameET(A)
912             {
913                 enum sameET = is(.ElementType!A == RvalueElementType);
914             }
915 
916             enum bool allSameType = allSatisfy!(sameET, R);
917             alias ElementType = RvalueElementType;
918 
919             static if (allSameType && allSatisfy!(hasLvalueElements, R))
920             {
921                 static ref RvalueElementType fixRef(ref RvalueElementType val)
922                 {
923                     return val;
924                 }
925             }
926             else
927             {
928                 static RvalueElementType fixRef(RvalueElementType val)
929                 {
930                     return val;
931                 }
932             }
933 
934             // This is the entire state
935             R source;
936             // TODO: use a vtable (or more) instead of linear iteration
937 
938         public:
939             this(R input)
940             {
941                 foreach (i, v; input)
942                 {
943                     source[i] = v;
944                 }
945             }
946 
947             import std.meta : anySatisfy;
948 
949             static if (anySatisfy!(isInfinite, R))
950             {
951                 // Propagate infiniteness.
952                 enum bool empty = false;
953             }
954             else
955             {
956                 @property bool empty()
957                 {
958                     foreach (i, Unused; R)
959                     {
960                         if (!source[i].empty) return false;
961                     }
962                     return true;
963                 }
964             }
965 
966             static if (allSatisfy!(isForwardRange, R))
967                 @property auto save()
968                 {
969                     auto saveSource(size_t len)()
970                     {
971                         import std.typecons : tuple;
972                         static assert(len > 0);
973                         static if (len == 1)
974                         {
975                             return tuple(source[0].save);
976                         }
977                         else
978                         {
979                             return saveSource!(len - 1)() ~
980                                 tuple(source[len - 1].save);
981                         }
982                     }
983                     return Result(saveSource!(R.length).expand);
984                 }
985 
986             void popFront()
987             {
988                 foreach (i, Unused; R)
989                 {
990                     if (source[i].empty) continue;
991                     source[i].popFront();
992                     return;
993                 }
994             }
995 
996             @property auto ref front()
997             {
998                 foreach (i, Unused; R)
999                 {
1000                     if (source[i].empty) continue;
1001                     return fixRef(source[i].front);
1002                 }
1003                 assert(false);
1004             }
1005 
1006             static if (allSameType && allSatisfy!(hasAssignableElements, R))
1007             {
1008                 // @@@BUG@@@
1009                 //@property void front(T)(T v) if (is(T : RvalueElementType))
1010 
1011                 @property void front(RvalueElementType v)
1012                 {
1013                     foreach (i, Unused; R)
1014                     {
1015                         if (source[i].empty) continue;
1016                         source[i].front = v;
1017                         return;
1018                     }
1019                     assert(false);
1020                 }
1021             }
1022 
1023             static if (allSatisfy!(hasMobileElements, R))
1024             {
1025                 RvalueElementType moveFront()
1026                 {
1027                     foreach (i, Unused; R)
1028                     {
1029                         if (source[i].empty) continue;
1030                         return source[i].moveFront();
1031                     }
1032                     assert(false);
1033                 }
1034             }
1035 
1036             static if (allSatisfy!(isBidirectionalRange, R))
1037             {
1038                 @property auto ref back()
1039                 {
1040                     foreach_reverse (i, Unused; R)
1041                     {
1042                         if (source[i].empty) continue;
1043                         return fixRef(source[i].back);
1044                     }
1045                     assert(false);
1046                 }
1047 
1048                 void popBack()
1049                 {
1050                     foreach_reverse (i, Unused; R)
1051                     {
1052                         if (source[i].empty) continue;
1053                         source[i].popBack();
1054                         return;
1055                     }
1056                 }
1057 
1058                 static if (allSatisfy!(hasMobileElements, R))
1059                 {
1060                     RvalueElementType moveBack()
1061                     {
1062                         foreach_reverse (i, Unused; R)
1063                         {
1064                             if (source[i].empty) continue;
1065                             return source[i].moveBack();
1066                         }
1067                         assert(false);
1068                     }
1069                 }
1070 
1071                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1072                 {
1073                     @property void back(RvalueElementType v)
1074                     {
1075                         foreach_reverse (i, Unused; R)
1076                         {
1077                             if (source[i].empty) continue;
1078                             source[i].back = v;
1079                             return;
1080                         }
1081                         assert(false);
1082                     }
1083                 }
1084             }
1085 
1086             static if (allSatisfy!(hasLength, R))
1087             {
1088                 @property size_t length()
1089                 {
1090                     size_t result;
1091                     foreach (i, Unused; R)
1092                     {
1093                         result += source[i].length;
1094                     }
1095                     return result;
1096                 }
1097 
1098                 alias opDollar = length;
1099             }
1100 
1101             static if (allSatisfy!(isRandomAccessRange, R))
1102             {
1103                 auto ref opIndex(size_t index)
1104                 {
1105                     foreach (i, Range; R)
1106                     {
1107                         static if (isInfinite!(Range))
1108                         {
1109                             return source[i][index];
1110                         }
1111                         else
1112                         {
1113                             immutable length = source[i].length;
1114                             if (index < length) return fixRef(source[i][index]);
1115                             index -= length;
1116                         }
1117                     }
1118                     assert(false);
1119                 }
1120 
1121                 static if (allSatisfy!(hasMobileElements, R))
1122                 {
1123                     RvalueElementType moveAt(size_t index)
1124                     {
1125                         foreach (i, Range; R)
1126                         {
1127                             static if (isInfinite!(Range))
1128                             {
1129                                 return source[i].moveAt(index);
1130                             }
1131                             else
1132                             {
1133                                 immutable length = source[i].length;
1134                                 if (index < length) return source[i].moveAt(index);
1135                                 index -= length;
1136                             }
1137                         }
1138                         assert(false);
1139                     }
1140                 }
1141 
1142                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1143                     void opIndexAssign(ElementType v, size_t index)
1144                     {
1145                         foreach (i, Range; R)
1146                         {
1147                             static if (isInfinite!(Range))
1148                             {
1149                                 source[i][index] = v;
1150                             }
1151                             else
1152                             {
1153                                 immutable length = source[i].length;
1154                                 if (index < length)
1155                                 {
1156                                     source[i][index] = v;
1157                                     return;
1158                                 }
1159                                 index -= length;
1160                             }
1161                         }
1162                         assert(false);
1163                     }
1164             }
1165 
1166             static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
1167                 auto opSlice(size_t begin, size_t end) return scope
1168                 {
1169                     auto result = this;
1170                     foreach (i, Unused; R)
1171                     {
1172                         immutable len = result.source[i].length;
1173                         if (len < begin)
1174                         {
1175                             result.source[i] = result.source[i]
1176                                 [len .. len];
1177                             begin -= len;
1178                         }
1179                         else
1180                         {
1181                             result.source[i] = result.source[i]
1182                                 [begin .. len];
1183                             break;
1184                         }
1185                     }
1186                     auto cut = length;
1187                     cut = cut <= end ? 0 : cut - end;
1188                     foreach_reverse (i, Unused; R)
1189                     {
1190                         immutable len = result.source[i].length;
1191                         if (cut > len)
1192                         {
1193                             result.source[i] = result.source[i]
1194                                 [0 .. 0];
1195                             cut -= len;
1196                         }
1197                         else
1198                         {
1199                             result.source[i] = result.source[i]
1200                                 [0 .. len - cut];
1201                             break;
1202                         }
1203                     }
1204                     return result;
1205                 }
1206         }
1207         return Result(rs);
1208     }
1209 }
1210 
1211 ///
1212 pure @safe nothrow unittest
1213 {
1214     import std.algorithm.comparison : equal;
1215 
1216     int[] arr1 = [ 1, 2, 3, 4 ];
1217     int[] arr2 = [ 5, 6 ];
1218     int[] arr3 = [ 7 ];
1219     auto s = chain(arr1, arr2, arr3);
1220     assert(s.length == 7);
1221     assert(s[5] == 6);
1222     assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1223 }
1224 
1225 /**
1226  * Range primitives are carried over to the returned range if
1227  * all of the ranges provide them
1228  */
1229 pure @safe nothrow unittest
1230 {
1231     import std.algorithm.comparison : equal;
1232     import std.algorithm.sorting : sort;
1233 
1234     int[] arr1 = [5, 2, 8];
1235     int[] arr2 = [3, 7, 9];
1236     int[] arr3 = [1, 4, 6];
1237 
1238     // in-place sorting across all of the arrays
1239     auto s = arr1.chain(arr2, arr3).sort;
1240 
1241     assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1242     assert(arr1.equal([1, 2, 3]));
1243     assert(arr2.equal([4, 5, 6]));
1244     assert(arr3.equal([7, 8, 9]));
1245 }
1246 
1247 /**
1248 Due to safe type promotion in D, chaining together different
1249 character ranges results in a `uint` range.
1250 
1251 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf),
1252 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges
1253 to get the type you need.
1254  */
1255 pure @safe nothrow unittest
1256 {
1257     import std.utf : byChar, byCodeUnit;
1258 
1259     auto s1 = "string one";
1260     auto s2 = "string two";
1261     // s1 and s2 front is dchar because of auto-decoding
1262     static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
1263 
1264     auto r1 = s1.chain(s2);
1265     // chains of ranges of the same character type give that same type
1266     static assert(is(typeof(r1.front) == dchar));
1267 
1268     auto s3 = "string three".byCodeUnit;
1269     static assert(is(typeof(s3.front) == immutable char));
1270     auto r2 = s1.chain(s3);
1271     // chaining ranges of mixed character types gives `dchar`
1272     static assert(is(typeof(r2.front) == dchar));
1273 
1274     // use byChar on character ranges to correctly convert them to UTF-8
1275     auto r3 = s1.byChar.chain(s3);
1276     static assert(is(typeof(r3.front) == immutable char));
1277 }
1278 
1279 pure @safe nothrow unittest
1280 {
1281     import std.algorithm.comparison : equal;
1282     import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1283                                           propagatesRangeType;
1284 
1285     {
1286         int[] arr1 = [ 1, 2, 3, 4 ];
1287         int[] arr2 = [ 5, 6 ];
1288         int[] arr3 = [ 7 ];
1289         int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1290         auto s1 = chain(arr1);
1291         static assert(isRandomAccessRange!(typeof(s1)));
1292         auto s2 = chain(arr1, arr2);
1293         static assert(isBidirectionalRange!(typeof(s2)));
1294         static assert(isRandomAccessRange!(typeof(s2)));
1295         s2.front = 1;
1296         auto s = chain(arr1, arr2, arr3);
1297         assert(s[5] == 6);
1298         assert(equal(s, witness));
1299         assert(s[5] == 6);
1300     }
1301     {
1302         int[] arr1 = [ 1, 2, 3, 4 ];
1303         int[] witness = [ 1, 2, 3, 4 ];
1304         assert(equal(chain(arr1), witness));
1305     }
1306     {
1307         uint[] foo = [1,2,3,4,5];
1308         uint[] bar = [1,2,3,4,5];
1309         auto c = chain(foo, bar);
1310         c[3] = 42;
1311         assert(c[3] == 42);
1312         assert(c.moveFront() == 1);
1313         assert(c.moveBack() == 5);
1314         assert(c.moveAt(4) == 5);
1315         assert(c.moveAt(5) == 1);
1316     }
1317 
1318 
1319     // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed.
1320     // elements are mutable.
1321     assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1322 
1323     // Test the case where infinite ranges are present.
1324     auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1325     assert(inf[0] == 0);
1326     assert(inf[3] == 4);
1327     assert(inf[6] == 4);
1328     assert(inf[7] == 5);
1329     static assert(isInfinite!(typeof(inf)));
1330 
1331     immutable int[] immi = [ 1, 2, 3 ];
1332     immutable float[] immf = [ 1, 2, 3 ];
1333     static assert(is(typeof(chain(immi, immf))));
1334 
1335     // Check that chain at least instantiates and compiles with every possible
1336     // pair of DummyRange types, in either order.
1337 
1338     foreach (DummyType1; AllDummyRanges)
1339     (){ // workaround slow optimizations for large functions
1340         // https://issues.dlang.org/show_bug.cgi?id=2396
1341         DummyType1 dummy1;
1342         foreach (DummyType2; AllDummyRanges)
1343         {
1344             DummyType2 dummy2;
1345             auto myChain = chain(dummy1, dummy2);
1346 
1347             static assert(
1348                 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1349             );
1350 
1351             assert(myChain.front == 1);
1352             foreach (i; 0 .. dummyLength)
1353             {
1354                 myChain.popFront();
1355             }
1356             assert(myChain.front == 1);
1357 
1358             static if (isBidirectionalRange!DummyType1 &&
1359                       isBidirectionalRange!DummyType2) {
1360                 assert(myChain.back == 10);
1361             }
1362 
1363             static if (isRandomAccessRange!DummyType1 &&
1364                       isRandomAccessRange!DummyType2) {
1365                 assert(myChain[0] == 1);
1366             }
1367 
1368             static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1369             {
1370                 static assert(hasLvalueElements!(typeof(myChain)));
1371             }
1372             else
1373             {
1374                 static assert(!hasLvalueElements!(typeof(myChain)));
1375             }
1376         }
1377     }();
1378 }
1379 
1380 pure @safe nothrow @nogc unittest
1381 {
1382     class Foo{}
1383     immutable(Foo)[] a;
1384     immutable(Foo)[] b;
1385     assert(chain(a, b).empty);
1386 }
1387 
1388 // https://issues.dlang.org/show_bug.cgi?id=18657
1389 pure @safe unittest
1390 {
1391     import std.algorithm.comparison : equal;
1392     string s = "foo";
1393     auto r = refRange(&s).chain("bar");
1394     assert(equal(r.save, "foobar"));
1395     assert(equal(r, "foobar"));
1396 }
1397 
1398 /**
1399 Choose one of two ranges at runtime depending on a Boolean condition.
1400 
1401 The ranges may be different, but they must have compatible element types (i.e.
1402 `CommonType` must exist for the two element types). The result is a range
1403 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D
1404 R1) is a random-access range and `R2` is a forward range).
1405 
1406 Params:
1407     condition = which range to choose: `r1` if `true`, `r2` otherwise
1408     r1 = the "true" range
1409     r2 = the "false" range
1410 
1411 Returns:
1412     A range type dependent on `R1` and `R2`.
1413  */
1414 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
1415 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1416     !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1417 {
1418     return ChooseResult!(R1, R2)(condition, r1, r2);
1419 }
1420 
1421 ///
1422 @safe nothrow pure @nogc unittest
1423 {
1424     import std.algorithm.comparison : equal;
1425     import std.algorithm.iteration : filter, map;
1426 
1427     auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
1428     auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
1429 
1430     // choose() is primarily useful when you need to select one of two ranges
1431     // with different types at runtime.
1432     static assert(!is(typeof(data1) == typeof(data2)));
1433 
1434     auto chooseRange(bool pickFirst)
1435     {
1436         // The returned range is a common wrapper type that can be used for
1437         // returning or storing either range without running into a type error.
1438         return choose(pickFirst, data1, data2);
1439 
1440         // Simply returning the chosen range without using choose() does not
1441         // work, because map() and filter() return different types.
1442         //return pickFirst ? data1 : data2; // does not compile
1443     }
1444 
1445     auto result = chooseRange(true);
1446     assert(result.equal(only(1, 2, 4)));
1447 
1448     result = chooseRange(false);
1449     assert(result.equal(only(6, 7, 8, 9)));
1450 }
1451 
1452 
1453 private struct ChooseResult(R1, R2)
1454 {
1455     import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor;
1456 
1457     private union
1458     {
1459         R1 r1;
1460         R2 r2;
1461     }
1462     private bool r1Chosen;
1463 
1464     private static auto ref actOnChosen(alias foo, ExtraArgs ...)(ref ChooseResult r,
1465             auto ref ExtraArgs extraArgs)
1466     {
1467         if (r.r1Chosen)
1468         {
1469             ref get1(return ref ChooseResult r) @trusted { return r.r1; }
1470             return foo(get1(r), extraArgs);
1471         }
1472         else
1473         {
1474             ref get2(return ref ChooseResult r) @trusted { return r.r2; }
1475             return foo(get2(r), extraArgs);
1476         }
1477     }
1478 
1479     this(bool r1Chosen, return scope R1 r1, return scope R2 r2) @trusted
1480     {
1481         // @trusted because of assignment of r1 and r2 which overlap each other
1482         import std.conv : emplace;
1483 
1484         // This should be the only place r1Chosen is ever assigned
1485         // independently
1486         this.r1Chosen = r1Chosen;
1487         if (r1Chosen)
1488         {
1489             this.r2 = R2.init;
1490             emplace(&this.r1, r1);
1491         }
1492         else
1493         {
1494             this.r1 = R1.init;
1495             emplace(&this.r2, r2);
1496         }
1497     }
1498 
1499     void opAssign(ChooseResult r)
1500     {
1501         static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2)
1502             if (r1Chosen != r.r1Chosen)
1503             {
1504                 // destroy the current item
1505                 actOnChosen!((ref r) => destroy(r))(this);
1506             }
1507         r1Chosen = r.r1Chosen;
1508         if (r1Chosen)
1509         {
1510             ref get1(return ref ChooseResult r) @trusted { return r.r1; }
1511             get1(this) = get1(r);
1512         }
1513         else
1514         {
1515             ref get2(return ref ChooseResult r) @trusted { return r.r2; }
1516             get2(this) = get2(r);
1517         }
1518     }
1519 
1520     // Carefully defined postblit to postblit the appropriate range
1521     static if (hasElaborateCopyConstructor!R1
1522         || hasElaborateCopyConstructor!R2)
1523     this(this)
1524     {
1525         actOnChosen!((ref r) {
1526                 static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit();
1527             })(this);
1528     }
1529 
1530     static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2)
1531     ~this()
1532     {
1533         actOnChosen!((ref r) => destroy(r))(this);
1534     }
1535 
1536     static if (isInfinite!R1 && isInfinite!R2)
1537         // Propagate infiniteness.
1538         enum bool empty = false;
1539     else
1540         @property bool empty()
1541         {
1542             return actOnChosen!(r => r.empty)(this);
1543         }
1544 
1545     @property auto ref front()
1546     {
1547         static auto ref getFront(R)(ref R r) { return r.front; }
1548         return actOnChosen!getFront(this);
1549     }
1550 
1551     void popFront()
1552     {
1553         return actOnChosen!((ref r) { r.popFront; })(this);
1554     }
1555 
1556     static if (isForwardRange!R1 && isForwardRange!R2)
1557     @property auto save() return scope
1558     {
1559         if (r1Chosen)
1560         {
1561             ref R1 getR1() @trusted { return r1; }
1562             return ChooseResult(r1Chosen, getR1.save, R2.init);
1563         }
1564         else
1565         {
1566             ref R2 getR2() @trusted { return r2; }
1567             return ChooseResult(r1Chosen, R1.init, getR2.save);
1568         }
1569     }
1570 
1571     @property void front(T)(T v)
1572     if (is(typeof({ r1.front = v; r2.front = v; })))
1573     {
1574         actOnChosen!((ref r, T v) { r.front = v; })(this, v);
1575     }
1576 
1577     static if (hasMobileElements!R1 && hasMobileElements!R2)
1578         auto moveFront()
1579         {
1580             return actOnChosen!((ref r) => r.moveFront)(this);
1581         }
1582 
1583     static if (isBidirectionalRange!R1 && isBidirectionalRange!R2)
1584     {
1585         @property auto ref back()
1586         {
1587             static auto ref getBack(R)(ref R r) { return r.back; }
1588             return actOnChosen!getBack(this);
1589         }
1590 
1591         void popBack()
1592         {
1593             actOnChosen!((ref r) { r.popBack; })(this);
1594         }
1595 
1596         static if (hasMobileElements!R1 && hasMobileElements!R2)
1597             auto moveBack()
1598             {
1599                 return actOnChosen!((ref r) => r.moveBack)(this);
1600             }
1601 
1602         @property void back(T)(T v)
1603         if (is(typeof({ r1.back = v; r2.back = v; })))
1604         {
1605             actOnChosen!((ref r, T v) { r.back = v; })(this, v);
1606         }
1607     }
1608 
1609     static if (hasLength!R1 && hasLength!R2)
1610     {
1611         @property size_t length()
1612         {
1613             return actOnChosen!(r => r.length)(this);
1614         }
1615         alias opDollar = length;
1616     }
1617 
1618     static if (isRandomAccessRange!R1 && isRandomAccessRange!R2)
1619     {
1620         auto ref opIndex(size_t index)
1621         {
1622             static auto ref get(R)(ref R r, size_t index) { return r[index]; }
1623             return actOnChosen!get(this, index);
1624         }
1625 
1626         static if (hasMobileElements!R1 && hasMobileElements!R2)
1627             auto moveAt(size_t index)
1628             {
1629                 return actOnChosen!((ref r, size_t index) => r.moveAt(index))
1630                     (this, index);
1631             }
1632 
1633         void opIndexAssign(T)(T v, size_t index)
1634         if (is(typeof({ r1[1] = v; r2[1] = v; })))
1635         {
1636             return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
1637                 (this, index, v);
1638         }
1639     }
1640 
1641     static if (hasSlicing!R1 && hasSlicing!R2)
1642         auto opSlice(size_t begin, size_t end)
1643         {
1644             alias Slice1 = typeof(R1.init[0 .. 1]);
1645             alias Slice2 = typeof(R2.init[0 .. 1]);
1646             return actOnChosen!((r, size_t begin, size_t end) {
1647                     static if (is(typeof(r) == Slice1))
1648                         return choose(true, r[begin .. end], Slice2.init);
1649                     else
1650                         return choose(false, Slice1.init, r[begin .. end]);
1651                 })(this, begin, end);
1652         }
1653 }
1654 
1655 // https://issues.dlang.org/show_bug.cgi?id=18657
1656 pure @safe unittest
1657 {
1658     import std.algorithm.comparison : equal;
1659     string s = "foo";
1660     auto r = choose(true, refRange(&s), "bar");
1661     assert(equal(r.save, "foo"));
1662     assert(equal(r, "foo"));
1663 }
1664 
1665 @safe unittest
1666 {
1667     static void* p;
1668     static struct R
1669     {
1670         void* q;
1671         int front;
1672         bool empty;
1673         void popFront() {}
1674         @property R save() { p = q; return this; }
1675             // `p = q;` is only there to prevent inference of `scope return`.
1676     }
1677     R r;
1678     choose(true, r, r).save;
1679 }
1680 
1681 // Make sure ChooseResult.save doesn't trust @system user code.
1682 @system unittest // copy is @system
1683 {
1684     static struct R
1685     {
1686         int front;
1687         bool empty;
1688         void popFront() {}
1689         this(this) @system {}
1690         @property R save() { return R(front, empty); }
1691     }
1692     choose(true, R(), R()).save;
1693     choose(true, [0], R()).save;
1694     choose(true, R(), [0]).save;
1695 }
1696 
1697 @safe unittest // copy is @system
1698 {
1699     static struct R
1700     {
1701         int front;
1702         bool empty;
1703         void popFront() {}
1704         this(this) @system {}
1705         @property R save() { return R(front, empty); }
1706     }
1707     static assert(!__traits(compiles, choose(true, R(), R()).save));
1708     static assert(!__traits(compiles, choose(true, [0], R()).save));
1709     static assert(!__traits(compiles, choose(true, R(), [0]).save));
1710 }
1711 
1712 @system unittest // .save is @system
1713 {
1714     static struct R
1715     {
1716         int front;
1717         bool empty;
1718         void popFront() {}
1719         @property R save() @system { return this; }
1720     }
1721     choose(true, R(), R()).save;
1722     choose(true, [0], R()).save;
1723     choose(true, R(), [0]).save;
1724 }
1725 
1726 @safe unittest // .save is @system
1727 {
1728     static struct R
1729     {
1730         int front;
1731         bool empty;
1732         void popFront() {}
1733         @property R save() @system { return this; }
1734     }
1735     static assert(!__traits(compiles, choose(true, R(), R()).save));
1736     static assert(!__traits(compiles, choose(true, [0], R()).save));
1737     static assert(!__traits(compiles, choose(true, R(), [0]).save));
1738 }
1739 
1740 //https://issues.dlang.org/show_bug.cgi?id=19738
1741 @safe nothrow pure @nogc unittest
1742 {
1743     static struct EvilRange
1744     {
1745         enum empty = true;
1746         int front;
1747         void popFront() @safe {}
1748         auto opAssign(const ref EvilRange other)
1749         {
1750             *(cast(uint*) 0xcafebabe) = 0xdeadbeef;
1751             return this;
1752         }
1753     }
1754 
1755     static assert(!__traits(compiles, () @safe
1756     {
1757         auto c1 = choose(true, EvilRange(), EvilRange());
1758         auto c2 = c1;
1759         c1 = c2;
1760     }));
1761 }
1762 
1763 
1764 // https://issues.dlang.org/show_bug.cgi?id=20495
1765 @safe unittest
1766 {
1767     static struct KillableRange
1768     {
1769         int *item;
1770         ref int front() { return *item; }
1771         bool empty() { return *item > 10; }
1772         void popFront() { ++(*item); }
1773         this(this)
1774         {
1775             assert(item is null || cast(size_t) item > 1000);
1776             item = new int(*item);
1777         }
1778         KillableRange save() { return this; }
1779     }
1780 
1781     auto kr = KillableRange(new int(1));
1782     int[] x = [1,2,3,4,5]; // length is first
1783 
1784     auto chosen = choose(true, x, kr);
1785     auto chosen2 = chosen.save;
1786 }
1787 
1788 /**
1789 Choose one of multiple ranges at runtime.
1790 
1791 The ranges may be different, but they must have compatible element types. The
1792 result is a range that offers the weakest capabilities of all `Ranges`.
1793 
1794 Params:
1795     index = which range to choose, must be less than the number of ranges
1796     rs = two or more ranges
1797 
1798 Returns:
1799     The indexed range. If rs consists of only one range, the return type is an
1800     alias of that range's type.
1801  */
1802 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
1803 if (Ranges.length >= 2
1804         && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
1805         && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
1806 {
1807     static if (Ranges.length == 2)
1808         return choose(index == 0, rs[0], rs[1]);
1809     else
1810         return choose(index == 0, rs[0], chooseAmong(index - 1, rs[1 .. $]));
1811 }
1812 
1813 ///
1814 @safe nothrow pure @nogc unittest
1815 {
1816     auto test()
1817     {
1818         import std.algorithm.comparison : equal;
1819 
1820         int[4] sarr1 = [1, 2, 3, 4];
1821         int[2] sarr2 = [5, 6];
1822         int[1] sarr3 = [7];
1823         auto arr1 = sarr1[];
1824         auto arr2 = sarr2[];
1825         auto arr3 = sarr3[];
1826 
1827         {
1828             auto s = chooseAmong(0, arr1, arr2, arr3);
1829             auto t = s.save;
1830             assert(s.length == 4);
1831             assert(s[2] == 3);
1832             s.popFront();
1833             assert(equal(t, only(1, 2, 3, 4)));
1834         }
1835         {
1836             auto s = chooseAmong(1, arr1, arr2, arr3);
1837             assert(s.length == 2);
1838             s.front = 8;
1839             assert(equal(s, only(8, 6)));
1840         }
1841         {
1842             auto s = chooseAmong(1, arr1, arr2, arr3);
1843             assert(s.length == 2);
1844             s[1] = 9;
1845             assert(equal(s, only(8, 9)));
1846         }
1847         {
1848             auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
1849             assert(s.length == 2);
1850             assert(equal(s, only(2, 3)));
1851         }
1852         {
1853             auto s = chooseAmong(0, arr1, arr2, arr3);
1854             assert(s.length == 4);
1855             assert(s.back == 4);
1856             s.popBack();
1857             s.back = 5;
1858             assert(equal(s, only(1, 2, 5)));
1859             s.back = 3;
1860             assert(equal(s, only(1, 2, 3)));
1861         }
1862         {
1863             uint[5] foo = [1, 2, 3, 4, 5];
1864             uint[5] bar = [6, 7, 8, 9, 10];
1865             auto c = chooseAmong(1, foo[], bar[]);
1866             assert(c[3] == 9);
1867             c[3] = 42;
1868             assert(c[3] == 42);
1869             assert(c.moveFront() == 6);
1870             assert(c.moveBack() == 10);
1871             assert(c.moveAt(4) == 10);
1872         }
1873         {
1874             import std.range : cycle;
1875             auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
1876             assert(isInfinite!(typeof(s)));
1877             assert(!s.empty);
1878             assert(s[100] == 8);
1879             assert(s[101] == 9);
1880             assert(s[0 .. 3].equal(only(8, 9, 8)));
1881         }
1882         return 0;
1883     }
1884     // works at runtime
1885     auto a = test();
1886     // and at compile time
1887     static b = test();
1888 }
1889 
1890 @safe nothrow pure @nogc unittest
1891 {
1892     int[3] a = [1, 2, 3];
1893     long[3] b = [4, 5, 6];
1894     auto c = chooseAmong(0, a[], b[]);
1895     c[0] = 42;
1896     assert(c[0] == 42);
1897 }
1898 
1899 @safe nothrow pure @nogc unittest
1900 {
1901     static struct RefAccessRange
1902     {
1903         int[] r;
1904         ref front() @property { return r[0]; }
1905         ref back() @property { return r[$ - 1]; }
1906         void popFront() { r = r[1 .. $]; }
1907         void popBack() { r = r[0 .. $ - 1]; }
1908         auto empty() @property { return r.empty; }
1909         ref opIndex(size_t i) { return r[i]; }
1910         auto length() @property { return r.length; }
1911         alias opDollar = length;
1912         auto save() { return this; }
1913     }
1914     static assert(isRandomAccessRange!RefAccessRange);
1915     static assert(isRandomAccessRange!RefAccessRange);
1916     int[4] a = [4, 3, 2, 1];
1917     int[2] b = [6, 5];
1918     auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[]));
1919 
1920     void refFunc(ref int a, int target) { assert(a == target); }
1921 
1922     refFunc(c[2], 2);
1923     refFunc(c.front, 4);
1924     refFunc(c.back, 1);
1925 }
1926 
1927 
1928 /**
1929 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`,
1930 then `r3.front`, after which it pops off one element from each and
1931 continues again from `r1`. For example, if two ranges are involved,
1932 it alternately yields elements off the two ranges. `roundRobin`
1933 stops after it has consumed all ranges (skipping over the ones that
1934 finish early).
1935  */
1936 auto roundRobin(Rs...)(Rs rs)
1937 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
1938 {
1939     struct Result
1940     {
1941         import std.conv : to;
1942 
1943         public Rs source;
1944         private size_t _current = size_t.max;
1945 
1946         @property bool empty()
1947         {
1948             foreach (i, Unused; Rs)
1949             {
1950                 if (!source[i].empty) return false;
1951             }
1952             return true;
1953         }
1954 
1955         @property auto ref front()
1956         {
1957             final switch (_current)
1958             {
1959                 foreach (i, R; Rs)
1960                 {
1961                     case i:
1962                         assert(
1963                             !source[i].empty,
1964                             "Attempting to fetch the front of an empty roundRobin"
1965                         );
1966                         return source[i].front;
1967                 }
1968             }
1969             assert(0);
1970         }
1971 
1972         void popFront()
1973         {
1974             final switch (_current)
1975             {
1976                 foreach (i, R; Rs)
1977                 {
1978                     case i:
1979                         source[i].popFront();
1980                         break;
1981                 }
1982             }
1983 
1984             auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
1985             final switch (next)
1986             {
1987                 foreach (i, R; Rs)
1988                 {
1989                     case i:
1990                         if (!source[i].empty)
1991                         {
1992                             _current = i;
1993                             return;
1994                         }
1995                         if (i == _current)
1996                         {
1997                             _current = _current.max;
1998                             return;
1999                         }
2000                         goto case (i + 1) % Rs.length;
2001                 }
2002             }
2003         }
2004 
2005         static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
2006             @property auto save()
2007             {
2008                 auto saveSource(size_t len)()
2009                 {
2010                     import std.typecons : tuple;
2011                     static assert(len > 0);
2012                     static if (len == 1)
2013                     {
2014                         return tuple(source[0].save);
2015                     }
2016                     else
2017                     {
2018                         return saveSource!(len - 1)() ~
2019                             tuple(source[len - 1].save);
2020                     }
2021                 }
2022                 return Result(saveSource!(Rs.length).expand, _current);
2023             }
2024 
2025         static if (allSatisfy!(hasLength, Rs))
2026         {
2027             @property size_t length()
2028             {
2029                 size_t result;
2030                 foreach (i, R; Rs)
2031                 {
2032                     result += source[i].length;
2033                 }
2034                 return result;
2035             }
2036 
2037             alias opDollar = length;
2038         }
2039     }
2040 
2041     return Result(rs, 0);
2042 }
2043 
2044 ///
2045 @safe unittest
2046 {
2047     import std.algorithm.comparison : equal;
2048 
2049     int[] a = [ 1, 2, 3 ];
2050     int[] b = [ 10, 20, 30, 40 ];
2051     auto r = roundRobin(a, b);
2052     assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
2053 }
2054 
2055 /**
2056  * roundRobin can be used to create "interleave" functionality which inserts
2057  * an element between each element in a range.
2058  */
2059 @safe unittest
2060 {
2061     import std.algorithm.comparison : equal;
2062 
2063     auto interleave(R, E)(R range, E element)
2064     if ((isInputRange!R && hasLength!R) || isForwardRange!R)
2065     {
2066         static if (hasLength!R)
2067             immutable len = range.length;
2068         else
2069             immutable len = range.save.walkLength;
2070 
2071         return roundRobin(
2072             range,
2073             element.repeat(len - 1)
2074         );
2075     }
2076 
2077     assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
2078 }
2079 
2080 pure @safe unittest
2081 {
2082     import std.algorithm.comparison : equal;
2083     string f = "foo", b = "bar";
2084     auto r = roundRobin(refRange(&f), refRange(&b));
2085     assert(equal(r.save, "fboaor"));
2086     assert(equal(r.save, "fboaor"));
2087 }
2088 
2089 /**
2090 Iterates a random-access range starting from a given point and
2091 progressively extending left and right from that point. If no initial
2092 point is given, iteration starts from the middle of the
2093 range. Iteration spans the entire range.
2094 
2095 When `startingIndex` is 0 the range will be fully iterated in order
2096 and in reverse order when `r.length` is given.
2097 
2098 Params:
2099     r = a random access range with length and slicing
2100     startingIndex = the index to begin iteration from
2101 
2102 Returns:
2103     A forward range with length
2104  */
2105 auto radial(Range, I)(Range r, I startingIndex)
2106 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
2107 {
2108     if (startingIndex != r.length) ++startingIndex;
2109     return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
2110 }
2111 
2112 /// Ditto
2113 auto radial(R)(R r)
2114 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
2115 {
2116     return .radial(r, (r.length - !r.empty) / 2);
2117 }
2118 
2119 ///
2120 @safe unittest
2121 {
2122     import std.algorithm.comparison : equal;
2123     int[] a = [ 1, 2, 3, 4, 5 ];
2124     assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
2125     a = [ 1, 2, 3, 4 ];
2126     assert(equal(radial(a), [ 2, 3, 1, 4 ]));
2127 
2128     // If the left end is reached first, the remaining elements on the right
2129     // are concatenated in order:
2130     a = [ 0, 1, 2, 3, 4, 5 ];
2131     assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
2132 
2133     // If the right end is reached first, the remaining elements on the left
2134     // are concatenated in reverse order:
2135     assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
2136 }
2137 
2138 @safe unittest
2139 {
2140     import std.algorithm.comparison : equal;
2141     import std.conv : text;
2142     import std.exception : enforce;
2143     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2144 
2145     void test(int[] input, int[] witness)
2146     {
2147         enforce(equal(radial(input), witness),
2148                 text(radial(input), " vs. ", witness));
2149     }
2150     test([], []);
2151     test([ 1 ], [ 1 ]);
2152     test([ 1, 2 ], [ 1, 2 ]);
2153     test([ 1, 2, 3 ], [ 2, 3, 1 ]);
2154     test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
2155     test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
2156     test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
2157 
2158     int[] a = [ 1, 2, 3, 4, 5 ];
2159     assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
2160     assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
2161     assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
2162     static assert(isForwardRange!(typeof(radial(a, 1))));
2163 
2164     auto r = radial([1,2,3,4,5]);
2165     for (auto rr = r.save; !rr.empty; rr.popFront())
2166     {
2167         assert(rr.front == moveFront(rr));
2168     }
2169     r.front = 5;
2170     assert(r.front == 5);
2171 
2172     // Test instantiation without lvalue elements.
2173     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
2174     assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
2175 
2176     // immutable int[] immi = [ 1, 2 ];
2177     // static assert(is(typeof(radial(immi))));
2178 }
2179 
2180 @safe unittest
2181 {
2182     import std.algorithm.comparison : equal;
2183 
2184     auto LL = iota(1L, 6L);
2185     auto r = radial(LL);
2186     assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
2187 }
2188 
2189 /**
2190 Lazily takes only up to `n` elements of a range. This is
2191 particularly useful when using with infinite ranges.
2192 
2193 Unlike $(LREF takeExactly), `take` does not require that there
2194 are `n` or more elements in `input`. As a consequence, length
2195 information is not applied to the result unless `input` also has
2196 length information.
2197 
2198 Params:
2199     input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2200     to iterate over up to `n` times
2201     n = the number of elements to take
2202 
2203 Returns:
2204     At minimum, an input range. If the range offers random access
2205     and `length`, `take` offers them as well.
2206  */
2207 Take!R take(R)(R input, size_t n)
2208 if (isInputRange!(Unqual!R))
2209 {
2210     alias U = Unqual!R;
2211     static if (is(R T == Take!T))
2212     {
2213         import std.algorithm.comparison : min;
2214         return R(input.source, min(n, input._maxAvailable));
2215     }
2216     else static if (!isInfinite!U && hasSlicing!U)
2217     {
2218         import std.algorithm.comparison : min;
2219         return input[0 .. min(n, input.length)];
2220     }
2221     else
2222     {
2223         return Take!R(input, n);
2224     }
2225 }
2226 
2227 /// ditto
2228 struct Take(Range)
2229 if (isInputRange!(Unqual!Range) &&
2230     //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
2231     //take for slicing infinite ranges.
2232     !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
2233 {
2234     private alias R = Unqual!Range;
2235 
2236     /// User accessible in read and write
2237     public R source;
2238 
2239     private size_t _maxAvailable;
2240 
2241     alias Source = R;
2242 
2243     /// Range primitives
2244     @property bool empty()
2245     {
2246         return _maxAvailable == 0 || source.empty;
2247     }
2248 
2249     /// ditto
2250     @property auto ref front()
2251     {
2252         assert(!empty,
2253             "Attempting to fetch the front of an empty "
2254             ~ Take.stringof);
2255         return source.front;
2256     }
2257 
2258     /// ditto
2259     void popFront()
2260     {
2261         assert(!empty,
2262             "Attempting to popFront() past the end of a "
2263             ~ Take.stringof);
2264         source.popFront();
2265         --_maxAvailable;
2266     }
2267 
2268     static if (isForwardRange!R)
2269         /// ditto
2270         @property Take save()
2271         {
2272             return Take(source.save, _maxAvailable);
2273         }
2274 
2275     static if (hasAssignableElements!R)
2276         /// ditto
2277         @property void front(ElementType!R v)
2278         {
2279             assert(!empty,
2280                 "Attempting to assign to the front of an empty "
2281                 ~ Take.stringof);
2282             // This has to return auto instead of void because of
2283             // https://issues.dlang.org/show_bug.cgi?id=4706
2284             source.front = v;
2285         }
2286 
2287     static if (hasMobileElements!R)
2288     {
2289         /// ditto
2290         auto moveFront()
2291         {
2292             assert(!empty,
2293                 "Attempting to move the front of an empty "
2294                 ~ Take.stringof);
2295             return source.moveFront();
2296         }
2297     }
2298 
2299     static if (isInfinite!R)
2300     {
2301         /// ditto
2302         @property size_t length() const
2303         {
2304             return _maxAvailable;
2305         }
2306 
2307         /// ditto
2308         alias opDollar = length;
2309 
2310         //Note: Due to Take/hasSlicing circular dependency,
2311         //This needs to be a restrained template.
2312         /// ditto
2313         auto opSlice()(size_t i, size_t j)
2314         if (hasSlicing!R)
2315         {
2316             assert(i <= j, "Invalid slice bounds");
2317             assert(j <= length, "Attempting to slice past the end of a "
2318                 ~ Take.stringof);
2319             return source[i .. j];
2320         }
2321     }
2322     else static if (hasLength!R)
2323     {
2324         /// ditto
2325         @property size_t length()
2326         {
2327             import std.algorithm.comparison : min;
2328             return min(_maxAvailable, source.length);
2329         }
2330 
2331         alias opDollar = length;
2332     }
2333 
2334     static if (isRandomAccessRange!R)
2335     {
2336         /// ditto
2337         void popBack()
2338         {
2339             assert(!empty,
2340                 "Attempting to popBack() past the beginning of a "
2341                 ~ Take.stringof);
2342             --_maxAvailable;
2343         }
2344 
2345         /// ditto
2346         @property auto ref back()
2347         {
2348             assert(!empty,
2349                 "Attempting to fetch the back of an empty "
2350                 ~ Take.stringof);
2351             return source[this.length - 1];
2352         }
2353 
2354         /// ditto
2355         auto ref opIndex(size_t index)
2356         {
2357             assert(index < length,
2358                 "Attempting to index out of the bounds of a "
2359                 ~ Take.stringof);
2360             return source[index];
2361         }
2362 
2363         static if (hasAssignableElements!R)
2364         {
2365             /// ditto
2366             @property void back(ElementType!R v)
2367             {
2368                 // This has to return auto instead of void because of
2369                 // https://issues.dlang.org/show_bug.cgi?id=4706
2370                 assert(!empty,
2371                     "Attempting to assign to the back of an empty "
2372                     ~ Take.stringof);
2373                 source[this.length - 1] = v;
2374             }
2375 
2376             /// ditto
2377             void opIndexAssign(ElementType!R v, size_t index)
2378             {
2379                 assert(index < length,
2380                     "Attempting to index out of the bounds of a "
2381                     ~ Take.stringof);
2382                 source[index] = v;
2383             }
2384         }
2385 
2386         static if (hasMobileElements!R)
2387         {
2388             /// ditto
2389             auto moveBack()
2390             {
2391                 assert(!empty,
2392                     "Attempting to move the back of an empty "
2393                     ~ Take.stringof);
2394                 return source.moveAt(this.length - 1);
2395             }
2396 
2397             /// ditto
2398             auto moveAt(size_t index)
2399             {
2400                 assert(index < length,
2401                     "Attempting to index out of the bounds of a "
2402                     ~ Take.stringof);
2403                 return source.moveAt(index);
2404             }
2405         }
2406     }
2407 
2408     /**
2409     Access to maximal length of the range.
2410     Note: the actual length of the range depends on the underlying range.
2411     If it has fewer elements, it will stop before maxLength is reached.
2412     */
2413     @property size_t maxLength() const
2414     {
2415         return _maxAvailable;
2416     }
2417 }
2418 
2419 /// ditto
2420 template Take(R)
2421 if (isInputRange!(Unqual!R) &&
2422     ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2423 {
2424     alias Take = R;
2425 }
2426 
2427 ///
2428 pure @safe nothrow unittest
2429 {
2430     import std.algorithm.comparison : equal;
2431 
2432     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2433     auto s = take(arr1, 5);
2434     assert(s.length == 5);
2435     assert(s[4] == 5);
2436     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2437 }
2438 
2439 /**
2440  * If the range runs out before `n` elements, `take` simply returns the entire
2441  * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2442  * the range ends prematurely):
2443  */
2444 pure @safe nothrow unittest
2445 {
2446     import std.algorithm.comparison : equal;
2447 
2448     int[] arr2 = [ 1, 2, 3 ];
2449     auto t = take(arr2, 5);
2450     assert(t.length == 3);
2451     assert(equal(t, [ 1, 2, 3 ]));
2452 }
2453 
2454 pure @safe nothrow unittest
2455 {
2456     import std.algorithm.comparison : equal;
2457     import std.internal.test.dummyrange : AllDummyRanges;
2458 
2459     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2460     auto s = take(arr1, 5);
2461     assert(s.length == 5);
2462     assert(s[4] == 5);
2463     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2464     assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2465 
2466     // Test fix for bug 4464.
2467     static assert(is(typeof(s) == Take!(int[])));
2468     static assert(is(typeof(s) == int[]));
2469 
2470     // Test using narrow strings.
2471     import std.exception : assumeWontThrow;
2472 
2473     auto myStr = "This is a string.";
2474     auto takeMyStr = take(myStr, 7);
2475     assert(assumeWontThrow(equal(takeMyStr, "This is")));
2476     // Test fix for bug 5052.
2477     auto takeMyStrAgain = take(takeMyStr, 4);
2478     assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2479     static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
2480     takeMyStrAgain = take(takeMyStr, 10);
2481     assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
2482 
2483     foreach (DummyType; AllDummyRanges)
2484     {
2485         DummyType dummy;
2486         auto t = take(dummy, 5);
2487         alias T = typeof(t);
2488 
2489         static if (isRandomAccessRange!DummyType)
2490         {
2491             static assert(isRandomAccessRange!T);
2492             assert(t[4] == 5);
2493 
2494             assert(moveAt(t, 1) == t[1]);
2495             assert(t.back == moveBack(t));
2496         }
2497         else static if (isForwardRange!DummyType)
2498         {
2499             static assert(isForwardRange!T);
2500         }
2501 
2502         for (auto tt = t; !tt.empty; tt.popFront())
2503         {
2504             assert(tt.front == moveFront(tt));
2505         }
2506 
2507         // Bidirectional ranges can't be propagated properly if they don't
2508         // also have random access.
2509 
2510         assert(equal(t, [1,2,3,4,5]));
2511 
2512         //Test that take doesn't wrap the result of take.
2513         assert(take(t, 4) == take(dummy, 4));
2514     }
2515 
2516     immutable myRepeat = repeat(1);
2517     static assert(is(Take!(typeof(myRepeat))));
2518 }
2519 
2520 pure @safe nothrow @nogc unittest
2521 {
2522     //check for correct slicing of Take on an infinite range
2523     import std.algorithm.comparison : equal;
2524     foreach (start; 0 .. 4)
2525         foreach (stop; start .. 4)
2526             assert(iota(4).cycle.take(4)[start .. stop]
2527                 .equal(iota(start, stop)));
2528 }
2529 
2530 pure @safe nothrow @nogc unittest
2531 {
2532     // Check that one can declare variables of all Take types,
2533     // and that they match the return type of the corresponding
2534     // take().
2535     // See https://issues.dlang.org/show_bug.cgi?id=4464
2536     int[] r1;
2537     Take!(int[]) t1;
2538     t1 = take(r1, 1);
2539     assert(t1.empty);
2540 
2541     string r2;
2542     Take!string t2;
2543     t2 = take(r2, 1);
2544     assert(t2.empty);
2545 
2546     Take!(Take!string) t3;
2547     t3 = take(t2, 1);
2548     assert(t3.empty);
2549 }
2550 
2551 pure @safe nothrow @nogc unittest
2552 {
2553     alias R1 = typeof(repeat(1));
2554     alias R2 = typeof(cycle([1]));
2555     alias TR1 = Take!R1;
2556     alias TR2 = Take!R2;
2557     static assert(isBidirectionalRange!TR1);
2558     static assert(isBidirectionalRange!TR2);
2559 }
2560 
2561 // https://issues.dlang.org/show_bug.cgi?id=12731
2562 pure @safe nothrow @nogc unittest
2563 {
2564     auto a = repeat(1);
2565     auto s = a[1 .. 5];
2566     s = s[1 .. 3];
2567     assert(s.length == 2);
2568     assert(s[0] == 1);
2569     assert(s[1] == 1);
2570 }
2571 
2572 // https://issues.dlang.org/show_bug.cgi?id=13151
2573 pure @safe nothrow @nogc unittest
2574 {
2575     import std.algorithm.comparison : equal;
2576 
2577     auto r = take(repeat(1, 4), 3);
2578     assert(r.take(2).equal(repeat(1, 2)));
2579 }
2580 
2581 
2582 /**
2583 Similar to $(LREF take), but assumes that `range` has at least $(D
2584 n) elements. Consequently, the result of $(D takeExactly(range, n))
2585 always defines the `length` property (and initializes it to `n`)
2586 even when `range` itself does not define `length`.
2587 
2588 The result of `takeExactly` is identical to that of $(LREF take) in
2589 cases where the original range defines `length` or is infinite.
2590 
2591 Unlike $(LREF take), however, it is illegal to pass a range with less than
2592 `n` elements to `takeExactly`; this will cause an assertion failure.
2593  */
2594 auto takeExactly(R)(R range, size_t n)
2595 if (isInputRange!R)
2596 {
2597     static if (is(typeof(takeExactly(range._input, n)) == R))
2598     {
2599         assert(n <= range._n,
2600                "Attempted to take more than the length of the range with takeExactly.");
2601         // takeExactly(takeExactly(r, n1), n2) has the same type as
2602         // takeExactly(r, n1) and simply returns takeExactly(r, n2)
2603         range._n = n;
2604         return range;
2605     }
2606     //Also covers hasSlicing!R for finite ranges.
2607     else static if (hasLength!R)
2608     {
2609         assert(n <= range.length,
2610                "Attempted to take more than the length of the range with takeExactly.");
2611         return take(range, n);
2612     }
2613     else static if (isInfinite!R)
2614         return Take!R(range, n);
2615     else
2616     {
2617         static struct Result
2618         {
2619             R _input;
2620             private size_t _n;
2621 
2622             @property bool empty() const { return !_n; }
2623             @property auto ref front()
2624             {
2625                 assert(_n > 0, "front() on an empty " ~ Result.stringof);
2626                 return _input.front;
2627             }
2628             void popFront() { _input.popFront(); --_n; }
2629             @property size_t length() const { return _n; }
2630             alias opDollar = length;
2631 
2632             @property auto _takeExactly_Result_asTake()
2633             {
2634                 return take(_input, _n);
2635             }
2636 
2637             alias _takeExactly_Result_asTake this;
2638 
2639             static if (isForwardRange!R)
2640                 @property auto save()
2641                 {
2642                     return Result(_input.save, _n);
2643                 }
2644 
2645             static if (hasMobileElements!R)
2646             {
2647                 auto moveFront()
2648                 {
2649                     assert(!empty,
2650                         "Attempting to move the front of an empty "
2651                         ~ typeof(this).stringof);
2652                     return _input.moveFront();
2653                 }
2654             }
2655 
2656             static if (hasAssignableElements!R)
2657             {
2658                 @property auto ref front(ElementType!R v)
2659                 {
2660                     assert(!empty,
2661                         "Attempting to assign to the front of an empty "
2662                         ~ typeof(this).stringof);
2663                     return _input.front = v;
2664                 }
2665             }
2666         }
2667 
2668         return Result(range, n);
2669     }
2670 }
2671 
2672 ///
2673 pure @safe nothrow unittest
2674 {
2675     import std.algorithm.comparison : equal;
2676 
2677     auto a = [ 1, 2, 3, 4, 5 ];
2678 
2679     auto b = takeExactly(a, 3);
2680     assert(equal(b, [1, 2, 3]));
2681     static assert(is(typeof(b.length) == size_t));
2682     assert(b.length == 3);
2683     assert(b.front == 1);
2684     assert(b.back == 3);
2685 }
2686 
2687 pure @safe nothrow unittest
2688 {
2689     import std.algorithm.comparison : equal;
2690     import std.algorithm.iteration : filter;
2691 
2692     auto a = [ 1, 2, 3, 4, 5 ];
2693     auto b = takeExactly(a, 3);
2694     assert(equal(b, [1, 2, 3]));
2695     auto c = takeExactly(b, 2);
2696     assert(equal(c, [1, 2]));
2697 
2698 
2699 
2700     auto d = filter!"a > 2"(a);
2701     auto e = takeExactly(d, 3);
2702     assert(equal(e, [3, 4, 5]));
2703     static assert(is(typeof(e.length) == size_t));
2704     assert(e.length == 3);
2705     assert(e.front == 3);
2706 
2707     assert(equal(takeExactly(e, 3), [3, 4, 5]));
2708 }
2709 
2710 pure @safe nothrow unittest
2711 {
2712     import std.algorithm.comparison : equal;
2713     import std.internal.test.dummyrange : AllDummyRanges;
2714 
2715     auto a = [ 1, 2, 3, 4, 5 ];
2716     //Test that take and takeExactly are the same for ranges which define length
2717     //but aren't sliceable.
2718     struct L
2719     {
2720         @property auto front() { return _arr[0]; }
2721         @property bool empty() { return _arr.empty; }
2722         void popFront() { _arr.popFront(); }
2723         @property size_t length() { return _arr.length; }
2724         int[] _arr;
2725     }
2726     static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
2727     assert(take(L(a), 3) == takeExactly(L(a), 3));
2728 
2729     //Test that take and takeExactly are the same for ranges which are sliceable.
2730     static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
2731     assert(take(a, 3) == takeExactly(a, 3));
2732 
2733     //Test that take and takeExactly are the same for infinite ranges.
2734     auto inf = repeat(1);
2735     static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
2736     assert(take(inf, 5) == takeExactly(inf, 5));
2737 
2738     //Test that take and takeExactly are _not_ the same for ranges which don't
2739     //define length.
2740     static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
2741 
2742     foreach (DummyType; AllDummyRanges)
2743     {
2744         {
2745             DummyType dummy;
2746             auto t = takeExactly(dummy, 5);
2747 
2748             //Test that takeExactly doesn't wrap the result of takeExactly.
2749             assert(takeExactly(t, 4) == takeExactly(dummy, 4));
2750         }
2751 
2752         static if (hasMobileElements!DummyType)
2753         {
2754             {
2755                 auto t = takeExactly(DummyType.init, 4);
2756                 assert(t.moveFront() == 1);
2757                 assert(equal(t, [1, 2, 3, 4]));
2758             }
2759         }
2760 
2761         static if (hasAssignableElements!DummyType)
2762         {
2763             {
2764                 auto t = takeExactly(DummyType.init, 4);
2765                 t.front = 9;
2766                 assert(equal(t, [9, 2, 3, 4]));
2767             }
2768         }
2769     }
2770 }
2771 
2772 pure @safe nothrow unittest
2773 {
2774     import std.algorithm.comparison : equal;
2775     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2776 
2777     alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
2778     auto te = takeExactly(DummyType(), 5);
2779     Take!DummyType t = te;
2780     assert(equal(t, [1, 2, 3, 4, 5]));
2781     assert(equal(t, te));
2782 }
2783 
2784 // https://issues.dlang.org/show_bug.cgi?id=18092
2785 // can't combine take and takeExactly
2786 @safe unittest
2787 {
2788     import std.algorithm.comparison : equal;
2789     import std.internal.test.dummyrange : AllDummyRanges;
2790 
2791     static foreach (Range; AllDummyRanges)
2792     {{
2793         Range r;
2794         assert(r.take(6).takeExactly(2).equal([1, 2]));
2795         assert(r.takeExactly(6).takeExactly(2).equal([1, 2]));
2796         assert(r.takeExactly(6).take(2).equal([1, 2]));
2797     }}
2798 }
2799 
2800 /**
2801 Returns a range with at most one element; for example, $(D
2802 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
2803 42). Calling `popFront()` off that range renders it empty.
2804 
2805 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in
2806 certain interfaces it is important to know statically that the range may only
2807 have at most one element.
2808 
2809 The type returned by `takeOne` is a random-access range with length
2810 regardless of `R`'s capabilities, as long as it is a forward range.
2811 (another feature that distinguishes `takeOne` from `take`). If
2812 (D R) is an input range but not a forward range, return type is an input
2813 range with all random-access capabilities except save.
2814  */
2815 auto takeOne(R)(R source)
2816 if (isInputRange!R)
2817 {
2818     static if (hasSlicing!R)
2819     {
2820         return source[0 .. !source.empty];
2821     }
2822     else
2823     {
2824         static struct Result
2825         {
2826             private R _source;
2827             private bool _empty = true;
2828             @property bool empty() const { return _empty; }
2829             @property auto ref front()
2830             {
2831                 assert(!empty, "Attempting to fetch the front of an empty takeOne");
2832                 return _source.front;
2833             }
2834             void popFront()
2835             {
2836                 assert(!empty, "Attempting to popFront an empty takeOne");
2837                 _source.popFront();
2838                 _empty = true;
2839             }
2840             void popBack()
2841             {
2842                 assert(!empty, "Attempting to popBack an empty takeOne");
2843                 _source.popFront();
2844                 _empty = true;
2845             }
2846             static if (isForwardRange!(Unqual!R))
2847             {
2848                 @property auto save() { return Result(_source.save, empty); }
2849             }
2850             @property auto ref back()
2851             {
2852                 assert(!empty, "Attempting to fetch the back of an empty takeOne");
2853                 return _source.front;
2854             }
2855             @property size_t length() const { return !empty; }
2856             alias opDollar = length;
2857             auto ref opIndex(size_t n)
2858             {
2859                 assert(n < length, "Attempting to index a takeOne out of bounds");
2860                 return _source.front;
2861             }
2862             auto opSlice(size_t m, size_t n)
2863             {
2864                 assert(
2865                     m <= n,
2866                     "Attempting to slice a takeOne range with a larger first argument than the second."
2867                 );
2868                 assert(
2869                     n <= length,
2870                     "Attempting to slice using an out of bounds index on a takeOne range."
2871                     );
2872                 return n > m ? this : Result(_source, true);
2873             }
2874             // Non-standard property
2875             @property R source() { return _source; }
2876         }
2877 
2878         return Result(source, source.empty);
2879     }
2880 }
2881 
2882 ///
2883 pure @safe nothrow unittest
2884 {
2885     auto s = takeOne([42, 43, 44]);
2886     static assert(isRandomAccessRange!(typeof(s)));
2887     assert(s.length == 1);
2888     assert(!s.empty);
2889     assert(s.front == 42);
2890     s.front = 43;
2891     assert(s.front == 43);
2892     assert(s.back == 43);
2893     assert(s[0] == 43);
2894     s.popFront();
2895     assert(s.length == 0);
2896     assert(s.empty);
2897 }
2898 
2899 pure @safe nothrow @nogc unittest
2900 {
2901     struct NonForwardRange
2902     {
2903         enum empty = false;
2904         int front() { return 42; }
2905         void popFront() {}
2906     }
2907 
2908     static assert(!isForwardRange!NonForwardRange);
2909 
2910     auto s = takeOne(NonForwardRange());
2911     assert(s.length == 1);
2912     assert(!s.empty);
2913     assert(s.front == 42);
2914     assert(s.back == 42);
2915     assert(s[0] == 42);
2916 
2917     auto t = s[0 .. 0];
2918     assert(t.empty);
2919     assert(t.length == 0);
2920 
2921     auto u = s[1 .. 1];
2922     assert(u.empty);
2923     assert(u.length == 0);
2924 
2925     auto v = s[0 .. 1];
2926     s.popFront();
2927     assert(s.length == 0);
2928     assert(s.empty);
2929     assert(!v.empty);
2930     assert(v.front == 42);
2931     v.popBack();
2932     assert(v.empty);
2933     assert(v.length == 0);
2934 }
2935 
2936 pure @safe nothrow @nogc unittest
2937 {
2938     struct NonSlicingForwardRange
2939     {
2940         enum empty = false;
2941         int front() { return 42; }
2942         void popFront() {}
2943         @property auto save() { return this; }
2944     }
2945 
2946     static assert(isForwardRange!NonSlicingForwardRange);
2947     static assert(!hasSlicing!NonSlicingForwardRange);
2948 
2949     auto s = takeOne(NonSlicingForwardRange());
2950     assert(s.length == 1);
2951     assert(!s.empty);
2952     assert(s.front == 42);
2953     assert(s.back == 42);
2954     assert(s[0] == 42);
2955     auto t = s.save;
2956     s.popFront();
2957     assert(s.length == 0);
2958     assert(s.empty);
2959     assert(!t.empty);
2960     assert(t.front == 42);
2961     t.popBack();
2962     assert(t.empty);
2963     assert(t.length == 0);
2964 }
2965 
2966 // Test that asserts trigger correctly
2967 @system unittest
2968 {
2969     import std.exception : assertThrown;
2970     import core.exception : AssertError;
2971 
2972     struct NonForwardRange
2973     {
2974         enum empty = false;
2975         int front() { return 42; }
2976         void popFront() {}
2977     }
2978 
2979     auto s = takeOne(NonForwardRange());
2980 
2981     assertThrown!AssertError(s[1]);
2982     assertThrown!AssertError(s[0 .. 2]);
2983 
2984     size_t one = 1;     // Avoid style warnings triggered by literals
2985     size_t zero = 0;
2986     assertThrown!AssertError(s[one .. zero]);
2987 
2988     s.popFront;
2989     assert(s.empty);
2990     assertThrown!AssertError(s.front);
2991     assertThrown!AssertError(s.back);
2992     assertThrown!AssertError(s.popFront);
2993     assertThrown!AssertError(s.popBack);
2994 }
2995 
2996 // https://issues.dlang.org/show_bug.cgi?id=16999
2997 pure @safe unittest
2998 {
2999     auto myIota = new class
3000     {
3001         int front = 0;
3002         @safe void popFront(){front++;}
3003         enum empty = false;
3004     };
3005     auto iotaPart = myIota.takeOne;
3006     int sum;
3007     foreach (var; chain(iotaPart, iotaPart, iotaPart))
3008     {
3009         sum += var;
3010     }
3011     assert(sum == 3);
3012     assert(iotaPart.front == 3);
3013 }
3014 
3015 /++
3016     Returns an empty range which is statically known to be empty and is
3017     guaranteed to have `length` and be random access regardless of `R`'s
3018     capabilities.
3019   +/
3020 auto takeNone(R)()
3021 if (isInputRange!R)
3022 {
3023     return typeof(takeOne(R.init)).init;
3024 }
3025 
3026 ///
3027 pure @safe nothrow @nogc unittest
3028 {
3029     auto range = takeNone!(int[])();
3030     assert(range.length == 0);
3031     assert(range.empty);
3032 }
3033 
3034 pure @safe nothrow @nogc unittest
3035 {
3036     enum ctfe = takeNone!(int[])();
3037     static assert(ctfe.length == 0);
3038     static assert(ctfe.empty);
3039 }
3040 
3041 
3042 /++
3043     Creates an empty range from the given range in $(BIGOH 1). If it can, it
3044     will return the same range type. If not, it will return
3045     $(D takeExactly(range, 0)).
3046   +/
3047 auto takeNone(R)(R range)
3048 if (isInputRange!R)
3049 {
3050     import std.traits : isDynamicArray;
3051     //Makes it so that calls to takeNone which don't use UFCS still work with a
3052     //member version if it's defined.
3053     static if (is(typeof(R.takeNone)))
3054         auto retval = range.takeNone();
3055     // https://issues.dlang.org/show_bug.cgi?id=8339
3056     else static if (isDynamicArray!R)/+ ||
3057                    (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
3058     {
3059         auto retval = R.init;
3060     }
3061     //An infinite range sliced at [0 .. 0] would likely still not be empty...
3062     else static if (hasSlicing!R && !isInfinite!R)
3063         auto retval = range[0 .. 0];
3064     else
3065         auto retval = takeExactly(range, 0);
3066 
3067     // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being
3068     // done in an out block.
3069     assert(retval.empty);
3070     return retval;
3071 }
3072 
3073 ///
3074 pure @safe nothrow unittest
3075 {
3076     import std.algorithm.iteration : filter;
3077     assert(takeNone([42, 27, 19]).empty);
3078     assert(takeNone("dlang.org").empty);
3079     assert(takeNone(filter!"true"([42, 27, 19])).empty);
3080 }
3081 
3082 @safe unittest
3083 {
3084     import std.algorithm.iteration : filter;
3085     import std.meta : AliasSeq;
3086 
3087     struct Dummy
3088     {
3089         mixin template genInput()
3090         {
3091         @safe:
3092             @property bool empty() { return _arr.empty; }
3093             @property auto front() { return _arr.front; }
3094             void popFront() { _arr.popFront(); }
3095             static assert(isInputRange!(typeof(this)));
3096         }
3097     }
3098     alias genInput = Dummy.genInput;
3099 
3100     static struct NormalStruct
3101     {
3102         //Disabled to make sure that the takeExactly version is used.
3103         @disable this();
3104         this(int[] arr) { _arr = arr; }
3105         mixin genInput;
3106         int[] _arr;
3107     }
3108 
3109     static struct SliceStruct
3110     {
3111         @disable this();
3112         this(int[] arr) { _arr = arr; }
3113         mixin genInput;
3114         @property auto save() { return this; }
3115         auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
3116         @property size_t length() { return _arr.length; }
3117         int[] _arr;
3118     }
3119 
3120     static struct InitStruct
3121     {
3122         mixin genInput;
3123         int[] _arr;
3124     }
3125 
3126     static struct TakeNoneStruct
3127     {
3128         this(int[] arr) { _arr = arr; }
3129         @disable this();
3130         mixin genInput;
3131         auto takeNone() { return typeof(this)(null); }
3132         int[] _arr;
3133     }
3134 
3135     static class NormalClass
3136     {
3137         this(int[] arr) {_arr = arr;}
3138         mixin genInput;
3139         int[] _arr;
3140     }
3141 
3142     static class SliceClass
3143     {
3144     @safe:
3145         this(int[] arr) { _arr = arr; }
3146         mixin genInput;
3147         @property auto save() { return new typeof(this)(_arr); }
3148         auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
3149         @property size_t length() { return _arr.length; }
3150         int[] _arr;
3151     }
3152 
3153     static class TakeNoneClass
3154     {
3155     @safe:
3156         this(int[] arr) { _arr = arr; }
3157         mixin genInput;
3158         auto takeNone() { return new typeof(this)(null); }
3159         int[] _arr;
3160     }
3161 
3162     import std.format : format;
3163 
3164     static foreach (range; AliasSeq!([1, 2, 3, 4, 5],
3165                              "hello world",
3166                              "hello world"w,
3167                              "hello world"d,
3168                              SliceStruct([1, 2, 3]),
3169                              // https://issues.dlang.org/show_bug.cgi?id=8339
3170                              // forces this to be takeExactly `InitStruct([1, 2, 3]),
3171                              TakeNoneStruct([1, 2, 3])))
3172     {
3173         static assert(takeNone(range).empty, typeof(range).stringof);
3174         assert(takeNone(range).empty);
3175         static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
3176     }
3177 
3178     static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
3179                              InitStruct([1, 2, 3])))
3180     {
3181         static assert(takeNone(range).empty, typeof(range).stringof);
3182         assert(takeNone(range).empty);
3183         static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
3184     }
3185 
3186     //Don't work in CTFE.
3187     auto normal = new NormalClass([1, 2, 3]);
3188     assert(takeNone(normal).empty);
3189     static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
3190 
3191     auto slice = new SliceClass([1, 2, 3]);
3192     assert(takeNone(slice).empty);
3193     static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
3194 
3195     auto taken = new TakeNoneClass([1, 2, 3]);
3196     assert(takeNone(taken).empty);
3197     static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
3198 
3199     auto filtered = filter!"true"([1, 2, 3, 4, 5]);
3200     assert(takeNone(filtered).empty);
3201     // https://issues.dlang.org/show_bug.cgi?id=8339 and
3202     // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly
3203     //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
3204 }
3205 
3206 /++
3207  + Return a range advanced to within `_n` elements of the end of
3208  + `range`.
3209  +
3210  + Intended as the range equivalent of the Unix
3211  + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
3212  + of `range` is less than or equal to `_n`, `range` is returned
3213  + as-is.
3214  +
3215  + Completes in $(BIGOH 1) steps for ranges that support slicing and have
3216  + length. Completes in $(BIGOH range.length) time for all other ranges.
3217  +
3218  + Params:
3219  +    range = range to get _tail of
3220  +    n = maximum number of elements to include in _tail
3221  +
3222  + Returns:
3223  +    Returns the _tail of `range` augmented with length information
3224  +/
3225 auto tail(Range)(Range range, size_t n)
3226 if (isInputRange!Range && !isInfinite!Range &&
3227     (hasLength!Range || isForwardRange!Range))
3228 {
3229     static if (hasLength!Range)
3230     {
3231         immutable length = range.length;
3232         if (n >= length)
3233             return range.takeExactly(length);
3234         else
3235             return range.drop(length - n).takeExactly(n);
3236     }
3237     else
3238     {
3239         Range scout = range.save;
3240         foreach (immutable i; 0 .. n)
3241         {
3242             if (scout.empty)
3243                 return range.takeExactly(i);
3244             scout.popFront();
3245         }
3246 
3247         auto tail = range.save;
3248         while (!scout.empty)
3249         {
3250             assert(!tail.empty);
3251             scout.popFront();
3252             tail.popFront();
3253         }
3254 
3255         return tail.takeExactly(n);
3256     }
3257 }
3258 
3259 ///
3260 pure @safe nothrow unittest
3261 {
3262     // tail -c n
3263     assert([1, 2, 3].tail(1) == [3]);
3264     assert([1, 2, 3].tail(2) == [2, 3]);
3265     assert([1, 2, 3].tail(3) == [1, 2, 3]);
3266     assert([1, 2, 3].tail(4) == [1, 2, 3]);
3267     assert([1, 2, 3].tail(0).length == 0);
3268 
3269     // tail --lines=n
3270     import std.algorithm.comparison : equal;
3271     import std.algorithm.iteration : joiner;
3272     import std.exception : assumeWontThrow;
3273     import std..string : lineSplitter;
3274     assert("one\ntwo\nthree"
3275         .lineSplitter
3276         .tail(2)
3277         .joiner("\n")
3278         .equal("two\nthree")
3279         .assumeWontThrow);
3280 }
3281 
3282 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408
3283 pure nothrow @safe /+@nogc+/ unittest
3284 {
3285     import std.algorithm.comparison : equal;
3286     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
3287         RangeType, ReturnBy;
3288 
3289     static immutable cheatsheet = [6, 7, 8, 9, 10];
3290 
3291     foreach (R; AllDummyRanges)
3292     {
3293         static if (isInputRange!R && !isInfinite!R &&
3294                    (hasLength!R || isForwardRange!R))
3295         {
3296             assert(R.init.tail(5).equal(cheatsheet));
3297             static assert(R.init.tail(5).equal(cheatsheet));
3298 
3299             assert(R.init.tail(0).length == 0);
3300             assert(R.init.tail(10).equal(R.init));
3301             assert(R.init.tail(11).equal(R.init));
3302         }
3303     }
3304 
3305     // Infinite ranges are not supported
3306     static assert(!__traits(compiles, repeat(0).tail(0)));
3307 
3308     // Neither are non-forward ranges without length
3309     static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
3310         RangeType.Input).init.tail(5)));
3311 }
3312 
3313 pure @safe nothrow @nogc unittest
3314 {
3315     static immutable input = [1, 2, 3];
3316     static immutable expectedOutput = [2, 3];
3317     assert(input.tail(2) == expectedOutput);
3318 }
3319 
3320 /++
3321     Convenience function which calls
3322     $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`.
3323     `drop` makes it easier to pop elements from a range
3324     and then pass it to another function within a single expression,
3325     whereas `popFrontN` would require multiple statements.
3326 
3327     `dropBack` provides the same functionality but instead calls
3328     $(REF popBackN, std, range, primitives)`(range, n)`
3329 
3330     Note: `drop` and `dropBack` will only pop $(I up to)
3331     `n` elements but will stop if the range is empty first.
3332     In other languages this is sometimes called `skip`.
3333 
3334     Params:
3335         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3336         n = the number of elements to drop
3337 
3338     Returns:
3339         `range` with up to `n` elements dropped
3340 
3341     See_Also:
3342         $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives)
3343   +/
3344 R drop(R)(R range, size_t n)
3345 if (isInputRange!R)
3346 {
3347     range.popFrontN(n);
3348     return range;
3349 }
3350 
3351 ///
3352 @safe unittest
3353 {
3354     import std.algorithm.comparison : equal;
3355 
3356     assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
3357     assert("hello world".drop(6) == "world");
3358     assert("hello world".drop(50).empty);
3359     assert("hello world".take(6).drop(3).equal("lo "));
3360 }
3361 
3362 /// ditto
3363 R dropBack(R)(R range, size_t n)
3364 if (isBidirectionalRange!R)
3365 {
3366     range.popBackN(n);
3367     return range;
3368 }
3369 
3370 ///
3371 @safe unittest
3372 {
3373     import std.algorithm.comparison : equal;
3374 
3375     assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
3376     assert("hello world".dropBack(6) == "hello");
3377     assert("hello world".dropBack(50).empty);
3378     assert("hello world".drop(4).dropBack(4).equal("o w"));
3379 }
3380 
3381 @safe unittest
3382 {
3383     import std.algorithm.comparison : equal;
3384     import std.container.dlist : DList;
3385 
3386     //Remove all but the first two elements
3387     auto a = DList!int(0, 1, 9, 9, 9, 9);
3388     a.remove(a[].drop(2));
3389     assert(a[].equal(a[].take(2)));
3390 }
3391 
3392 @safe unittest
3393 {
3394     import std.algorithm.comparison : equal;
3395     import std.algorithm.iteration : filter;
3396 
3397     assert(drop("", 5).empty);
3398     assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3399 }
3400 
3401 @safe unittest
3402 {
3403     import std.algorithm.comparison : equal;
3404     import std.container.dlist : DList;
3405 
3406     //insert before the last two elements
3407     auto a = DList!int(0, 1, 2, 5, 6);
3408     a.insertAfter(a[].dropBack(2), [3, 4]);
3409     assert(a[].equal(iota(0, 7)));
3410 }
3411 
3412 /++
3413     Similar to $(LREF drop) and `dropBack` but they call
3414     $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)`
3415     instead.
3416 
3417     Note: Unlike `drop`, `dropExactly` will assume that the
3418     range holds at least `n` elements. This makes `dropExactly`
3419     faster than `drop`, but it also means that if `range` does
3420     not contain at least `n` elements, it will attempt to call `popFront`
3421     on an empty range, which is undefined behavior. So, only use
3422     `popFrontExactly` when it is guaranteed that `range` holds at least
3423     `n` elements.
3424 
3425     Params:
3426         range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3427         n = the number of elements to drop
3428 
3429     Returns:
3430         `range` with `n` elements dropped
3431 
3432     See_Also:
3433         $(REF popFrontExcatly, std, range, primitives),
3434         $(REF popBackExcatly, std, range, primitives)
3435 +/
3436 R dropExactly(R)(R range, size_t n)
3437 if (isInputRange!R)
3438 {
3439     popFrontExactly(range, n);
3440     return range;
3441 }
3442 /// ditto
3443 R dropBackExactly(R)(R range, size_t n)
3444 if (isBidirectionalRange!R)
3445 {
3446     popBackExactly(range, n);
3447     return range;
3448 }
3449 
3450 ///
3451 @safe unittest
3452 {
3453     import std.algorithm.comparison : equal;
3454     import std.algorithm.iteration : filterBidirectional;
3455 
3456     auto a = [1, 2, 3];
3457     assert(a.dropExactly(2) == [3]);
3458     assert(a.dropBackExactly(2) == [1]);
3459 
3460     string s = "日本語";
3461     assert(s.dropExactly(2) == "語");
3462     assert(s.dropBackExactly(2) == "日");
3463 
3464     auto bd = filterBidirectional!"true"([1, 2, 3]);
3465     assert(bd.dropExactly(2).equal([3]));
3466     assert(bd.dropBackExactly(2).equal([1]));
3467 }
3468 
3469 /++
3470     Convenience function which calls
3471     `range.popFront()` and returns `range`. `dropOne`
3472     makes it easier to pop an element from a range
3473     and then pass it to another function within a single expression,
3474     whereas `popFront` would require multiple statements.
3475 
3476     `dropBackOne` provides the same functionality but instead calls
3477     `range.popBack()`.
3478 +/
3479 R dropOne(R)(R range)
3480 if (isInputRange!R)
3481 {
3482     range.popFront();
3483     return range;
3484 }
3485 /// ditto
3486 R dropBackOne(R)(R range)
3487 if (isBidirectionalRange!R)
3488 {
3489     range.popBack();
3490     return range;
3491 }
3492 
3493 ///
3494 pure @safe nothrow unittest
3495 {
3496     import std.algorithm.comparison : equal;
3497     import std.algorithm.iteration : filterBidirectional;
3498     import std.container.dlist : DList;
3499 
3500     auto dl = DList!int(9, 1, 2, 3, 9);
3501     assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
3502 
3503     auto a = [1, 2, 3];
3504     assert(a.dropOne() == [2, 3]);
3505     assert(a.dropBackOne() == [1, 2]);
3506 
3507     string s = "日本語";
3508     import std.exception : assumeWontThrow;
3509     assert(assumeWontThrow(s.dropOne() == "本語"));
3510     assert(assumeWontThrow(s.dropBackOne() == "日本"));
3511 
3512     auto bd = filterBidirectional!"true"([1, 2, 3]);
3513     assert(bd.dropOne().equal([2, 3]));
3514     assert(bd.dropBackOne().equal([1, 2]));
3515 }
3516 
3517 /**
3518 Create a range which repeats one value.
3519 
3520 Params:
3521     value = the _value to repeat
3522     n = the number of times to repeat `value`
3523 
3524 Returns:
3525     If `n` is not defined, an infinite random access range
3526     with slicing.
3527 
3528     If `n` is defined, a random access range with slicing.
3529 */
3530 struct Repeat(T)
3531 {
3532 private:
3533     //Store a non-qualified T when possible: This is to make Repeat assignable
3534     static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable)))
3535     {
3536         import std.typecons : Rebindable;
3537         alias UT = Rebindable!T;
3538     }
3539     else static if (is(T : Unqual!T) && is(Unqual!T : T))
3540         alias UT = Unqual!T;
3541     else
3542         alias UT = T;
3543     UT _value;
3544 
3545 public:
3546     /// Range primitives
3547     @property inout(T) front() inout { return _value; }
3548 
3549     /// ditto
3550     @property inout(T) back() inout { return _value; }
3551 
3552     /// ditto
3553     enum bool empty = false;
3554 
3555     /// ditto
3556     void popFront() {}
3557 
3558     /// ditto
3559     void popBack() {}
3560 
3561     /// ditto
3562     @property auto save() inout { return this; }
3563 
3564     /// ditto
3565     inout(T) opIndex(size_t) inout { return _value; }
3566 
3567     /// ditto
3568     auto opSlice(size_t i, size_t j)
3569     in
3570     {
3571         assert(
3572             i <= j,
3573             "Attempting to slice a Repeat with a larger first argument than the second."
3574         );
3575     }
3576     do
3577     {
3578         return this.takeExactly(j - i);
3579     }
3580     private static struct DollarToken {}
3581 
3582     /// ditto
3583     enum opDollar = DollarToken.init;
3584 
3585     /// ditto
3586     auto opSlice(size_t, DollarToken) inout { return this; }
3587 }
3588 
3589 /// Ditto
3590 Repeat!T repeat(T)(T value) { return Repeat!T(value); }
3591 
3592 ///
3593 pure @safe nothrow unittest
3594 {
3595     import std.algorithm.comparison : equal;
3596 
3597     assert(5.repeat().take(4).equal([5, 5, 5, 5]));
3598 }
3599 
3600 pure @safe nothrow unittest
3601 {
3602     import std.algorithm.comparison : equal;
3603 
3604     auto  r = repeat(5);
3605     alias R = typeof(r);
3606     static assert(isBidirectionalRange!R);
3607     static assert(isForwardRange!R);
3608     static assert(isInfinite!R);
3609     static assert(hasSlicing!R);
3610 
3611     assert(r.back == 5);
3612     assert(r.front == 5);
3613     assert(r.take(4).equal([ 5, 5, 5, 5 ]));
3614     assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
3615 
3616     R r2 = r[5 .. $];
3617     assert(r2.back == 5);
3618     assert(r2.front == 5);
3619 }
3620 
3621 /// ditto
3622 Take!(Repeat!T) repeat(T)(T value, size_t n)
3623 {
3624     return take(repeat(value), n);
3625 }
3626 
3627 ///
3628 pure @safe nothrow unittest
3629 {
3630     import std.algorithm.comparison : equal;
3631 
3632     assert(5.repeat(4).equal([5, 5, 5, 5]));
3633 }
3634 
3635 // https://issues.dlang.org/show_bug.cgi?id=12007
3636 pure @safe nothrow unittest
3637 {
3638     static class C{}
3639     Repeat!(immutable int) ri;
3640     ri = ri.save;
3641     Repeat!(immutable C) rc;
3642     rc = rc.save;
3643 
3644     import std.algorithm.setops : cartesianProduct;
3645     import std.algorithm.comparison : equal;
3646     import std.typecons : tuple;
3647     immutable int[] A = [1,2,3];
3648     immutable int[] B = [4,5,6];
3649 
3650     assert(equal(cartesianProduct(A,B),
3651         [
3652             tuple(1, 4), tuple(1, 5), tuple(1, 6),
3653             tuple(2, 4), tuple(2, 5), tuple(2, 6),
3654             tuple(3, 4), tuple(3, 5), tuple(3, 6),
3655         ]));
3656 }
3657 
3658 /**
3659 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
3660 whose front is defined by successive calls to `fun()`.
3661 This is especially useful to call function with global side effects (random
3662 functions), or to create ranges expressed as a single delegate, rather than
3663 an entire `front`/`popFront`/`empty` structure.
3664 `fun` maybe be passed either a template alias parameter (existing
3665 function, delegate, struct type defining `static opCall`) or
3666 a run-time value argument (delegate, function object).
3667 The result range models an InputRange
3668 ($(REF isInputRange, std,range,primitives)).
3669 The resulting range will call `fun()` on construction, and every call to
3670 `popFront`, and the cached value will be returned when `front` is called.
3671 
3672 Returns: an `inputRange` where each element represents another call to fun.
3673 */
3674 auto generate(Fun)(Fun fun)
3675 if (isCallable!fun)
3676 {
3677     auto gen = Generator!(Fun)(fun);
3678     gen.popFront(); // prime the first element
3679     return gen;
3680 }
3681 
3682 /// ditto
3683 auto generate(alias fun)()
3684 if (isCallable!fun)
3685 {
3686     auto gen = Generator!(fun)();
3687     gen.popFront(); // prime the first element
3688     return gen;
3689 }
3690 
3691 ///
3692 @safe pure nothrow unittest
3693 {
3694     import std.algorithm.comparison : equal;
3695     import std.algorithm.iteration : map;
3696 
3697     int i = 1;
3698     auto powersOfTwo = generate!(() => i *= 2)().take(10);
3699     assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
3700 }
3701 
3702 ///
3703 @safe pure nothrow unittest
3704 {
3705     import std.algorithm.comparison : equal;
3706 
3707     //Returns a run-time delegate
3708     auto infiniteIota(T)(T low, T high)
3709     {
3710         T i = high;
3711         return (){if (i == high) i = low; return i++;};
3712     }
3713     //adapted as a range.
3714     assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
3715 }
3716 
3717 ///
3718 @safe unittest
3719 {
3720     import std.format : format;
3721     import std.random : uniform;
3722 
3723     auto r = generate!(() => uniform(0, 6)).take(10);
3724     format("%(%s %)", r);
3725 }
3726 
3727 private struct Generator(Fun...)
3728 {
3729     static assert(Fun.length == 1);
3730     static assert(isInputRange!Generator);
3731     import std.traits : FunctionAttribute, functionAttributes, ReturnType;
3732 
3733 private:
3734     static if (is(Fun[0]))
3735         Fun[0] fun;
3736     else
3737         alias fun = Fun[0];
3738 
3739     enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
3740     static if (returnByRef_)
3741         ReturnType!fun *elem_;
3742     else
3743         ReturnType!fun elem_;
3744 public:
3745     /// Range primitives
3746     enum empty = false;
3747 
3748     static if (returnByRef_)
3749     {
3750         /// ditto
3751         ref front() @property
3752         {
3753             return *elem_;
3754         }
3755         /// ditto
3756         void popFront()
3757         {
3758             elem_ = &fun();
3759         }
3760     }
3761     else
3762     {
3763         /// ditto
3764         auto front() @property
3765         {
3766             return elem_;
3767         }
3768         /// ditto
3769         void popFront()
3770         {
3771             elem_ = fun();
3772         }
3773     }
3774 }
3775 
3776 @safe nothrow unittest
3777 {
3778     import std.algorithm.comparison : equal;
3779 
3780     struct StaticOpCall
3781     {
3782         static ubyte opCall() { return 5 ; }
3783     }
3784 
3785     assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
3786 }
3787 
3788 @safe pure unittest
3789 {
3790     import std.algorithm.comparison : equal;
3791 
3792     struct OpCall
3793     {
3794         ubyte opCall() @safe pure { return 5 ; }
3795     }
3796 
3797     OpCall op;
3798     assert(equal(generate(op).take(10), repeat(5).take(10)));
3799 }
3800 
3801 // verify ref mechanism works
3802 @system nothrow unittest
3803 {
3804     int[10] arr;
3805     int idx;
3806 
3807     ref int fun() {
3808         auto x = idx++;
3809         idx %= arr.length;
3810         return arr[x];
3811     }
3812     int y = 1;
3813     foreach (ref x; generate!(fun).take(20))
3814     {
3815         x += y++;
3816     }
3817     import std.algorithm.comparison : equal;
3818     assert(equal(arr[], iota(12, 32, 2)));
3819 }
3820 
3821 // assure front isn't the mechanism to make generate go to the next element.
3822 @safe unittest
3823 {
3824     int i;
3825     auto g = generate!(() => ++i);
3826     auto f = g.front;
3827     assert(f == g.front);
3828     g = g.drop(5); // reassign because generate caches
3829     assert(g.front == f + 5);
3830 }
3831 
3832 /**
3833 Repeats the given forward range ad infinitum. If the original range is
3834 infinite (fact that would make `Cycle` the identity application),
3835 `Cycle` detects that and aliases itself to the range type
3836 itself. That works for non-forward ranges too.
3837 If the original range has random access, `Cycle` offers
3838 random access and also offers a constructor taking an initial position
3839 `index`. `Cycle` works with static arrays in addition to ranges,
3840 mostly for performance reasons.
3841 
3842 Note: The input range must not be empty.
3843 
3844 Tip: This is a great way to implement simple circular buffers.
3845 */
3846 struct Cycle(R)
3847 if (isForwardRange!R && !isInfinite!R)
3848 {
3849     static if (isRandomAccessRange!R && hasLength!R)
3850     {
3851         private R _original;
3852         private size_t _index;
3853 
3854         /// Range primitives
3855         this(R input, size_t index = 0)
3856         {
3857             _original = input;
3858             _index = index % _original.length;
3859         }
3860 
3861         /// ditto
3862         @property auto ref front()
3863         {
3864             return _original[_index];
3865         }
3866 
3867         static if (is(typeof((cast(const R)_original)[_index])))
3868         {
3869             /// ditto
3870             @property auto ref front() const
3871             {
3872                 return _original[_index];
3873             }
3874         }
3875 
3876         static if (hasAssignableElements!R)
3877         {
3878             /// ditto
3879             @property void front(ElementType!R val)
3880             {
3881                 _original[_index] = val;
3882             }
3883         }
3884 
3885         /// ditto
3886         enum bool empty = false;
3887 
3888         /// ditto
3889         void popFront()
3890         {
3891             ++_index;
3892             if (_index >= _original.length)
3893                 _index = 0;
3894         }
3895 
3896         /// ditto
3897         auto ref opIndex(size_t n)
3898         {
3899             return _original[(n + _index) % _original.length];
3900         }
3901 
3902         static if (is(typeof((cast(const R)_original)[_index])) &&
3903                    is(typeof((cast(const R)_original).length)))
3904         {
3905             /// ditto
3906             auto ref opIndex(size_t n) const
3907             {
3908                 return _original[(n + _index) % _original.length];
3909             }
3910         }
3911 
3912         static if (hasAssignableElements!R)
3913         {
3914             /// ditto
3915             void opIndexAssign(ElementType!R val, size_t n)
3916             {
3917                 _original[(n + _index) % _original.length] = val;
3918             }
3919         }
3920 
3921         /// ditto
3922         @property Cycle save()
3923         {
3924             //No need to call _original.save, because Cycle never actually modifies _original
3925             return Cycle(_original, _index);
3926         }
3927 
3928         private static struct DollarToken {}
3929 
3930         /// ditto
3931         enum opDollar = DollarToken.init;
3932 
3933         static if (hasSlicing!R)
3934         {
3935             /// ditto
3936             auto opSlice(size_t i, size_t j)
3937             in
3938             {
3939                 assert(i <= j);
3940             }
3941             do
3942             {
3943                 return this[i .. $].takeExactly(j - i);
3944             }
3945 
3946             /// ditto
3947             auto opSlice(size_t i, DollarToken)
3948             {
3949                 return typeof(this)(_original, _index + i);
3950             }
3951         }
3952     }
3953     else
3954     {
3955         private R _original;
3956         private R _current;
3957 
3958         /// ditto
3959         this(R input)
3960         {
3961             _original = input;
3962             _current = input.save;
3963         }
3964 
3965         private this(R original, R current)
3966         {
3967             _original = original;
3968             _current = current;
3969         }
3970 
3971         /// ditto
3972         @property auto ref front()
3973         {
3974             return _current.front;
3975         }
3976 
3977         static if (is(typeof((cast(const R)_current).front)))
3978         {
3979             /// ditto
3980             @property auto ref front() const
3981             {
3982                 return _current.front;
3983             }
3984         }
3985 
3986         static if (hasAssignableElements!R)
3987         {
3988             /// ditto
3989             @property auto front(ElementType!R val)
3990             {
3991                 return _current.front = val;
3992             }
3993         }
3994 
3995         /// ditto
3996         enum bool empty = false;
3997 
3998         /// ditto
3999         void popFront()
4000         {
4001             _current.popFront();
4002             if (_current.empty)
4003                 _current = _original.save;
4004         }
4005 
4006         /// ditto
4007         @property Cycle save()
4008         {
4009             //No need to call _original.save, because Cycle never actually modifies _original
4010             return Cycle(_original, _current.save);
4011         }
4012     }
4013 }
4014 
4015 /// ditto
4016 template Cycle(R)
4017 if (isInfinite!R)
4018 {
4019     alias Cycle = R;
4020 }
4021 
4022 /// ditto
4023 struct Cycle(R)
4024 if (isStaticArray!R)
4025 {
4026     private alias ElementType = typeof(R.init[0]);
4027     private ElementType* _ptr;
4028     private size_t _index;
4029 
4030 nothrow:
4031 
4032     /// Range primitives
4033     this(ref R input, size_t index = 0) @system
4034     {
4035         _ptr = input.ptr;
4036         _index = index % R.length;
4037     }
4038 
4039     /// ditto
4040     @property ref inout(ElementType) front() inout @safe
4041     {
4042         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4043         {
4044             return p[idx];
4045         }
4046         return trustedPtrIdx(_ptr, _index);
4047     }
4048 
4049     /// ditto
4050     enum bool empty = false;
4051 
4052     /// ditto
4053     void popFront() @safe
4054     {
4055         ++_index;
4056         if (_index >= R.length)
4057             _index = 0;
4058     }
4059 
4060     /// ditto
4061     ref inout(ElementType) opIndex(size_t n) inout @safe
4062     {
4063         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4064         {
4065             return p[idx % R.length];
4066         }
4067         return trustedPtrIdx(_ptr, n + _index);
4068     }
4069 
4070     /// ditto
4071     @property inout(Cycle) save() inout @safe
4072     {
4073         return this;
4074     }
4075 
4076     private static struct DollarToken {}
4077     /// ditto
4078     enum opDollar = DollarToken.init;
4079 
4080     /// ditto
4081     auto opSlice(size_t i, size_t j) @safe
4082     in
4083     {
4084         assert(
4085             i <= j,
4086             "Attempting to slice a Repeat with a larger first argument than the second."
4087         );
4088     }
4089     do
4090     {
4091         return this[i .. $].takeExactly(j - i);
4092     }
4093 
4094     /// ditto
4095     inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
4096     {
4097         static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
4098         {
4099             return cast(inout) Cycle(*cast(R*)(p), idx);
4100         }
4101         return trustedCtor(_ptr, _index + i);
4102     }
4103 }
4104 
4105 /// Ditto
4106 auto cycle(R)(R input)
4107 if (isInputRange!R)
4108 {
4109     static assert(isForwardRange!R || isInfinite!R,
4110         "Cycle requires a forward range argument unless it's statically known"
4111          ~ " to be infinite");
4112     assert(!input.empty, "Attempting to pass an empty input to cycle");
4113     static if (isInfinite!R) return input;
4114     else return Cycle!R(input);
4115 }
4116 
4117 ///
4118 @safe unittest
4119 {
4120     import std.algorithm.comparison : equal;
4121     import std.range : cycle, take;
4122 
4123     // Here we create an infinitive cyclic sequence from [1, 2]
4124     // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
4125     // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
4126     // and compare them with the expected values for equality.
4127     assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
4128 }
4129 
4130 /// Ditto
4131 Cycle!R cycle(R)(R input, size_t index = 0)
4132 if (isRandomAccessRange!R && !isInfinite!R)
4133 {
4134     assert(!input.empty, "Attempting to pass an empty input to cycle");
4135     return Cycle!R(input, index);
4136 }
4137 
4138 /// Ditto
4139 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
4140 if (isStaticArray!R)
4141 {
4142     return Cycle!R(input, index);
4143 }
4144 
4145 @safe nothrow unittest
4146 {
4147     import std.algorithm.comparison : equal;
4148     import std.internal.test.dummyrange : AllDummyRanges;
4149 
4150     static assert(isForwardRange!(Cycle!(uint[])));
4151 
4152     // Make sure ref is getting propagated properly.
4153     int[] nums = [1,2,3];
4154     auto c2 = cycle(nums);
4155     c2[3]++;
4156     assert(nums[0] == 2);
4157 
4158     immutable int[] immarr = [1, 2, 3];
4159 
4160     foreach (DummyType; AllDummyRanges)
4161     {
4162         static if (isForwardRange!DummyType)
4163         {
4164             DummyType dummy;
4165             auto cy = cycle(dummy);
4166             static assert(isForwardRange!(typeof(cy)));
4167             auto t = take(cy, 20);
4168             assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
4169 
4170             const cRange = cy;
4171             assert(cRange.front == 1);
4172 
4173             static if (hasAssignableElements!DummyType)
4174             {
4175                 {
4176                     cy.front = 66;
4177                     scope(exit) cy.front = 1;
4178                     assert(dummy.front == 66);
4179                 }
4180 
4181                 static if (isRandomAccessRange!DummyType)
4182                 {
4183                     {
4184                         cy[10] = 66;
4185                         scope(exit) cy[10] = 1;
4186                         assert(dummy.front == 66);
4187                     }
4188 
4189                     assert(cRange[10] == 1);
4190                 }
4191             }
4192 
4193             static if (hasSlicing!DummyType)
4194             {
4195                 auto slice = cy[5 .. 15];
4196                 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
4197                 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
4198 
4199                 auto infSlice = cy[7 .. $];
4200                 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
4201                 static assert(isInfinite!(typeof(infSlice)));
4202             }
4203         }
4204     }
4205 }
4206 
4207 @system nothrow unittest // For static arrays.
4208 {
4209     import std.algorithm.comparison : equal;
4210 
4211     int[3] a = [ 1, 2, 3 ];
4212     static assert(isStaticArray!(typeof(a)));
4213     auto c = cycle(a);
4214     assert(a.ptr == c._ptr);
4215     assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
4216     static assert(isForwardRange!(typeof(c)));
4217 
4218     // Test qualifiers on slicing.
4219     alias C = typeof(c);
4220     static assert(is(typeof(c[1 .. $]) == C));
4221     const cConst = c;
4222     static assert(is(typeof(cConst[1 .. $]) == const(C)));
4223 }
4224 
4225 @safe nothrow unittest // For infinite ranges
4226 {
4227     struct InfRange
4228     {
4229         void popFront() { }
4230         @property int front() { return 0; }
4231         enum empty = false;
4232         auto save() { return this; }
4233     }
4234     struct NonForwardInfRange
4235     {
4236         void popFront() { }
4237         @property int front() { return 0; }
4238         enum empty = false;
4239     }
4240 
4241     InfRange i;
4242     NonForwardInfRange j;
4243     auto c = cycle(i);
4244     assert(c == i);
4245     //make sure it can alias out even non-forward infinite ranges
4246     static assert(is(typeof(j.cycle) == typeof(j)));
4247 }
4248 
4249 @safe unittest
4250 {
4251     import std.algorithm.comparison : equal;
4252 
4253     int[5] arr = [0, 1, 2, 3, 4];
4254     auto cleD = cycle(arr[]); //Dynamic
4255     assert(equal(cleD[5 .. 10], arr[]));
4256 
4257     //n is a multiple of 5 worth about 3/4 of size_t.max
4258     auto n = size_t.max/4 + size_t.max/2;
4259     n -= n % 5;
4260 
4261     //Test index overflow
4262     foreach (_ ; 0 .. 10)
4263     {
4264         cleD = cleD[n .. $];
4265         assert(equal(cleD[5 .. 10], arr[]));
4266     }
4267 }
4268 
4269 @system @nogc nothrow unittest
4270 {
4271     import std.algorithm.comparison : equal;
4272 
4273     int[5] arr = [0, 1, 2, 3, 4];
4274     auto cleS = cycle(arr);   //Static
4275     assert(equal(cleS[5 .. 10], arr[]));
4276 
4277     //n is a multiple of 5 worth about 3/4 of size_t.max
4278     auto n = size_t.max/4 + size_t.max/2;
4279     n -= n % 5;
4280 
4281     //Test index overflow
4282     foreach (_ ; 0 .. 10)
4283     {
4284         cleS = cleS[n .. $];
4285         assert(equal(cleS[5 .. 10], arr[]));
4286     }
4287 }
4288 
4289 @system unittest
4290 {
4291     import std.algorithm.comparison : equal;
4292 
4293     int[1] arr = [0];
4294     auto cleS = cycle(arr);
4295     cleS = cleS[10 .. $];
4296     assert(equal(cleS[5 .. 10], 0.repeat(5)));
4297     assert(cleS.front == 0);
4298 }
4299 
4300 // https://issues.dlang.org/show_bug.cgi?id=10845
4301 @system unittest
4302 {
4303     import std.algorithm.comparison : equal;
4304     import std.algorithm.iteration : filter;
4305 
4306     auto a = inputRangeObject(iota(3).filter!"true");
4307     assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
4308 }
4309 
4310 // https://issues.dlang.org/show_bug.cgi?id=12177
4311 @safe unittest
4312 {
4313     static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
4314 }
4315 
4316 // https://issues.dlang.org/show_bug.cgi?id=13390
4317 @system unittest
4318 {
4319     import core.exception : AssertError;
4320     import std.exception : assertThrown;
4321     assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
4322 }
4323 
4324 // https://issues.dlang.org/show_bug.cgi?id=18657
4325 pure @safe unittest
4326 {
4327     import std.algorithm.comparison : equal;
4328     string s = "foo";
4329     auto r = refRange(&s).cycle.take(4);
4330     assert(equal(r.save, "foof"));
4331     assert(equal(r.save, "foof"));
4332 }
4333 
4334 private alias lengthType(R) = typeof(R.init.length.init);
4335 
4336 /**
4337    Iterate several ranges in lockstep. The element type is a proxy tuple
4338    that allows accessing the current element in the `n`th range by
4339    using `e[n]`.
4340 
4341    `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
4342    bundle its elements and uses the `opApply` protocol.
4343    `lockstep` allows reference access to the elements in
4344    `foreach` iterations.
4345 
4346     Params:
4347         sp = controls what `zip` will do if the ranges are different lengths
4348         ranges = the ranges to zip together
4349     Returns:
4350         At minimum, an input range. `Zip` offers the lowest range facilities
4351         of all components, e.g. it offers random access iff all ranges offer
4352         random access, and also offers mutation and swapping if all ranges offer
4353         it. Due to this, `Zip` is extremely powerful because it allows manipulating
4354         several ranges in lockstep.
4355     Throws:
4356         An `Exception` if all of the ranges are not the same length and
4357         `sp` is set to `StoppingPolicy.requireSameLength`.
4358 
4359     Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for
4360     the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This
4361     limitation is not shared by the anonymous range returned by the `zip`
4362     function when not given an explicit `StoppingPolicy` as an argument.
4363 */
4364 struct Zip(Ranges...)
4365 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4366 {
4367     import std.format : format; //for generic mixins
4368     import std.typecons : Tuple;
4369 
4370     alias R = Ranges;
4371     private R ranges;
4372     alias ElementType = Tuple!(staticMap!(.ElementType, R));
4373     private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
4374 
4375 /**
4376    Builds an object. Usually this is invoked indirectly by using the
4377    $(LREF zip) function.
4378  */
4379     this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
4380     {
4381         ranges[] = rs[];
4382         stoppingPolicy = s;
4383     }
4384 
4385 /**
4386    Returns `true` if the range is at end. The test depends on the
4387    stopping policy.
4388 */
4389     static if (allSatisfy!(isInfinite, R))
4390     {
4391         // BUG:  Doesn't propagate infiniteness if only some ranges are infinite
4392         //       and s == StoppingPolicy.longest.  This isn't fixable in the
4393         //       current design since StoppingPolicy is known only at runtime.
4394         enum bool empty = false;
4395     }
4396     else
4397     {
4398         ///
4399         @property bool empty()
4400         {
4401             import std.exception : enforce;
4402             import std.meta : anySatisfy;
4403 
4404             final switch (stoppingPolicy)
4405             {
4406             case StoppingPolicy.shortest:
4407                 foreach (i, Unused; R)
4408                 {
4409                     if (ranges[i].empty) return true;
4410                 }
4411                 return false;
4412             case StoppingPolicy.longest:
4413                 static if (anySatisfy!(isInfinite, R))
4414                 {
4415                     return false;
4416                 }
4417                 else
4418                 {
4419                     foreach (i, Unused; R)
4420                     {
4421                         if (!ranges[i].empty) return false;
4422                     }
4423                     return true;
4424                 }
4425             case StoppingPolicy.requireSameLength:
4426                 foreach (i, Unused; R[1 .. $])
4427                 {
4428                     enforce(ranges[0].empty ==
4429                             ranges[i + 1].empty,
4430                             "Inequal-length ranges passed to Zip");
4431                 }
4432                 return ranges[0].empty;
4433             }
4434             assert(false);
4435         }
4436     }
4437 
4438     static if (allSatisfy!(isForwardRange, R))
4439     {
4440         ///
4441         @property Zip save()
4442         {
4443             //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
4444             return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4445         }
4446     }
4447 
4448     private .ElementType!(R[i]) tryGetInit(size_t i)()
4449     {
4450         alias E = .ElementType!(R[i]);
4451         static if (!is(typeof({static E i;})))
4452             throw new Exception("Range with non-default constructable elements exhausted.");
4453         else
4454             return E.init;
4455     }
4456 
4457 /**
4458    Returns the current iterated element.
4459 */
4460     @property ElementType front()
4461     {
4462         @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
4463         //ElementType(tryGetFront!0, tryGetFront!1, ...)
4464         return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
4465     }
4466 
4467 /**
4468    Sets the front of all iterated ranges.
4469 */
4470     static if (allSatisfy!(hasAssignableElements, R))
4471     {
4472         @property void front(ElementType v)
4473         {
4474             foreach (i, Unused; R)
4475             {
4476                 if (!ranges[i].empty)
4477                 {
4478                     ranges[i].front = v[i];
4479                 }
4480             }
4481         }
4482     }
4483 
4484 /**
4485    Moves out the front.
4486 */
4487     static if (allSatisfy!(hasMobileElements, R))
4488     {
4489         ElementType moveFront()
4490         {
4491             @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4492             //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
4493             return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
4494         }
4495     }
4496 
4497 /**
4498    Returns the rightmost element.
4499 */
4500     static if (allSatisfy!(isBidirectionalRange, R))
4501     {
4502         @property ElementType back()
4503         {
4504             //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4505 
4506             @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
4507             //ElementType(tryGetBack!0, tryGetBack!1, ...)
4508             return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
4509         }
4510 
4511 /**
4512    Moves out the back.
4513 */
4514         static if (allSatisfy!(hasMobileElements, R))
4515         {
4516             ElementType moveBack()
4517             {
4518                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4519 
4520                 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();}
4521                 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
4522                 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
4523             }
4524         }
4525 
4526 /**
4527    Returns the current iterated element.
4528 */
4529         static if (allSatisfy!(hasAssignableElements, R))
4530         {
4531             @property void back(ElementType v)
4532             {
4533                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
4534                 //Not sure the call is even legal for StoppingPolicy.longest
4535 
4536                 foreach (i, Unused; R)
4537                 {
4538                     if (!ranges[i].empty)
4539                     {
4540                         ranges[i].back = v[i];
4541                     }
4542                 }
4543             }
4544         }
4545     }
4546 
4547 /**
4548    Advances to the next element in all controlled ranges.
4549 */
4550     void popFront()
4551     {
4552         import std.exception : enforce;
4553 
4554         final switch (stoppingPolicy)
4555         {
4556         case StoppingPolicy.shortest:
4557             foreach (i, Unused; R)
4558             {
4559                 assert(!ranges[i].empty);
4560                 ranges[i].popFront();
4561             }
4562             break;
4563         case StoppingPolicy.longest:
4564             foreach (i, Unused; R)
4565             {
4566                 if (!ranges[i].empty) ranges[i].popFront();
4567             }
4568             break;
4569         case StoppingPolicy.requireSameLength:
4570             foreach (i, Unused; R)
4571             {
4572                 enforce(!ranges[i].empty, "Invalid Zip object");
4573                 ranges[i].popFront();
4574             }
4575             break;
4576         }
4577     }
4578 
4579 /**
4580    Calls `popBack` for all controlled ranges.
4581 */
4582     static if (allSatisfy!(isBidirectionalRange, R))
4583     {
4584         void popBack()
4585         {
4586             //TODO: Fixme! In case of jaggedness, this is wrong.
4587             import std.exception : enforce;
4588 
4589             final switch (stoppingPolicy)
4590             {
4591             case StoppingPolicy.shortest:
4592                 foreach (i, Unused; R)
4593                 {
4594                     assert(!ranges[i].empty);
4595                     ranges[i].popBack();
4596                 }
4597                 break;
4598             case StoppingPolicy.longest:
4599                 foreach (i, Unused; R)
4600                 {
4601                     if (!ranges[i].empty) ranges[i].popBack();
4602                 }
4603                 break;
4604             case StoppingPolicy.requireSameLength:
4605                 foreach (i, Unused; R)
4606                 {
4607                     enforce(!ranges[i].empty, "Invalid Zip object");
4608                     ranges[i].popBack();
4609                 }
4610                 break;
4611             }
4612         }
4613     }
4614 
4615 /**
4616    Returns the length of this range. Defined only if all ranges define
4617    `length`.
4618 */
4619     static if (allSatisfy!(hasLength, R))
4620     {
4621         @property auto length()
4622         {
4623             static if (Ranges.length == 1)
4624                 return ranges[0].length;
4625             else
4626             {
4627                 if (stoppingPolicy == StoppingPolicy.requireSameLength)
4628                     return ranges[0].length;
4629 
4630                 //[min|max](ranges[0].length, ranges[1].length, ...)
4631                 import std.algorithm.comparison : min, max;
4632                 if (stoppingPolicy == StoppingPolicy.shortest)
4633                     return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4634                 else
4635                     return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4636             }
4637         }
4638 
4639         alias opDollar = length;
4640     }
4641 
4642 /**
4643    Returns a slice of the range. Defined only if all range define
4644    slicing.
4645 */
4646     static if (allSatisfy!(hasSlicing, R))
4647     {
4648         auto opSlice(size_t from, size_t to)
4649         {
4650             //Slicing an infinite range yields the type Take!R
4651             //For finite ranges, the type Take!R aliases to R
4652             alias ZipResult = Zip!(staticMap!(Take, R));
4653 
4654             //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
4655             return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4656         }
4657     }
4658 
4659 /**
4660    Returns the `n`th element in the composite range. Defined if all
4661    ranges offer random access.
4662 */
4663     static if (allSatisfy!(isRandomAccessRange, R))
4664     {
4665         ElementType opIndex(size_t n)
4666         {
4667             //TODO: Fixme! This may create an out of bounds access
4668             //for StoppingPolicy.longest
4669 
4670             //ElementType(ranges[0][n], ranges[1][n], ...)
4671             return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
4672         }
4673 
4674 /**
4675    Assigns to the `n`th element in the composite range. Defined if
4676    all ranges offer random access.
4677 */
4678         static if (allSatisfy!(hasAssignableElements, R))
4679         {
4680             void opIndexAssign(ElementType v, size_t n)
4681             {
4682                 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
4683                 foreach (i, Range; R)
4684                 {
4685                     ranges[i][n] = v[i];
4686                 }
4687             }
4688         }
4689 
4690 /**
4691    Destructively reads the `n`th element in the composite
4692    range. Defined if all ranges offer random access.
4693 */
4694         static if (allSatisfy!(hasMobileElements, R))
4695         {
4696             ElementType moveAt(size_t n)
4697             {
4698                 //TODO: Fixme! This may create an out of bounds access
4699                 //for StoppingPolicy.longest
4700 
4701                 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
4702                 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
4703             }
4704         }
4705     }
4706 }
4707 
4708 /// Ditto
4709 auto zip(Ranges...)(Ranges ranges)
4710 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4711 {
4712     import std.meta : anySatisfy, templateOr;
4713     static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1)
4714     {
4715         return ZipShortest!(Ranges)(ranges);
4716     }
4717     else static if (allSatisfy!(isBidirectionalRange, Ranges))
4718     {
4719         static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)
4720             && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges)
4721             && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges)))
4722         {
4723             // If all the ranges are bidirectional, if possible slice them to
4724             // the same length to simplify the implementation.
4725             static assert(anySatisfy!(hasLength, Ranges));
4726             static foreach (i, Range; Ranges)
4727                 static if (hasLength!Range)
4728                 {
4729                     static if (!anySatisfy!(hasLength, Ranges[0 .. i]))
4730                         size_t minLen = ranges[i].length;
4731                     else
4732                     {{
4733                         const x = ranges[i].length;
4734                         if (x < minLen) minLen = x;
4735                     }}
4736                 }
4737             import std.format : format;
4738             static if (!anySatisfy!(isInfinite, Ranges))
4739                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
4740                     `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length)));
4741             else
4742                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
4743                     `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length)));
4744         }
4745         else static if (allSatisfy!(isRandomAccessRange, Ranges))
4746         {
4747             // We can't slice but we can still use random access to ensure
4748             // "back" is retrieving the same index for each range.
4749             return ZipShortest!(Ranges)(ranges);
4750         }
4751         else
4752         {
4753             // If bidirectional range operations would not be supported by
4754             // ZipShortest that might have actually been a bug since Zip
4755             // supported `back` without verifying that each range had the
4756             // same length, but for the sake of backwards compatibility
4757             // use the old Zip to continue supporting them.
4758             return Zip!Ranges(ranges);
4759         }
4760     }
4761     else
4762     {
4763         return ZipShortest!(Ranges)(ranges);
4764     }
4765 }
4766 
4767 ///
4768 @nogc nothrow pure @safe unittest
4769 {
4770     import std.algorithm.comparison : equal;
4771     import std.algorithm.iteration : map;
4772 
4773     // pairwise sum
4774     auto arr = only(0, 1, 2);
4775     auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
4776     assert(part1.equal(only(1, 3)));
4777 }
4778 
4779 ///
4780 nothrow pure @safe unittest
4781 {
4782     import std.conv : to;
4783 
4784     int[] a = [ 1, 2, 3 ];
4785     string[] b = [ "a", "b", "c" ];
4786     string[] result;
4787 
4788     foreach (tup; zip(a, b))
4789     {
4790         result ~= tup[0].to!string ~ tup[1];
4791     }
4792 
4793     assert(result == [ "1a", "2b", "3c" ]);
4794 
4795     size_t idx = 0;
4796     // unpacking tuple elements with foreach
4797     foreach (e1, e2; zip(a, b))
4798     {
4799         assert(e1 == a[idx]);
4800         assert(e2 == b[idx]);
4801         ++idx;
4802     }
4803 }
4804 
4805 /// `zip` is powerful - the following code sorts two arrays in parallel:
4806 nothrow pure @safe unittest
4807 {
4808     import std.algorithm.sorting : sort;
4809 
4810     int[] a = [ 1, 2, 3 ];
4811     string[] b = [ "a", "c", "b" ];
4812     zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
4813 
4814     assert(a == [ 3, 2, 1 ]);
4815     // b is sorted according to a's sorting
4816     assert(b == [ "b", "c", "a" ]);
4817 }
4818 
4819 /// Ditto
4820 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
4821 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4822 {
4823     return Zip!Ranges(ranges, sp);
4824 }
4825 
4826 /**
4827    Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop.
4828    By default stop at the end of the shortest of all ranges.
4829 */
4830 enum StoppingPolicy
4831 {
4832     /// Stop when the shortest range is exhausted
4833     shortest,
4834     /// Stop when the longest range is exhausted
4835     longest,
4836     /// Require that all ranges are equal
4837     requireSameLength,
4838 }
4839 
4840 ///
4841 pure @safe unittest
4842 {
4843     import std.algorithm.comparison : equal;
4844     import std.exception : assertThrown;
4845     import std.range.primitives;
4846     import std.typecons : tuple;
4847 
4848     auto a = [1, 2, 3];
4849     auto b = [4, 5, 6, 7];
4850 
4851     auto shortest = zip(StoppingPolicy.shortest, a, b);
4852     assert(shortest.equal([
4853         tuple(1, 4),
4854         tuple(2, 5),
4855         tuple(3, 6)
4856     ]));
4857 
4858     auto longest = zip(StoppingPolicy.longest, a, b);
4859     assert(longest.equal([
4860         tuple(1, 4),
4861         tuple(2, 5),
4862         tuple(3, 6),
4863         tuple(0, 7)
4864     ]));
4865 
4866     auto same = zip(StoppingPolicy.requireSameLength, a, b);
4867     same.popFrontN(3);
4868     assertThrown!Exception(same.popFront);
4869 }
4870 
4871 /+
4872 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest`
4873 except it properly implements `back` and `popBack` in the
4874 case of uneven ranges or disables those operations when
4875 it is not possible to guarantee they are correct.
4876 +/
4877 package template ZipShortest(Ranges...)
4878 if (Ranges.length && __traits(compiles,
4879     {
4880         static assert(allSatisfy!(isInputRange, Ranges));
4881     }))
4882 {
4883     alias ZipShortest = .ZipShortest!(
4884         Ranges.length == 1 || allSatisfy!(isInfinite, Ranges)
4885             ? Yes.allKnownSameLength
4886             : No.allKnownSameLength,
4887         Ranges);
4888 }
4889 /+ non-public, ditto +/
4890 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...)
4891 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4892 {
4893     import std.format : format; //for generic mixins
4894     import std.meta : anySatisfy, templateOr;
4895     import std.typecons : Tuple;
4896 
4897     deprecated("Use of an undocumented alias R.")
4898     alias R = Ranges; // Unused here but defined in case library users rely on it.
4899     private Ranges ranges;
4900     alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
4901 
4902     /+
4903        Builds an object. Usually this is invoked indirectly by using the
4904        $(LREF zip) function.
4905     +/
4906     this(Ranges rs)
4907     {
4908         ranges[] = rs[];
4909     }
4910 
4911     /+
4912        Returns `true` if the range is at end.
4913     +/
4914     static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges)
4915         : allSatisfy!(isInfinite, Ranges))
4916     {
4917         enum bool empty = false;
4918     }
4919     else
4920     {
4921         @property bool empty()
4922         {
4923             static if (allKnownSameLength)
4924             {
4925                 return ranges[0].empty;
4926             }
4927             else
4928             {
4929                 static foreach (i; 0 .. Ranges.length)
4930                 {
4931                     if (ranges[i].empty)
4932                         return true;
4933                 }
4934                 return false;
4935             }
4936         }
4937     }
4938 
4939     /+
4940        Forward range primitive. Only present if each constituent range is a
4941        forward range.
4942     +/
4943     static if (allSatisfy!(isForwardRange, Ranges))
4944     @property typeof(this) save()
4945     {
4946         return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length)));
4947     }
4948 
4949     /+
4950        Returns the current iterated element.
4951     +/
4952     @property ElementType front()
4953     {
4954         return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length)));
4955     }
4956 
4957     /+
4958        Sets the front of all iterated ranges. Only present if each constituent
4959        range has assignable elements.
4960     +/
4961     static if (allSatisfy!(hasAssignableElements, Ranges))
4962     @property void front()(ElementType v)
4963     {
4964         static foreach (i; 0 .. Ranges.length)
4965             ranges[i].front = v[i];
4966     }
4967 
4968     /+
4969        Moves out the front. Present if each constituent range has mobile elements.
4970     +/
4971     static if (allSatisfy!(hasMobileElements, Ranges))
4972     ElementType moveFront()()
4973     {
4974         return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length)));
4975     }
4976 
4977     private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges)
4978         && (allKnownSameLength
4979             || allSatisfy!(isRandomAccessRange, Ranges)
4980             // Could also add the case where there is one non-infinite bidirectional
4981             // range that defines `length` and all others are infinite random access
4982             // ranges. Adding this would require appropriate branches in
4983             // back/moveBack/popBack.
4984             );
4985 
4986     /+
4987        Returns the rightmost element. Present if all constituent ranges are
4988        bidirectional and either there is a compile-time guarantee that all
4989        ranges have the same length (in `allKnownSameLength`) or all ranges
4990        provide random access to elements.
4991     +/
4992     static if (isBackWellDefined)
4993     @property ElementType back()
4994     {
4995         static if (allKnownSameLength)
4996         {
4997             return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length)));
4998         }
4999         else
5000         {
5001             const backIndex = length - 1;
5002             return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length)));
5003         }
5004     }
5005 
5006     /+
5007        Moves out the back. Present if `back` is defined and
5008        each constituent range has mobile elements.
5009     +/
5010     static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges))
5011     ElementType moveBack()()
5012     {
5013         static if (allKnownSameLength)
5014         {
5015             return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length)));
5016         }
5017         else
5018         {
5019             const backIndex = length - 1;
5020             return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length)));
5021         }
5022     }
5023 
5024     /+
5025        Sets the rightmost element. Only present if `back` is defined and
5026        each constituent range has assignable elements.
5027     +/
5028     static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges))
5029     @property void back()(ElementType v)
5030     {
5031         static if (allKnownSameLength)
5032         {
5033             static foreach (i; 0 .. Ranges.length)
5034                 ranges[i].back = v[i];
5035         }
5036         else
5037         {
5038             const backIndex = length - 1;
5039             static foreach (i; 0 .. Ranges.length)
5040                 ranges[i][backIndex] = v[i];
5041         }
5042     }
5043 
5044     /+
5045        Calls `popFront` on each constituent range.
5046     +/
5047     void popFront()
5048     {
5049         static foreach (i; 0 .. Ranges.length)
5050             ranges[i].popFront();
5051     }
5052 
5053     /+
5054        Pops the rightmost element. Present if `back` is defined.
5055     +/
5056     static if (isBackWellDefined)
5057     void popBack()
5058     {
5059         static if (allKnownSameLength)
5060         {
5061             static foreach (i; 0 .. Ranges.length)
5062                 ranges[i].popBack;
5063         }
5064         else
5065         {
5066             const len = length;
5067             static foreach (i; 0 .. Ranges.length)
5068                 static if (!isInfinite!(Ranges[i]))
5069                     if (ranges[i].length == len)
5070                         ranges[i].popBack();
5071         }
5072     }
5073 
5074     /+
5075        Returns the length of this range. Defined if at least one
5076        constituent range defines `length` and the other ranges all also
5077        define `length` or are infinite, or if at least one constituent
5078        range defines `length` and there is a compile-time guarantee that
5079        all ranges have the same length (in `allKnownSameLength`).
5080     +/
5081     static if (allKnownSameLength
5082         ? anySatisfy!(hasLength, Ranges)
5083         : (anySatisfy!(hasLength, Ranges)
5084             && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
5085     {
5086         @property size_t length()
5087         {
5088             static if (allKnownSameLength)
5089             {
5090                 static foreach (i, Range; Ranges)
5091                 {
5092                     static if (hasLength!Range && !anySatisfy!(hasLength, Ranges[0 .. i]))
5093                         return ranges[i].length;
5094                 }
5095             }
5096             else
5097             {
5098                 static foreach (i, Range; Ranges)
5099                     static if (hasLength!Range)
5100                     {
5101                         static if (!anySatisfy!(hasLength, Ranges[0 .. i]))
5102                             size_t minLen = ranges[i].length;
5103                         else
5104                         {{
5105                             const x = ranges[i].length;
5106                             if (x < minLen) minLen = x;
5107                         }}
5108                     }
5109                 return minLen;
5110             }
5111         }
5112 
5113         alias opDollar = length;
5114     }
5115 
5116     /+
5117        Returns a slice of the range. Defined if all constituent ranges
5118        support slicing.
5119     +/
5120     static if (allSatisfy!(hasSlicing, Ranges))
5121     {
5122         // Note: we will know that all elements of the resultant range
5123         // will have the same length but we cannot change `allKnownSameLength`
5124         // because the `hasSlicing` predicate tests that the result returned
5125         // by `opSlice` has the same type as the receiver.
5126         auto opSlice()(size_t from, size_t to)
5127         {
5128             //(ranges[0][from .. to], ranges[1][from .. to], ...)
5129             enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length));
5130             static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs)))
5131                 return mixin(`typeof(this)`~sliceArgs);
5132             else
5133                 // The type is different anyway so we might as well
5134                 // explicitly set allKnownSameLength.
5135                 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`
5136                     ~sliceArgs);
5137         }
5138     }
5139 
5140     /+
5141        Returns the `n`th element in the composite range. Defined if all
5142        constituent ranges offer random access.
5143     +/
5144     static if (allSatisfy!(isRandomAccessRange, Ranges))
5145     ElementType opIndex()(size_t n)
5146     {
5147         return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length)));
5148     }
5149 
5150     /+
5151        Sets the `n`th element in the composite range. Defined if all
5152        constituent ranges offer random access and have assignable elements.
5153     +/
5154     static if (allSatisfy!(isRandomAccessRange, Ranges)
5155         && allSatisfy!(hasAssignableElements, Ranges))
5156     void opIndexAssign()(ElementType v, size_t n)
5157     {
5158         static foreach (i; 0 .. Ranges.length)
5159             ranges[i][n] = v[i];
5160     }
5161 
5162     /+
5163        Destructively reads the `n`th element in the composite
5164        range. Defined if all constituent ranges offer random
5165        access and have mobile elements.
5166     +/
5167     static if (allSatisfy!(isRandomAccessRange, Ranges)
5168         && allSatisfy!(hasMobileElements, Ranges))
5169     ElementType moveAt()(size_t n)
5170     {
5171         return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length)));
5172     }
5173 }
5174 
5175 pure @system unittest
5176 {
5177     import std.algorithm.comparison : equal;
5178     import std.algorithm.iteration : filter, map;
5179     import std.algorithm.mutation : swap;
5180     import std.algorithm.sorting : sort;
5181 
5182     import std.exception : assertThrown, assertNotThrown;
5183     import std.typecons : tuple;
5184 
5185     int[] a = [ 1, 2, 3 ];
5186     float[] b = [ 1.0, 2.0, 3.0 ];
5187     foreach (e; zip(a, b))
5188     {
5189         assert(e[0] == e[1]);
5190     }
5191 
5192     swap(a[0], a[1]);
5193     {
5194         auto z = zip(a, b);
5195     }
5196     //swap(z.front(), z.back());
5197     sort!("a[0] < b[0]")(zip(a, b));
5198     assert(a == [1, 2, 3]);
5199     assert(b == [2.0, 1.0, 3.0]);
5200 
5201     auto z = zip(StoppingPolicy.requireSameLength, a, b);
5202     assertNotThrown(z.popBack());
5203     assertNotThrown(z.popBack());
5204     assertNotThrown(z.popBack());
5205     assert(z.empty);
5206     assertThrown(z.popBack());
5207 
5208     a = [ 1, 2, 3 ];
5209     b = [ 1.0, 2.0, 3.0 ];
5210     sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
5211     assert(a == [3, 2, 1]);
5212     assert(b == [3.0, 2.0, 1.0]);
5213 
5214     a = [];
5215     b = [];
5216     assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
5217 
5218     // Test infiniteness propagation.
5219     static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
5220 
5221     // Test stopping policies with both value and reference.
5222     auto a1 = [1, 2];
5223     auto a2 = [1, 2, 3];
5224     auto stuff = tuple(tuple(a1, a2),
5225             tuple(filter!"a"(a1), filter!"a"(a2)));
5226 
5227     alias FOO = Zip!(immutable(int)[], immutable(float)[]);
5228 
5229     foreach (t; stuff.expand)
5230     {
5231         auto arr1 = t[0];
5232         auto arr2 = t[1];
5233         auto zShortest = zip(arr1, arr2);
5234         assert(equal(map!"a[0]"(zShortest), [1, 2]));
5235         assert(equal(map!"a[1]"(zShortest), [1, 2]));
5236 
5237         try {
5238             auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
5239             foreach (elem; zSame) {}
5240             assert(0);
5241         } catch (Throwable) { /* It's supposed to throw.*/ }
5242 
5243         auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
5244         assert(!zLongest.ranges[0].empty);
5245         assert(!zLongest.ranges[1].empty);
5246 
5247         zLongest.popFront();
5248         zLongest.popFront();
5249         assert(!zLongest.empty);
5250         assert(zLongest.ranges[0].empty);
5251         assert(!zLongest.ranges[1].empty);
5252 
5253         zLongest.popFront();
5254         assert(zLongest.empty);
5255     }
5256 
5257     // https://issues.dlang.org/show_bug.cgi?id=8900
5258     assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
5259     assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
5260 
5261     // https://issues.dlang.org/show_bug.cgi?id=18524
5262     // moveBack instead performs moveFront
5263     {
5264         auto r = zip([1,2,3]);
5265         assert(r.moveBack()[0] == 3);
5266         assert(r.moveFront()[0] == 1);
5267     }
5268 
5269     // Doesn't work yet.  Issues w/ emplace.
5270     // static assert(is(Zip!(immutable int[], immutable float[])));
5271 
5272 
5273     // These unittests pass, but make the compiler consume an absurd amount
5274     // of RAM and time.  Therefore, they should only be run if explicitly
5275     // uncommented when making changes to Zip.  Also, running them using
5276     // make -fwin32.mak unittest makes the compiler completely run out of RAM.
5277     // You need to test just this module.
5278     /+
5279      foreach (DummyType1; AllDummyRanges)
5280      {
5281          DummyType1 d1;
5282          foreach (DummyType2; AllDummyRanges)
5283          {
5284              DummyType2 d2;
5285              auto r = zip(d1, d2);
5286              assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
5287              assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
5288 
5289              static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
5290              {
5291                  static assert(isForwardRange!(typeof(r)));
5292              }
5293 
5294              static if (isBidirectionalRange!DummyType1 &&
5295                      isBidirectionalRange!DummyType2) {
5296                  static assert(isBidirectionalRange!(typeof(r)));
5297              }
5298              static if (isRandomAccessRange!DummyType1 &&
5299                      isRandomAccessRange!DummyType2) {
5300                  static assert(isRandomAccessRange!(typeof(r)));
5301              }
5302          }
5303      }
5304     +/
5305 }
5306 
5307 nothrow pure @safe unittest
5308 {
5309     import std.algorithm.sorting : sort;
5310 
5311     auto a = [5,4,3,2,1];
5312     auto b = [3,1,2,5,6];
5313     auto z = zip(a, b);
5314 
5315     sort!"a[0] < b[0]"(z);
5316 
5317     assert(a == [1, 2, 3, 4, 5]);
5318     assert(b == [6, 5, 2, 1, 3]);
5319 }
5320 
5321 nothrow pure @safe unittest
5322 {
5323     import std.algorithm.comparison : equal;
5324     import std.typecons : tuple;
5325 
5326     auto LL = iota(1L, 1000L);
5327     auto z = zip(LL, [4]);
5328 
5329     assert(equal(z, [tuple(1L,4)]));
5330 
5331     auto LL2 = iota(0L, 500L);
5332     auto z2 = zip([7], LL2);
5333     assert(equal(z2, [tuple(7, 0L)]));
5334 }
5335 
5336 // Test for https://issues.dlang.org/show_bug.cgi?id=11196
5337 @safe pure unittest
5338 {
5339     import std.exception : assertThrown;
5340 
5341     static struct S { @disable this(); }
5342     assert(zip((S[5]).init[]).length == 5);
5343     assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
5344     assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
5345 }
5346 
5347 // https://issues.dlang.org/show_bug.cgi?id=12007
5348 @nogc nothrow @safe pure unittest
5349 {
5350     static struct R
5351     {
5352         enum empty = false;
5353         void popFront(){}
5354         int front(){return 1;} @property
5355         R save(){return this;} @property
5356         void opAssign(R) @disable;
5357     }
5358     R r;
5359     auto z = zip(r, r);
5360     assert(z.save == z);
5361 }
5362 
5363 nothrow pure @system unittest
5364 {
5365     import std.typecons : tuple;
5366 
5367     auto r1 = [0,1,2];
5368     auto r2 = [1,2,3];
5369     auto z1 = zip(refRange(&r1), refRange(&r2));
5370     auto z2 = z1.save;
5371     z1.popFront();
5372     assert(z1.front == tuple(1,2));
5373     assert(z2.front == tuple(0,1));
5374 }
5375 
5376 @nogc nothrow pure @safe unittest
5377 {
5378     // Test zip's `back` and `length` with non-equal ranges.
5379     static struct NonSliceableRandomAccess
5380     {
5381         private int[] a;
5382         @property ref front()
5383         {
5384             return a.front;
5385         }
5386         @property ref back()
5387         {
5388             return a.back;
5389         }
5390         ref opIndex(size_t i)
5391         {
5392             return a[i];
5393         }
5394         void popFront()
5395         {
5396             a.popFront();
5397         }
5398         void popBack()
5399         {
5400             a.popBack();
5401         }
5402         auto moveFront()
5403         {
5404             return a.moveFront();
5405         }
5406         auto moveBack()
5407         {
5408             return a.moveBack();
5409         }
5410         auto moveAt(size_t i)
5411         {
5412             return a.moveAt(i);
5413         }
5414         bool empty() const
5415         {
5416             return a.empty;
5417         }
5418         size_t length() const
5419         {
5420             return a.length;
5421         }
5422         typeof(this) save()
5423         {
5424             return this;
5425         }
5426     }
5427     static assert(isRandomAccessRange!NonSliceableRandomAccess);
5428     static assert(!hasSlicing!NonSliceableRandomAccess);
5429     static foreach (iteration; 0 .. 2)
5430     {{
5431         int[5] data = [101, 102, 103, 201, 202];
5432         static if (iteration == 0)
5433         {
5434             auto r1 = NonSliceableRandomAccess(data[0 .. 3]);
5435             auto r2 = NonSliceableRandomAccess(data[3 .. 5]);
5436         }
5437         else
5438         {
5439             auto r1 = data[0 .. 3];
5440             auto r2 = data[3 .. 5];
5441         }
5442         auto z = zip(r1, r2);
5443         static assert(isRandomAccessRange!(typeof(z)));
5444         assert(z.length == 2);
5445         assert(z.back[0] == 102 && z.back[1] == 202);
5446         z.back = typeof(z.back)(-102, -202);// Assign to back.
5447         assert(z.back[0] == -102 && z.back[1] == -202);
5448         z.popBack();
5449         assert(z.length == 1);
5450         assert(z.back[0] == 101 && z.back[1] == 201);
5451         z.front = typeof(z.front)(-101, -201);
5452         assert(z.moveBack() == typeof(z.back)(-101, -201));
5453         z.popBack();
5454         assert(z.empty);
5455     }}
5456 }
5457 
5458 @nogc nothrow pure @safe unittest
5459 {
5460     // Test opSlice on infinite `zip`.
5461     auto z = zip(repeat(1), repeat(2));
5462     assert(hasSlicing!(typeof(z)));
5463     auto slice = z[10 .. 20];
5464     assert(slice.length == 10);
5465     static assert(!is(typeof(z) == typeof(slice)));
5466 }
5467 
5468 /*
5469     Generate lockstep's opApply function as a mixin string.
5470     If withIndex is true prepend a size_t index to the delegate.
5471 */
5472 private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
5473 {
5474     import std.format : format;
5475 
5476     string[] params;
5477     string[] emptyChecks;
5478     string[] dgArgs;
5479     string[] popFronts;
5480     string indexDef;
5481     string indexInc;
5482 
5483     if (withIndex)
5484     {
5485         params ~= "size_t";
5486         dgArgs ~= "index";
5487         if (reverse)
5488         {
5489             indexDef = q{
5490                 size_t index = ranges[0].length-1;
5491                 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
5492                         "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
5493 
5494                 foreach (range; ranges[1..$])
5495                     enforce(range.length == ranges[0].length);
5496                 };
5497             indexInc = "--index;";
5498         }
5499         else
5500         {
5501             indexDef = "size_t index = 0;";
5502             indexInc = "++index;";
5503         }
5504     }
5505 
5506     foreach (idx, Range; Ranges)
5507     {
5508         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
5509         emptyChecks ~= format("!ranges[%s].empty", idx);
5510         if (reverse)
5511         {
5512             dgArgs ~= format("ranges[%s].back", idx);
5513             popFronts ~= format("ranges[%s].popBack();", idx);
5514         }
5515         else
5516         {
5517             dgArgs ~= format("ranges[%s].front", idx);
5518             popFronts ~= format("ranges[%s].popFront();", idx);
5519         }
5520     }
5521 
5522     string name = reverse ? "opApplyReverse" : "opApply";
5523 
5524     return format(
5525     q{
5526         int %s(scope int delegate(%s) dg)
5527         {
5528             import std.exception : enforce;
5529 
5530             auto ranges = _ranges;
5531             int res;
5532             %s
5533 
5534             while (%s)
5535             {
5536                 res = dg(%s);
5537                 if (res) break;
5538                 %s
5539                 %s
5540             }
5541 
5542             if (_stoppingPolicy == StoppingPolicy.requireSameLength)
5543             {
5544                 foreach (range; ranges)
5545                     enforce(range.empty);
5546             }
5547             return res;
5548         }
5549     }, name, params.join(", "), indexDef,
5550        emptyChecks.join(" && "), dgArgs.join(", "),
5551        popFronts.join("\n                "),
5552        indexInc);
5553 }
5554 
5555 /**
5556    Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
5557    $(LREF zip) it allows reference access to its elements. If only a single
5558    range is passed in, the `Lockstep` aliases itself away.  If the
5559    ranges are of different lengths and `s` == `StoppingPolicy.shortest`
5560    stop after the shortest range is empty.  If the ranges are of different
5561    lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
5562    exception.  `s` may not be `StoppingPolicy.longest`, and passing this
5563    will throw an exception.
5564 
5565    Iterating over `Lockstep` in reverse and with an index is only possible
5566    when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
5567    indexes. If an attempt is made at iterating in reverse when `s` ==
5568    `StoppingPolicy.shortest`, an exception will be thrown.
5569 
5570    By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
5571 
5572    Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be
5573    inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to
5574    a different implementation.
5575 
5576    See_Also: $(LREF zip)
5577 
5578        `lockstep` is similar to $(LREF zip), but `zip` bundles its
5579        elements and returns a range.
5580        `lockstep` also supports reference access.
5581        Use `zip` if you want to pass the result to a range function.
5582 */
5583 struct Lockstep(Ranges...)
5584 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
5585 {
5586     ///
5587     this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
5588     {
5589         import std.exception : enforce;
5590 
5591         _ranges = ranges;
5592         enforce(sp != StoppingPolicy.longest,
5593                 "Can't use StoppingPolicy.Longest on Lockstep.");
5594         _stoppingPolicy = sp;
5595     }
5596 
5597     mixin(lockstepMixin!Ranges(false, false));
5598     mixin(lockstepMixin!Ranges(true, false));
5599     static if (allSatisfy!(isBidirectionalRange, Ranges))
5600     {
5601         mixin(lockstepMixin!Ranges(false, true));
5602         static if (allSatisfy!(hasLength, Ranges))
5603         {
5604             mixin(lockstepMixin!Ranges(true, true));
5605         }
5606         else
5607         {
5608             mixin(lockstepReverseFailMixin!Ranges(true));
5609         }
5610     }
5611     else
5612     {
5613         mixin(lockstepReverseFailMixin!Ranges(false));
5614         mixin(lockstepReverseFailMixin!Ranges(true));
5615     }
5616 
5617 private:
5618     alias R = Ranges;
5619     R _ranges;
5620     StoppingPolicy _stoppingPolicy;
5621 }
5622 
5623 /// Ditto
5624 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
5625 if (allSatisfy!(isInputRange, Ranges))
5626 {
5627     return Lockstep!(Ranges)(ranges);
5628 }
5629 /// Ditto
5630 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
5631 if (allSatisfy!(isInputRange, Ranges))
5632 {
5633     static if (Ranges.length > 1)
5634         return Lockstep!Ranges(ranges, s);
5635     else
5636         return ranges[0];
5637 }
5638 
5639 ///
5640 @system unittest
5641 {
5642    auto arr1 = [1,2,3,4,5,100];
5643    auto arr2 = [6,7,8,9,10];
5644 
5645    foreach (ref a, b; lockstep(arr1, arr2))
5646    {
5647        a += b;
5648    }
5649 
5650    assert(arr1 == [7,9,11,13,15,100]);
5651 
5652    /// Lockstep also supports iterating with an index variable:
5653    foreach (index, a, b; lockstep(arr1, arr2))
5654    {
5655        assert(arr1[index] == a);
5656        assert(arr2[index] == b);
5657    }
5658 }
5659 
5660 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
5661 @system unittest
5662 {
5663     auto arr1 = [0, 1, 2, 3];
5664     auto arr2 = [4, 5, 6, 7];
5665 
5666     size_t n = arr1.length -1;
5667     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
5668     {
5669         assert(n == index);
5670         assert(index == a);
5671         assert(arr1[index] == a);
5672         assert(arr2[index] == b);
5673         n--;
5674     }
5675 
5676     auto arr3 = [4, 5];
5677     n = 1;
5678     foreach_reverse (a, b; lockstep(arr1, arr3))
5679     {
5680         assert(a == arr1[$-n] && b == arr3[$-n]);
5681         n++;
5682     }
5683 }
5684 
5685 @system unittest
5686 {
5687     import std.algorithm.iteration : filter;
5688     import std.conv : to;
5689 
5690     // The filters are to make these the lowest common forward denominator ranges,
5691     // i.e. w/o ref return, random access, length, etc.
5692     auto foo = filter!"a"([1,2,3,4,5]);
5693     immutable bar = [6f,7f,8f,9f,10f].idup;
5694     auto l = lockstep(foo, bar);
5695 
5696     // Should work twice.  These are forward ranges with implicit save.
5697     foreach (i; 0 .. 2)
5698     {
5699         uint[] res1;
5700         float[] res2;
5701 
5702         foreach (a, ref b; l)
5703         {
5704             res1 ~= a;
5705             res2 ~= b;
5706         }
5707 
5708         assert(res1 == [1,2,3,4,5]);
5709         assert(res2 == [6,7,8,9,10]);
5710         assert(bar == [6f,7f,8f,9f,10f]);
5711     }
5712 
5713     // Doc example.
5714     auto arr1 = [1,2,3,4,5];
5715     auto arr2 = [6,7,8,9,10];
5716 
5717     foreach (ref a, ref b; lockstep(arr1, arr2))
5718     {
5719         a += b;
5720     }
5721 
5722     assert(arr1 == [7,9,11,13,15]);
5723 
5724     // Make sure StoppingPolicy.requireSameLength doesn't throw.
5725     auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
5726 
5727     int k = 1;
5728     foreach (a, b; ls)
5729     {
5730         assert(a - b == k);
5731         ++k;
5732     }
5733 
5734     // Make sure StoppingPolicy.requireSameLength throws.
5735     arr2.popBack();
5736     ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
5737 
5738     try {
5739         foreach (a, b; ls) {}
5740         assert(0);
5741     } catch (Exception) {}
5742 
5743     // Just make sure 1-range case instantiates. This hangs the compiler
5744     // when no explicit stopping policy is specified due to
5745     // https://issues.dlang.org/show_bug.cgi?id=4652
5746     auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
5747     foreach (i, a; stuff)
5748     {
5749         assert(stuff[i] == a);
5750     }
5751 
5752     // Test with indexing.
5753     uint[] res1;
5754     float[] res2;
5755     size_t[] indices;
5756     foreach (i, a, b; lockstep(foo, bar))
5757     {
5758         indices ~= i;
5759         res1 ~= a;
5760         res2 ~= b;
5761     }
5762 
5763     assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
5764     assert(res1 == [1,2,3,4,5]);
5765     assert(res2 == [6f,7f,8f,9f,10f]);
5766 
5767     // Make sure we've worked around the relevant compiler bugs and this at least
5768     // compiles w/ >2 ranges.
5769     lockstep(foo, foo, foo);
5770 
5771     // Make sure it works with const.
5772     const(int[])[] foo2 = [[1, 2, 3]];
5773     const(int[])[] bar2 = [[4, 5, 6]];
5774     auto c = chain(foo2, bar2);
5775 
5776     foreach (f, b; lockstep(c, c)) {}
5777 
5778     // Regression 10468
5779     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
5780 }
5781 
5782 @system unittest
5783 {
5784     struct RvalueRange
5785     {
5786         int[] impl;
5787         @property bool empty() { return impl.empty; }
5788         @property int front() { return impl[0]; } // N.B. non-ref
5789         void popFront() { impl.popFront(); }
5790     }
5791     auto data1 = [ 1, 2, 3, 4 ];
5792     auto data2 = [ 5, 6, 7, 8 ];
5793     auto r1 = RvalueRange(data1);
5794     auto r2 = data2;
5795     foreach (a, ref b; lockstep(r1, r2))
5796     {
5797         a++;
5798         b++;
5799     }
5800     assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
5801     assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
5802 
5803     // Since r1 is by-value only, the compiler should reject attempts to
5804     // foreach over it with ref.
5805     static assert(!__traits(compiles, {
5806         foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
5807     }));
5808 }
5809 
5810 private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
5811 {
5812     import std.format : format;
5813     string[] params;
5814     string message;
5815 
5816     if (withIndex)
5817     {
5818         message = "Indexed reverse iteration with lockstep is only supported"
5819         ~"if all ranges are bidirectional and have a length.\n";
5820     }
5821     else
5822     {
5823         message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
5824     }
5825 
5826     if (withIndex)
5827     {
5828         params ~= "size_t";
5829     }
5830 
5831     foreach (idx, Range; Ranges)
5832     {
5833         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
5834     }
5835 
5836     return format(
5837     q{
5838         int opApplyReverse()(scope int delegate(%s) dg)
5839         {
5840             static assert(false, "%s");
5841         }
5842     }, params.join(", "), message);
5843 }
5844 
5845 // For generic programming, make sure Lockstep!(Range) is well defined for a
5846 // single range.
5847 template Lockstep(Range)
5848 {
5849     alias Lockstep = Range;
5850 }
5851 
5852 /**
5853 Creates a mathematical sequence given the initial values and a
5854 recurrence function that computes the next value from the existing
5855 values. The sequence comes in the form of an infinite forward
5856 range. The type `Recurrence` itself is seldom used directly; most
5857 often, recurrences are obtained by calling the function $(D
5858 recurrence).
5859 
5860 When calling `recurrence`, the function that computes the next
5861 value is specified as a template argument, and the initial values in
5862 the recurrence are passed as regular arguments. For example, in a
5863 Fibonacci sequence, there are two initial values (and therefore a
5864 state size of 2) because computing the next Fibonacci value needs the
5865 past two values.
5866 
5867 The signature of this function should be:
5868 ----
5869 auto fun(R)(R state, size_t n)
5870 ----
5871 where `n` will be the index of the current value, and `state` will be an
5872 opaque state vector that can be indexed with array-indexing notation
5873 `state[i]`, where valid values of `i` range from $(D (n - 1)) to
5874 $(D (n - State.length)).
5875 
5876 If the function is passed in string form, the state has name `"a"`
5877 and the zero-based index in the recurrence has name `"n"`. The
5878 given string must return the desired value for `a[n]` given
5879 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
5880 state size is dictated by the number of arguments passed to the call
5881 to `recurrence`. The `Recurrence` struct itself takes care of
5882 managing the recurrence's state and shifting it appropriately.
5883  */
5884 struct Recurrence(alias fun, StateType, size_t stateSize)
5885 {
5886     import std.functional : binaryFun;
5887 
5888     StateType[stateSize] _state;
5889     size_t _n;
5890 
5891     this(StateType[stateSize] initial) { _state = initial; }
5892 
5893     void popFront()
5894     {
5895         static auto trustedCycle(ref typeof(_state) s) @trusted
5896         {
5897             return cycle(s);
5898         }
5899         // The cast here is reasonable because fun may cause integer
5900         // promotion, but needs to return a StateType to make its operation
5901         // closed.  Therefore, we have no other choice.
5902         _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
5903             trustedCycle(_state), _n + stateSize);
5904         ++_n;
5905     }
5906 
5907     @property StateType front()
5908     {
5909         return _state[_n % stateSize];
5910     }
5911 
5912     @property typeof(this) save()
5913     {
5914         return this;
5915     }
5916 
5917     enum bool empty = false;
5918 }
5919 
5920 ///
5921 pure @safe nothrow unittest
5922 {
5923     import std.algorithm.comparison : equal;
5924 
5925     // The Fibonacci numbers, using function in string form:
5926     // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
5927     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5928     assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
5929 
5930     // The factorials, using function in lambda form:
5931     auto fac = recurrence!((a,n) => a[n-1] * n)(1);
5932     assert(take(fac, 10).equal([
5933         1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
5934     ]));
5935 
5936     // The triangular numbers, using function in explicit form:
5937     static size_t genTriangular(R)(R state, size_t n)
5938     {
5939         return state[n-1] + n;
5940     }
5941     auto tri = recurrence!genTriangular(0);
5942     assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
5943 }
5944 
5945 /// Ditto
5946 Recurrence!(fun, CommonType!(State), State.length)
5947 recurrence(alias fun, State...)(State initial)
5948 {
5949     CommonType!(State)[State.length] state;
5950     foreach (i, Unused; State)
5951     {
5952         state[i] = initial[i];
5953     }
5954     return typeof(return)(state);
5955 }
5956 
5957 pure @safe nothrow unittest
5958 {
5959     import std.algorithm.comparison : equal;
5960 
5961     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5962     static assert(isForwardRange!(typeof(fib)));
5963 
5964     int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
5965     assert(equal(take(fib, 10), witness));
5966     foreach (e; take(fib, 10)) {}
5967     auto fact = recurrence!("n * a[n-1]")(1);
5968     assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
5969                             2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
5970     auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
5971     foreach (e; take(piapprox, 20)) {}
5972     // Thanks to yebblies for this test and the associated fix
5973     auto r = recurrence!"a[n-2]"(1, 2);
5974     witness = [1, 2, 1, 2, 1];
5975     assert(equal(take(r, 5), witness));
5976 }
5977 
5978 /**
5979    `Sequence` is similar to `Recurrence` except that iteration is
5980    presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
5981    closed form). This means that the `n`th element in the series is
5982    computable directly from the initial values and `n` itself. This
5983    implies that the interface offered by `Sequence` is a random-access
5984    range, as opposed to the regular `Recurrence`, which only offers
5985    forward iteration.
5986 
5987    The state of the sequence is stored as a `Tuple` so it can be
5988    heterogeneous.
5989 */
5990 struct Sequence(alias fun, State)
5991 {
5992 private:
5993     import std.functional : binaryFun;
5994 
5995     alias compute = binaryFun!(fun, "a", "n");
5996     alias ElementType = typeof(compute(State.init, cast(size_t) 1));
5997     State _state;
5998     size_t _n;
5999 
6000     static struct DollarToken{}
6001 
6002 public:
6003     this(State initial, size_t n = 0)
6004     {
6005         _state = initial;
6006         _n = n;
6007     }
6008 
6009     @property ElementType front()
6010     {
6011         return compute(_state, _n);
6012     }
6013 
6014     void popFront()
6015     {
6016         ++_n;
6017     }
6018 
6019     enum opDollar = DollarToken();
6020 
6021     auto opSlice(size_t lower, size_t upper)
6022     in
6023     {
6024         assert(
6025             upper >= lower,
6026             "Attempting to slice a Sequence with a larger first argument than the second."
6027         );
6028     }
6029     do
6030     {
6031         return typeof(this)(_state, _n + lower).take(upper - lower);
6032     }
6033 
6034     auto opSlice(size_t lower, DollarToken)
6035     {
6036         return typeof(this)(_state, _n + lower);
6037     }
6038 
6039     ElementType opIndex(size_t n)
6040     {
6041         return compute(_state, n + _n);
6042     }
6043 
6044     enum bool empty = false;
6045 
6046     @property Sequence save() { return this; }
6047 }
6048 
6049 /// Ditto
6050 auto sequence(alias fun, State...)(State args)
6051 {
6052     import std.typecons : Tuple, tuple;
6053     alias Return = Sequence!(fun, Tuple!State);
6054     return Return(tuple(args));
6055 }
6056 
6057 /// Odd numbers, using function in string form:
6058 pure @safe nothrow @nogc unittest
6059 {
6060     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6061     assert(odds.front == 1);
6062     odds.popFront();
6063     assert(odds.front == 3);
6064     odds.popFront();
6065     assert(odds.front == 5);
6066 }
6067 
6068 /// Triangular numbers, using function in lambda form:
6069 pure @safe nothrow @nogc unittest
6070 {
6071     auto tri = sequence!((a,n) => n*(n+1)/2)();
6072 
6073     // Note random access
6074     assert(tri[0] == 0);
6075     assert(tri[3] == 6);
6076     assert(tri[1] == 1);
6077     assert(tri[4] == 10);
6078     assert(tri[2] == 3);
6079 }
6080 
6081 /// Fibonacci numbers, using function in explicit form:
6082 @safe nothrow @nogc unittest
6083 {
6084     import std.math : pow, round, sqrt;
6085     static ulong computeFib(S)(S state, size_t n)
6086     {
6087         // Binet's formula
6088         return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6089                                  state[2]));
6090     }
6091     auto fib = sequence!computeFib(
6092         (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
6093         (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
6094         sqrt(5.0));
6095 
6096     // Note random access with [] operator
6097     assert(fib[1] == 1);
6098     assert(fib[4] == 5);
6099     assert(fib[3] == 3);
6100     assert(fib[2] == 2);
6101     assert(fib[9] == 55);
6102 }
6103 
6104 pure @safe nothrow @nogc unittest
6105 {
6106     import std.typecons : Tuple, tuple;
6107     auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6108     static assert(isForwardRange!(typeof(y)));
6109 
6110     //@@BUG
6111     //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6112     //foreach (e; take(y, 15))
6113     {}                                 //writeln(e);
6114 
6115     auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6116         tuple(1, 2));
6117     for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6118     {
6119         assert(odds.front == odds[0]);
6120         assert(odds[0] == currentOdd);
6121         odds.popFront();
6122     }
6123 }
6124 
6125 pure @safe nothrow @nogc unittest
6126 {
6127     import std.algorithm.comparison : equal;
6128 
6129     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6130     static assert(hasSlicing!(typeof(odds)));
6131 
6132     //Note: don't use drop or take as the target of an equal,
6133     //since they'll both just forward to opSlice, making the tests irrelevant
6134 
6135     // static slicing tests
6136     assert(equal(odds[0 .. 5], only(1,  3,  5,  7,  9)));
6137     assert(equal(odds[3 .. 7], only(7,  9, 11, 13)));
6138 
6139     // relative slicing test, testing slicing is NOT agnostic of state
6140     auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6141     assert(equal(odds_less5[0 ..  3], only(11, 13, 15)));
6142     assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6143 
6144     //Infinite slicing tests
6145     odds = odds[10 .. $];
6146     assert(equal(odds.take(3), only(21, 23, 25)));
6147 }
6148 
6149 // https://issues.dlang.org/show_bug.cgi?id=5036
6150 pure @safe nothrow unittest
6151 {
6152     auto s = sequence!((a, n) => new int)(0);
6153     assert(s.front != s.front);  // no caching
6154 }
6155 
6156 // iota
6157 /**
6158    Creates a range of values that span the given starting and stopping
6159    values.
6160 
6161    Params:
6162    begin = The starting value.
6163    end = The value that serves as the stopping criterion. This value is not
6164         included in the range.
6165    step = The value to add to the current value at each iteration.
6166 
6167    Returns:
6168    A range that goes through the numbers `begin`, $(D begin + step),
6169    $(D begin + 2 * step), `...`, up to and excluding `end`.
6170 
6171    The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6172    0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6173    is returned. If $(D step == 0) then $(D begin == end) is an error.
6174 
6175    For built-in types, the range returned is a random access range. For
6176    user-defined types that support `++`, the range is an input
6177    range.
6178 
6179    An integral iota also supports `in` operator from the right. It takes
6180    the stepping into account, the integral won't be considered
6181    contained if it falls between two consecutive values of the range.
6182    `contains` does the same as in, but from lefthand side.
6183 
6184     Example:
6185     ---
6186     void main()
6187     {
6188         import std.stdio;
6189 
6190         // The following groups all produce the same output of:
6191         // 0 1 2 3 4
6192 
6193         foreach (i; 0 .. 5)
6194             writef("%s ", i);
6195         writeln();
6196 
6197         import std.range : iota;
6198         foreach (i; iota(0, 5))
6199             writef("%s ", i);
6200         writeln();
6201 
6202         writefln("%(%s %|%)", iota(0, 5));
6203 
6204         import std.algorithm.iteration : map;
6205         import std.algorithm.mutation : copy;
6206         import std.format;
6207         iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6208         writeln();
6209     }
6210     ---
6211 */
6212 auto iota(B, E, S)(B begin, E end, S step)
6213 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6214         && isIntegral!S)
6215 {
6216     import std.conv : unsigned;
6217 
6218     alias Value = CommonType!(Unqual!B, Unqual!E);
6219     alias StepType = Unqual!S;
6220 
6221     assert(step != 0 || begin == end);
6222 
6223     static struct Result
6224     {
6225         private Value current, last;
6226         private StepType step; // by convention, 0 if range is empty
6227 
6228         this(Value current, Value pastLast, StepType step)
6229         {
6230             if (current < pastLast && step > 0)
6231             {
6232                 // Iterating upward
6233                 assert(unsigned((pastLast - current) / step) <= size_t.max);
6234                 // Cast below can't fail because current < pastLast
6235                 this.last = cast(Value) (pastLast - 1);
6236                 this.last -= unsigned(this.last - current) % step;
6237             }
6238             else if (current > pastLast && step < 0)
6239             {
6240                 // Iterating downward
6241                 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6242                 // Cast below can't fail because current > pastLast
6243                 this.last = cast(Value) (pastLast + 1);
6244                 this.last += unsigned(current - this.last) % (0 - step);
6245             }
6246             else
6247             {
6248                 // Initialize an empty range
6249                 this.step = 0;
6250                 return;
6251             }
6252             this.step = step;
6253             this.current = current;
6254         }
6255 
6256         @property bool empty() const { return step == 0; }
6257         @property inout(Value) front() inout { assert(!empty); return current; }
6258         void popFront()
6259         {
6260             assert(!empty);
6261             if (current == last) step = 0;
6262             else current += step;
6263         }
6264 
6265         @property inout(Value) back() inout
6266         {
6267             assert(!empty);
6268             return last;
6269         }
6270         void popBack()
6271         {
6272             assert(!empty);
6273             if (current == last) step = 0;
6274             else last -= step;
6275         }
6276 
6277         @property auto save() { return this; }
6278 
6279         inout(Value) opIndex(ulong n) inout
6280         {
6281             assert(n < this.length);
6282 
6283             // Just cast to Value here because doing so gives overflow behavior
6284             // consistent with calling popFront() n times.
6285             return cast(inout Value) (current + step * n);
6286         }
6287         auto opBinaryRight(string op)(Value val) const
6288         if (op == "in")
6289         {
6290             if (empty) return false;
6291             //cast to avoid becoming unsigned
6292             auto supposedIndex = cast(StepType)(val - current) / step;
6293             return supposedIndex < length && supposedIndex * step + current == val;
6294         }
6295         auto contains(Value x){return x in this;}
6296         inout(Result) opSlice() inout { return this; }
6297         inout(Result) opSlice(ulong lower, ulong upper) inout
6298         {
6299             assert(upper >= lower && upper <= this.length);
6300 
6301             return cast(inout Result) Result(
6302                 cast(Value)(current + lower * step),
6303                 cast(Value)(current + upper * step),
6304                 step);
6305         }
6306         @property size_t length() const
6307         {
6308             if (step > 0)
6309                 return 1 + cast(size_t) (unsigned(last - current) / step);
6310             if (step < 0)
6311                 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6312             return 0;
6313         }
6314 
6315         alias opDollar = length;
6316     }
6317 
6318     return Result(begin, end, step);
6319 }
6320 
6321 /// Ditto
6322 auto iota(B, E)(B begin, E end)
6323 if (isFloatingPoint!(CommonType!(B, E)))
6324 {
6325     return iota(begin, end, CommonType!(B, E)(1));
6326 }
6327 
6328 /// Ditto
6329 auto iota(B, E)(B begin, E end)
6330 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6331 {
6332     import std.conv : unsigned;
6333 
6334     alias Value = CommonType!(Unqual!B, Unqual!E);
6335 
6336     static struct Result
6337     {
6338         private Value current, pastLast;
6339 
6340         this(Value current, Value pastLast)
6341         {
6342             if (current < pastLast)
6343             {
6344                 assert(unsigned(pastLast - current) <= size_t.max);
6345 
6346                 this.current = current;
6347                 this.pastLast = pastLast;
6348             }
6349             else
6350             {
6351                 // Initialize an empty range
6352                 this.current = this.pastLast = current;
6353             }
6354         }
6355 
6356         @property bool empty() const { return current == pastLast; }
6357         @property inout(Value) front() inout { assert(!empty); return current; }
6358         void popFront() { assert(!empty); ++current; }
6359 
6360         @property inout(Value) back() inout { assert(!empty); return cast(inout(Value))(pastLast - 1); }
6361         void popBack() { assert(!empty); --pastLast; }
6362 
6363         @property auto save() { return this; }
6364 
6365         inout(Value) opIndex(size_t n) inout
6366         {
6367             assert(n < this.length);
6368 
6369             // Just cast to Value here because doing so gives overflow behavior
6370             // consistent with calling popFront() n times.
6371             return cast(inout Value) (current + n);
6372         }
6373         auto opBinaryRight(string op)(Value val) const
6374         if (op == "in")
6375         {
6376             return current <= val && val < pastLast;
6377         }
6378         auto contains(Value x){return x in this;}
6379         inout(Result) opSlice() inout { return this; }
6380         inout(Result) opSlice(ulong lower, ulong upper) inout
6381         {
6382             assert(upper >= lower && upper <= this.length);
6383 
6384             return cast(inout Result) Result(cast(Value)(current + lower),
6385                                             cast(Value)(pastLast - (length - upper)));
6386         }
6387         @property size_t length() const
6388         {
6389             return cast(size_t)(pastLast - current);
6390         }
6391 
6392         alias opDollar = length;
6393     }
6394 
6395     return Result(begin, end);
6396 }
6397 
6398 /// Ditto
6399 auto iota(E)(E end)
6400 if (is(typeof(iota(E(0), end))))
6401 {
6402     E begin = E(0);
6403     return iota(begin, end);
6404 }
6405 
6406 /// Ditto
6407 // Specialization for floating-point types
6408 auto iota(B, E, S)(B begin, E end, S step)
6409 if (isFloatingPoint!(CommonType!(B, E, S)))
6410 in
6411 {
6412     assert(step != 0, "iota: step must not be 0");
6413     assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
6414 }
6415 do
6416 {
6417     alias Value = Unqual!(CommonType!(B, E, S));
6418     static struct Result
6419     {
6420         private Value start, step;
6421         private size_t index, count;
6422 
6423         this(Value start, Value end, Value step)
6424         {
6425             import std.conv : to;
6426 
6427             this.start = start;
6428             this.step = step;
6429             immutable fcount = (end - start) / step;
6430             count = to!size_t(fcount);
6431             auto pastEnd = start + count * step;
6432             if (step > 0)
6433             {
6434                 if (pastEnd < end) ++count;
6435                 assert(start + count * step >= end);
6436             }
6437             else
6438             {
6439                 if (pastEnd > end) ++count;
6440                 assert(start + count * step <= end);
6441             }
6442         }
6443 
6444         @property bool empty() const { return index == count; }
6445         @property Value front() const { assert(!empty); return start + step * index; }
6446         void popFront()
6447         {
6448             assert(!empty);
6449             ++index;
6450         }
6451         @property Value back() const
6452         {
6453             assert(!empty);
6454             return start + step * (count - 1);
6455         }
6456         void popBack()
6457         {
6458             assert(!empty);
6459             --count;
6460         }
6461 
6462         @property auto save() { return this; }
6463 
6464         Value opIndex(size_t n) const
6465         {
6466             assert(n < count);
6467             return start + step * (n + index);
6468         }
6469         inout(Result) opSlice() inout
6470         {
6471             return this;
6472         }
6473         inout(Result) opSlice(size_t lower, size_t upper) inout
6474         {
6475             assert(upper >= lower && upper <= count);
6476 
6477             Result ret = this;
6478             ret.index += lower;
6479             ret.count = upper - lower + ret.index;
6480             return cast(inout Result) ret;
6481         }
6482         @property size_t length() const
6483         {
6484             return count - index;
6485         }
6486 
6487         alias opDollar = length;
6488     }
6489 
6490     return Result(begin, end, step);
6491 }
6492 
6493 ///
6494 pure @safe unittest
6495 {
6496     import std.algorithm.comparison : equal;
6497     import std.math : approxEqual;
6498 
6499     auto r = iota(0, 10, 1);
6500     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6501     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6502     assert(3 in r);
6503     assert(r.contains(3)); //Same as above
6504     assert(!(10 in r));
6505     assert(!(-8 in r));
6506     r = iota(0, 11, 3);
6507     assert(equal(r, [0, 3, 6, 9]));
6508     assert(r[2] == 6);
6509     assert(!(2 in r));
6510     auto rf = iota(0.0, 0.5, 0.1);
6511     assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
6512 }
6513 
6514 pure nothrow @nogc @safe unittest
6515 {
6516     import std.traits : Signed;
6517    //float overloads use std.conv.to so can't be @nogc or nothrow
6518     alias ssize_t = Signed!size_t;
6519     assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
6520     assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
6521     assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
6522     assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
6523     assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
6524 }
6525 
6526 debug @system unittest
6527 {//check the contracts
6528     import core.exception : AssertError;
6529     import std.exception : assertThrown;
6530     assertThrown!AssertError(iota(1,2,0));
6531     assertThrown!AssertError(iota(0f,1f,0f));
6532     assertThrown!AssertError(iota(1f,0f,0.1f));
6533     assertThrown!AssertError(iota(0f,1f,-0.1f));
6534 }
6535 
6536 pure @system nothrow unittest
6537 {
6538     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6539     auto r1 = iota(a.ptr, a.ptr + a.length, 1);
6540     assert(r1.front == a.ptr);
6541     assert(r1.back == a.ptr + a.length - 1);
6542     assert(&a[4] in r1);
6543 }
6544 
6545 pure @safe nothrow @nogc unittest
6546 {
6547     assert(iota(1UL, 0UL).length == 0);
6548     assert(iota(1UL, 0UL, 1).length == 0);
6549     assert(iota(0, 1, 1).length == 1);
6550     assert(iota(1, 0, -1).length == 1);
6551     assert(iota(0, 1, -1).length == 0);
6552     assert(iota(ulong.max, 0).length == 0);
6553 }
6554 
6555 pure @safe unittest
6556 {
6557     import std.algorithm.comparison : equal;
6558     import std.algorithm.searching : count;
6559     import std.math : approxEqual, nextUp, nextDown;
6560     import std.meta : AliasSeq;
6561 
6562     static assert(is(ElementType!(typeof(iota(0f))) == float));
6563 
6564     static assert(hasLength!(typeof(iota(0, 2))));
6565     auto r = iota(0, 10, 1);
6566     assert(r[$ - 1] == 9);
6567     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
6568 
6569     auto rSlice = r[2 .. 8];
6570     assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
6571 
6572     rSlice.popFront();
6573     assert(rSlice[0] == rSlice.front);
6574     assert(rSlice.front == 3);
6575 
6576     rSlice.popBack();
6577     assert(rSlice[rSlice.length - 1] == rSlice.back);
6578     assert(rSlice.back == 6);
6579 
6580     rSlice = r[0 .. 4];
6581     assert(equal(rSlice, [0, 1, 2, 3]));
6582     assert(3 in rSlice);
6583     assert(!(4 in rSlice));
6584 
6585     auto rr = iota(10);
6586     assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
6587 
6588     r = iota(0, -10, -1);
6589     assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
6590     rSlice = r[3 .. 9];
6591     assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
6592 
6593     r = iota(0, -6, -3);
6594     assert(equal(r, [0, -3][]));
6595     rSlice = r[1 .. 2];
6596     assert(equal(rSlice, [-3]));
6597 
6598     r = iota(0, -7, -3);
6599     assert(equal(r, [0, -3, -6][]));
6600     assert(0 in r);
6601     assert(-6 in r);
6602     rSlice = r[1 .. 3];
6603     assert(equal(rSlice, [-3, -6]));
6604     assert(!(0 in rSlice));
6605     assert(!(-2 in rSlice));
6606     assert(!(-5 in rSlice));
6607     assert(!(3 in rSlice));
6608     assert(!(-9 in rSlice));
6609 
6610     r = iota(0, 11, 3);
6611     assert(equal(r, [0, 3, 6, 9][]));
6612     assert(r[2] == 6);
6613     rSlice = r[1 .. 3];
6614     assert(equal(rSlice, [3, 6]));
6615 
6616     auto rf = iota(0.0, 0.5, 0.1);
6617     assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
6618     assert(rf.length == 5);
6619 
6620     rf.popFront();
6621     assert(rf.length == 4);
6622 
6623     auto rfSlice = rf[1 .. 4];
6624     assert(rfSlice.length == 3);
6625     assert(approxEqual(rfSlice, [0.2, 0.3, 0.4]));
6626 
6627     rfSlice.popFront();
6628     assert(approxEqual(rfSlice[0], 0.3));
6629 
6630     rf.popFront();
6631     assert(rf.length == 3);
6632 
6633     rfSlice = rf[1 .. 3];
6634     assert(rfSlice.length == 2);
6635     assert(approxEqual(rfSlice, [0.3, 0.4]));
6636     assert(approxEqual(rfSlice[0], 0.3));
6637 
6638     // With something just above 0.5
6639     rf = iota(0.0, nextUp(0.5), 0.1);
6640     assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
6641     rf.popBack();
6642     assert(rf[rf.length - 1] == rf.back);
6643     assert(approxEqual(rf.back, 0.4));
6644     assert(rf.length == 5);
6645 
6646     // going down
6647     rf = iota(0.0, -0.5, -0.1);
6648     assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
6649     rfSlice = rf[2 .. 5];
6650     assert(approxEqual(rfSlice, [-0.2, -0.3, -0.4]));
6651 
6652     rf = iota(0.0, nextDown(-0.5), -0.1);
6653     assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
6654 
6655     // iota of longs
6656     auto rl = iota(5_000_000L);
6657     assert(rl.length == 5_000_000L);
6658     assert(0 in rl);
6659     assert(4_000_000L in rl);
6660     assert(!(-4_000_000L in rl));
6661     assert(!(5_000_000L in rl));
6662 
6663     // iota of longs with steps
6664     auto iota_of_longs_with_steps = iota(50L, 101L, 10);
6665     assert(iota_of_longs_with_steps.length == 6);
6666     assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
6667 
6668     // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
6669     // Actually trying to consume it is the only way to find something is wrong
6670     // because the public properties are all correct.
6671     auto iota_zero_unsigned = iota(0, 0u, 3);
6672     assert(count(iota_zero_unsigned) == 0);
6673 
6674     // https://issues.dlang.org/show_bug.cgi?id=7982
6675     // unsigned reverse iota can be buggy if `.length` doesn't
6676     // take them into account
6677     assert(iota(10u, 0u, -1).length == 10);
6678     assert(iota(10u, 0u, -2).length == 5);
6679     assert(iota(uint.max, uint.max-10, -1).length == 10);
6680     assert(iota(uint.max, uint.max-10, -2).length == 5);
6681     assert(iota(uint.max, 0u, -1).length == uint.max);
6682 
6683     assert(20 in iota(20u, 10u, -2));
6684     assert(16 in iota(20u, 10u, -2));
6685     assert(!(15 in iota(20u, 10u, -2)));
6686     assert(!(10 in iota(20u, 10u, -2)));
6687     assert(!(uint.max in iota(20u, 10u, -1)));
6688     assert(!(int.min in iota(20u, 10u, -1)));
6689     assert(!(int.max in iota(20u, 10u, -1)));
6690 
6691 
6692     // https://issues.dlang.org/show_bug.cgi?id=8920
6693     static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
6694         int, uint, long, ulong))
6695     {{
6696         Type val;
6697         foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
6698         assert(val == 10);
6699     }}
6700 }
6701 
6702 pure @safe nothrow unittest
6703 {
6704     import std.algorithm.mutation : copy;
6705     auto idx = new size_t[100];
6706     copy(iota(0, idx.length), idx);
6707 }
6708 
6709 @safe unittest
6710 {
6711     import std.meta : AliasSeq;
6712     static foreach (range; AliasSeq!(iota(2, 27, 4),
6713                              iota(3, 9),
6714                              iota(2.7, 12.3, .1),
6715                              iota(3.2, 9.7)))
6716     {{
6717         const cRange = range;
6718         const e = cRange.empty;
6719         const f = cRange.front;
6720         const b = cRange.back;
6721         const i = cRange[2];
6722         const s1 = cRange[];
6723         const s2 = cRange[0 .. 3];
6724         const l = cRange.length;
6725     }}
6726 }
6727 
6728 @system unittest
6729 {
6730     //The ptr stuff can't be done at compile time, so we unfortunately end
6731     //up with some code duplication here.
6732     auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
6733 
6734     {
6735         const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
6736         const e = cRange.empty;
6737         const f = cRange.front;
6738         const b = cRange.back;
6739         const i = cRange[2];
6740         const s1 = cRange[];
6741         const s2 = cRange[0 .. 3];
6742         const l = cRange.length;
6743     }
6744 
6745     {
6746         const cRange = iota(arr.ptr, arr.ptr + arr.length);
6747         const e = cRange.empty;
6748         const f = cRange.front;
6749         const b = cRange.back;
6750         const i = cRange[2];
6751         const s1 = cRange[];
6752         const s2 = cRange[0 .. 3];
6753         const l = cRange.length;
6754     }
6755 }
6756 
6757 @nogc nothrow pure @safe unittest
6758 {
6759     {
6760         ushort start = 0, end = 10, step = 2;
6761         foreach (i; iota(start, end, step))
6762             static assert(is(typeof(i) == ushort));
6763     }
6764     {
6765         ubyte start = 0, end = 255, step = 128;
6766         uint x;
6767         foreach (i; iota(start, end, step))
6768         {
6769             static assert(is(typeof(i) == ubyte));
6770             ++x;
6771         }
6772         assert(x == 2);
6773     }
6774 }
6775 
6776 /* Generic overload that handles arbitrary types that support arithmetic
6777  * operations.
6778  *
6779  * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
6780  * as they can be incremented with `++` and compared with `<` or `==`.
6781  */
6782 /// ditto
6783 auto iota(B, E)(B begin, E end)
6784 if (!isIntegral!(CommonType!(B, E)) &&
6785     !isFloatingPoint!(CommonType!(B, E)) &&
6786     !isPointer!(CommonType!(B, E)) &&
6787     is(typeof((ref B b) { ++b; })) &&
6788     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
6789 {
6790     static struct Result
6791     {
6792         B current;
6793         E end;
6794 
6795         @property bool empty()
6796         {
6797             static if (is(typeof(B.init < E.init)))
6798                 return !(current < end);
6799             else static if (is(typeof(B.init != E.init)))
6800                 return current == end;
6801             else
6802                 static assert(0);
6803         }
6804         @property auto front() { return current; }
6805         void popFront()
6806         {
6807             assert(!empty);
6808             ++current;
6809         }
6810     }
6811     return Result(begin, end);
6812 }
6813 
6814 @safe unittest
6815 {
6816     import std.algorithm.comparison : equal;
6817 
6818     // Test iota() for a type that only supports ++ and != but does not have
6819     // '<'-ordering.
6820     struct Cyclic(int wrapAround)
6821     {
6822         int current;
6823 
6824         this(int start) { current = start % wrapAround; }
6825 
6826         bool opEquals(Cyclic c) const { return current == c.current; }
6827         bool opEquals(int i) const { return current == i; }
6828         void opUnary(string op)() if (op == "++")
6829         {
6830             current = (current + 1) % wrapAround;
6831         }
6832     }
6833     alias Cycle5 = Cyclic!5;
6834 
6835     // Easy case
6836     auto i1 = iota(Cycle5(1), Cycle5(4));
6837     assert(i1.equal([1, 2, 3]));
6838 
6839     // Wraparound case
6840     auto i2 = iota(Cycle5(3), Cycle5(2));
6841     assert(i2.equal([3, 4, 0, 1 ]));
6842 }
6843 
6844 /**
6845    Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
6846    (below).
6847 */
6848 enum TransverseOptions
6849 {
6850 /**
6851    When transversed, the elements of a range of ranges are assumed to
6852    have different lengths (e.g. a jagged array).
6853 */
6854     assumeJagged,                      //default
6855     /**
6856        The transversal enforces that the elements of a range of ranges have
6857        all the same length (e.g. an array of arrays, all having the same
6858        length). Checking is done once upon construction of the transversal
6859        range.
6860     */
6861         enforceNotJagged,
6862     /**
6863        The transversal assumes, without verifying, that the elements of a
6864        range of ranges have all the same length. This option is useful if
6865        checking was already done from the outside of the range.
6866     */
6867         assumeNotJagged,
6868 }
6869 
6870 ///
6871 @safe pure unittest
6872 {
6873     import std.algorithm.comparison : equal;
6874     import std.exception : assertThrown;
6875 
6876     auto arr = [[1, 2], [3, 4, 5]];
6877 
6878     auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
6879     assert(r1.equal([1, 3]));
6880 
6881     // throws on construction
6882     assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
6883 
6884     auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
6885     assert(r2.equal([1, 3]));
6886 
6887     // either assuming or checking for equal lengths makes
6888     // the result a random access range
6889     assert(r2[0] == 1);
6890     static assert(!__traits(compiles, r1[0]));
6891 }
6892 
6893 /**
6894    Given a range of ranges, iterate transversally through the first
6895    elements of each of the enclosed ranges.
6896 */
6897 struct FrontTransversal(Ror,
6898         TransverseOptions opt = TransverseOptions.assumeJagged)
6899 {
6900     alias RangeOfRanges = Unqual!(Ror);
6901     alias RangeType     = .ElementType!RangeOfRanges;
6902     alias ElementType   = .ElementType!RangeType;
6903 
6904     private void prime()
6905     {
6906         static if (opt == TransverseOptions.assumeJagged)
6907         {
6908             while (!_input.empty && _input.front.empty)
6909             {
6910                 _input.popFront();
6911             }
6912             static if (isBidirectionalRange!RangeOfRanges)
6913             {
6914                 while (!_input.empty && _input.back.empty)
6915                 {
6916                     _input.popBack();
6917                 }
6918             }
6919         }
6920     }
6921 
6922 /**
6923    Construction from an input.
6924 */
6925     this(RangeOfRanges input)
6926     {
6927         _input = input;
6928         prime();
6929         static if (opt == TransverseOptions.enforceNotJagged)
6930             // (isRandomAccessRange!RangeOfRanges
6931             //     && hasLength!RangeType)
6932         {
6933             import std.exception : enforce;
6934 
6935             if (empty) return;
6936             immutable commonLength = _input.front.length;
6937             foreach (e; _input)
6938             {
6939                 enforce(e.length == commonLength);
6940             }
6941         }
6942     }
6943 
6944 /**
6945    Forward range primitives.
6946 */
6947     static if (isInfinite!RangeOfRanges)
6948     {
6949         enum bool empty = false;
6950     }
6951     else
6952     {
6953         @property bool empty()
6954         {
6955             static if (opt != TransverseOptions.assumeJagged)
6956             {
6957                 if (!_input.empty)
6958                     return _input.front.empty;
6959             }
6960 
6961             return _input.empty;
6962         }
6963     }
6964 
6965     /// Ditto
6966     @property auto ref front()
6967     {
6968         assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
6969         return _input.front.front;
6970     }
6971 
6972     /// Ditto
6973     static if (hasMobileElements!RangeType)
6974     {
6975         ElementType moveFront()
6976         {
6977             return _input.front.moveFront();
6978         }
6979     }
6980 
6981     static if (hasAssignableElements!RangeType)
6982     {
6983         @property void front(ElementType val)
6984         {
6985             _input.front.front = val;
6986         }
6987     }
6988 
6989     /// Ditto
6990     void popFront()
6991     {
6992         assert(!empty, "Attempting to popFront an empty FrontTransversal");
6993         _input.popFront();
6994         prime();
6995     }
6996 
6997 /**
6998    Duplicates this `frontTransversal`. Note that only the encapsulating
6999    range of range will be duplicated. Underlying ranges will not be
7000    duplicated.
7001 */
7002     static if (isForwardRange!RangeOfRanges)
7003     {
7004         @property FrontTransversal save()
7005         {
7006             return FrontTransversal(_input.save);
7007         }
7008     }
7009 
7010     static if (isBidirectionalRange!RangeOfRanges)
7011     {
7012 /**
7013    Bidirectional primitives. They are offered if $(D
7014    isBidirectionalRange!RangeOfRanges).
7015 */
7016         @property auto ref back()
7017         {
7018             assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7019             return _input.back.front;
7020         }
7021         /// Ditto
7022         void popBack()
7023         {
7024             assert(!empty, "Attempting to popBack an empty FrontTransversal");
7025             _input.popBack();
7026             prime();
7027         }
7028 
7029         /// Ditto
7030         static if (hasMobileElements!RangeType)
7031         {
7032             ElementType moveBack()
7033             {
7034                 return _input.back.moveFront();
7035             }
7036         }
7037 
7038         static if (hasAssignableElements!RangeType)
7039         {
7040             @property void back(ElementType val)
7041             {
7042                 _input.back.front = val;
7043             }
7044         }
7045     }
7046 
7047     static if (isRandomAccessRange!RangeOfRanges &&
7048             (opt == TransverseOptions.assumeNotJagged ||
7049                     opt == TransverseOptions.enforceNotJagged))
7050     {
7051 /**
7052    Random-access primitive. It is offered if $(D
7053    isRandomAccessRange!RangeOfRanges && (opt ==
7054    TransverseOptions.assumeNotJagged || opt ==
7055    TransverseOptions.enforceNotJagged)).
7056 */
7057         auto ref opIndex(size_t n)
7058         {
7059             return _input[n].front;
7060         }
7061 
7062         /// Ditto
7063         static if (hasMobileElements!RangeType)
7064         {
7065             ElementType moveAt(size_t n)
7066             {
7067                 return _input[n].moveFront();
7068             }
7069         }
7070         /// Ditto
7071         static if (hasAssignableElements!RangeType)
7072         {
7073             void opIndexAssign(ElementType val, size_t n)
7074             {
7075                 _input[n].front = val;
7076             }
7077         }
7078         /// Ditto
7079         static if (hasLength!RangeOfRanges)
7080         {
7081             @property size_t length()
7082             {
7083                 return _input.length;
7084             }
7085 
7086             alias opDollar = length;
7087         }
7088 
7089 /**
7090    Slicing if offered if `RangeOfRanges` supports slicing and all the
7091    conditions for supporting indexing are met.
7092 */
7093         static if (hasSlicing!RangeOfRanges)
7094         {
7095             typeof(this) opSlice(size_t lower, size_t upper)
7096             {
7097                 return typeof(this)(_input[lower .. upper]);
7098             }
7099         }
7100     }
7101 
7102     auto opSlice() { return this; }
7103 
7104 private:
7105     RangeOfRanges _input;
7106 }
7107 
7108 /// Ditto
7109 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7110     TransverseOptions opt = TransverseOptions.assumeJagged,
7111     RangeOfRanges)
7112 (RangeOfRanges rr)
7113 {
7114     return typeof(return)(rr);
7115 }
7116 
7117 ///
7118 pure @safe nothrow unittest
7119 {
7120     import std.algorithm.comparison : equal;
7121     int[][] x = new int[][2];
7122     x[0] = [1, 2];
7123     x[1] = [3, 4];
7124     auto ror = frontTransversal(x);
7125     assert(equal(ror, [ 1, 3 ][]));
7126 }
7127 
7128 @safe unittest
7129 {
7130     import std.algorithm.comparison : equal;
7131     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7132 
7133     static assert(is(FrontTransversal!(immutable int[][])));
7134 
7135     foreach (DummyType; AllDummyRanges)
7136     {
7137         auto dummies =
7138             [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7139 
7140         foreach (i, ref elem; dummies)
7141         {
7142             // Just violate the DummyRange abstraction to get what I want.
7143             elem.arr = elem.arr[i..$ - (3 - i)];
7144         }
7145 
7146         auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7147         static if (isForwardRange!DummyType)
7148         {
7149             static assert(isForwardRange!(typeof(ft)));
7150         }
7151 
7152         assert(equal(ft, [1, 2, 3, 4]));
7153 
7154         // Test slicing.
7155         assert(equal(ft[0 .. 2], [1, 2]));
7156         assert(equal(ft[1 .. 3], [2, 3]));
7157 
7158         assert(ft.front == ft.moveFront());
7159         assert(ft.back == ft.moveBack());
7160         assert(ft.moveAt(1) == ft[1]);
7161 
7162 
7163         // Test infiniteness propagation.
7164         static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7165 
7166         static if (DummyType.r == ReturnBy.Reference)
7167         {
7168             {
7169                 ft.front++;
7170                 scope(exit) ft.front--;
7171                 assert(dummies.front.front == 2);
7172             }
7173 
7174             {
7175                 ft.front = 5;
7176                 scope(exit) ft.front = 1;
7177                 assert(dummies[0].front == 5);
7178             }
7179 
7180             {
7181                 ft.back = 88;
7182                 scope(exit) ft.back = 4;
7183                 assert(dummies.back.front == 88);
7184             }
7185 
7186             {
7187                 ft[1] = 99;
7188                 scope(exit) ft[1] = 2;
7189                 assert(dummies[1].front == 99);
7190             }
7191         }
7192     }
7193 }
7194 
7195 // https://issues.dlang.org/show_bug.cgi?id=16363
7196 pure @safe nothrow unittest
7197 {
7198     import std.algorithm.comparison : equal;
7199 
7200     int[][] darr = [[0, 1], [4, 5]];
7201     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7202 
7203     assert(equal(ft, [0, 4]));
7204     static assert(isRandomAccessRange!(typeof(ft)));
7205 }
7206 
7207 // https://issues.dlang.org/show_bug.cgi?id=16442
7208 pure @safe nothrow unittest
7209 {
7210     int[][] arr = [[], []];
7211 
7212     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7213     assert(ft.empty);
7214 }
7215 
7216 // ditto
7217 pure @safe unittest
7218 {
7219     int[][] arr = [[], []];
7220 
7221     auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7222     assert(ft.empty);
7223 }
7224 
7225 /**
7226     Given a range of ranges, iterate transversally through the
7227     `n`th element of each of the enclosed ranges. This function
7228     is similar to `unzip` in other languages.
7229 
7230     Params:
7231         opt = Controls the assumptions the function makes about the lengths
7232         of the ranges
7233         rr = An input range of random access ranges
7234     Returns:
7235         At minimum, an input range. Range primitives such as bidirectionality
7236         and random access are given if the element type of `rr` provides them.
7237 */
7238 struct Transversal(Ror,
7239         TransverseOptions opt = TransverseOptions.assumeJagged)
7240 {
7241     private alias RangeOfRanges = Unqual!Ror;
7242     private alias InnerRange = ElementType!RangeOfRanges;
7243     private alias E = ElementType!InnerRange;
7244 
7245     private void prime()
7246     {
7247         static if (opt == TransverseOptions.assumeJagged)
7248         {
7249             while (!_input.empty && _input.front.length <= _n)
7250             {
7251                 _input.popFront();
7252             }
7253             static if (isBidirectionalRange!RangeOfRanges)
7254             {
7255                 while (!_input.empty && _input.back.length <= _n)
7256                 {
7257                     _input.popBack();
7258                 }
7259             }
7260         }
7261     }
7262 
7263 /**
7264    Construction from an input and an index.
7265 */
7266     this(RangeOfRanges input, size_t n)
7267     {
7268         _input = input;
7269         _n = n;
7270         prime();
7271         static if (opt == TransverseOptions.enforceNotJagged)
7272         {
7273             import std.exception : enforce;
7274 
7275             if (empty) return;
7276             immutable commonLength = _input.front.length;
7277             foreach (e; _input)
7278             {
7279                 enforce(e.length == commonLength);
7280             }
7281         }
7282     }
7283 
7284 /**
7285    Forward range primitives.
7286 */
7287     static if (isInfinite!(RangeOfRanges))
7288     {
7289         enum bool empty = false;
7290     }
7291     else
7292     {
7293         @property bool empty()
7294         {
7295             return _input.empty;
7296         }
7297     }
7298 
7299     /// Ditto
7300     @property auto ref front()
7301     {
7302         assert(!empty, "Attempting to fetch the front of an empty Transversal");
7303         return _input.front[_n];
7304     }
7305 
7306     /// Ditto
7307     static if (hasMobileElements!InnerRange)
7308     {
7309         E moveFront()
7310         {
7311             return _input.front.moveAt(_n);
7312         }
7313     }
7314 
7315     /// Ditto
7316     static if (hasAssignableElements!InnerRange)
7317     {
7318         @property void front(E val)
7319         {
7320             _input.front[_n] = val;
7321         }
7322     }
7323 
7324 
7325     /// Ditto
7326     void popFront()
7327     {
7328         assert(!empty, "Attempting to popFront an empty Transversal");
7329         _input.popFront();
7330         prime();
7331     }
7332 
7333     /// Ditto
7334     static if (isForwardRange!RangeOfRanges)
7335     {
7336         @property typeof(this) save()
7337         {
7338             auto ret = this;
7339             ret._input = _input.save;
7340             return ret;
7341         }
7342     }
7343 
7344     static if (isBidirectionalRange!RangeOfRanges)
7345     {
7346 /**
7347    Bidirectional primitives. They are offered if $(D
7348    isBidirectionalRange!RangeOfRanges).
7349 */
7350         @property auto ref back()
7351         {
7352             assert(!empty, "Attempting to fetch the back of an empty Transversal");
7353             return _input.back[_n];
7354         }
7355 
7356         /// Ditto
7357         void popBack()
7358         {
7359             assert(!empty, "Attempting to popBack an empty Transversal");
7360             _input.popBack();
7361             prime();
7362         }
7363 
7364         /// Ditto
7365         static if (hasMobileElements!InnerRange)
7366         {
7367             E moveBack()
7368             {
7369                 return _input.back.moveAt(_n);
7370             }
7371         }
7372 
7373         /// Ditto
7374         static if (hasAssignableElements!InnerRange)
7375         {
7376             @property void back(E val)
7377             {
7378                 _input.back[_n] = val;
7379             }
7380         }
7381 
7382     }
7383 
7384     static if (isRandomAccessRange!RangeOfRanges &&
7385             (opt == TransverseOptions.assumeNotJagged ||
7386                     opt == TransverseOptions.enforceNotJagged))
7387     {
7388 /**
7389    Random-access primitive. It is offered if $(D
7390    isRandomAccessRange!RangeOfRanges && (opt ==
7391    TransverseOptions.assumeNotJagged || opt ==
7392    TransverseOptions.enforceNotJagged)).
7393 */
7394         auto ref opIndex(size_t n)
7395         {
7396             return _input[n][_n];
7397         }
7398 
7399         /// Ditto
7400         static if (hasMobileElements!InnerRange)
7401         {
7402             E moveAt(size_t n)
7403             {
7404                 return _input[n].moveAt(_n);
7405             }
7406         }
7407 
7408         /// Ditto
7409         static if (hasAssignableElements!InnerRange)
7410         {
7411             void opIndexAssign(E val, size_t n)
7412             {
7413                 _input[n][_n] = val;
7414             }
7415         }
7416 
7417         /// Ditto
7418         static if (hasLength!RangeOfRanges)
7419         {
7420             @property size_t length()
7421             {
7422                 return _input.length;
7423             }
7424 
7425             alias opDollar = length;
7426         }
7427 
7428 /**
7429    Slicing if offered if `RangeOfRanges` supports slicing and all the
7430    conditions for supporting indexing are met.
7431 */
7432         static if (hasSlicing!RangeOfRanges)
7433         {
7434             typeof(this) opSlice(size_t lower, size_t upper)
7435             {
7436                 return typeof(this)(_input[lower .. upper], _n);
7437             }
7438         }
7439     }
7440 
7441     auto opSlice() { return this; }
7442 
7443 private:
7444     RangeOfRanges _input;
7445     size_t _n;
7446 }
7447 
7448 /// Ditto
7449 Transversal!(RangeOfRanges, opt) transversal
7450 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
7451 (RangeOfRanges rr, size_t n)
7452 {
7453     return typeof(return)(rr, n);
7454 }
7455 
7456 ///
7457 @safe unittest
7458 {
7459     import std.algorithm.comparison : equal;
7460     int[][] x = new int[][2];
7461     x[0] = [1, 2];
7462     x[1] = [3, 4];
7463     auto ror = transversal(x, 1);
7464     assert(equal(ror, [ 2, 4 ]));
7465 }
7466 
7467 /// The following code does a full unzip
7468 @safe unittest
7469 {
7470     import std.algorithm.comparison : equal;
7471     import std.algorithm.iteration : map;
7472     int[][] y = [[1, 2, 3], [4, 5, 6]];
7473     auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
7474     assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
7475 }
7476 
7477 @safe unittest
7478 {
7479     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
7480 
7481     int[][] x = new int[][2];
7482     x[0] = [ 1, 2 ];
7483     x[1] = [3, 4];
7484     auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
7485     auto witness = [ 2, 4 ];
7486     uint i;
7487     foreach (e; ror) assert(e == witness[i++]);
7488     assert(i == 2);
7489     assert(ror.length == 2);
7490 
7491     static assert(is(Transversal!(immutable int[][])));
7492 
7493     // Make sure ref, assign is being propagated.
7494     {
7495         ror.front++;
7496         scope(exit) ror.front--;
7497         assert(x[0][1] == 3);
7498     }
7499     {
7500         ror.front = 5;
7501         scope(exit) ror.front = 2;
7502         assert(x[0][1] == 5);
7503         assert(ror.moveFront() == 5);
7504     }
7505     {
7506         ror.back = 999;
7507         scope(exit) ror.back = 4;
7508         assert(x[1][1] == 999);
7509         assert(ror.moveBack() == 999);
7510     }
7511     {
7512         ror[0] = 999;
7513         scope(exit) ror[0] = 2;
7514         assert(x[0][1] == 999);
7515         assert(ror.moveAt(0) == 999);
7516     }
7517 
7518     // Test w/o ref return.
7519     alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
7520     auto drs = [D.init, D.init];
7521     foreach (num; 0 .. 10)
7522     {
7523         auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
7524         assert(t[0] == t[1]);
7525         assert(t[1] == num + 1);
7526     }
7527 
7528     static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
7529 
7530     // Test slicing.
7531     auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
7532     auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
7533     assert(mat1[0] == 6);
7534     assert(mat1[1] == 10);
7535 }
7536 
7537 struct Transposed(RangeOfRanges,
7538     TransverseOptions opt = TransverseOptions.assumeJagged)
7539 if (isForwardRange!RangeOfRanges &&
7540     isInputRange!(ElementType!RangeOfRanges) &&
7541     hasAssignableElements!RangeOfRanges)
7542 {
7543     this(RangeOfRanges input)
7544     {
7545         this._input = input;
7546         static if (opt == TransverseOptions.enforceNotJagged)
7547         {
7548             import std.exception : enforce;
7549 
7550             if (empty) return;
7551             immutable commonLength = _input.front.length;
7552             foreach (e; _input)
7553             {
7554                 enforce(e.length == commonLength);
7555             }
7556         }
7557     }
7558 
7559     @property auto front()
7560     {
7561         import std.algorithm.iteration : filter, map;
7562         return _input.save
7563                      .filter!(a => !a.empty)
7564                      .map!(a => a.front);
7565     }
7566 
7567     void popFront()
7568     {
7569         // Advance the position of each subrange.
7570         auto r = _input.save;
7571         while (!r.empty)
7572         {
7573             auto e = r.front;
7574             if (!e.empty)
7575             {
7576                 e.popFront();
7577                 r.front = e;
7578             }
7579 
7580             r.popFront();
7581         }
7582     }
7583 
7584     static if (isRandomAccessRange!(ElementType!RangeOfRanges))
7585     {
7586         auto ref opIndex(size_t n)
7587         {
7588             return transversal!opt(_input, n);
7589         }
7590     }
7591 
7592     @property bool empty()
7593     {
7594         if (_input.empty) return true;
7595         foreach (e; _input.save)
7596         {
7597             if (!e.empty) return false;
7598         }
7599         return true;
7600     }
7601 
7602     deprecated("This function is incorrect and will be removed November 2018. See the docs for more details.")
7603     @property Transposed save()
7604     {
7605         return Transposed(_input.save);
7606     }
7607 
7608     auto opSlice() { return this; }
7609 
7610 private:
7611     RangeOfRanges _input;
7612 }
7613 
7614 @safe unittest
7615 {
7616     // Boundary case: transpose of empty range should be empty
7617     int[][] ror = [];
7618     assert(transposed(ror).empty);
7619 }
7620 
7621 // https://issues.dlang.org/show_bug.cgi?id=9507
7622 @safe unittest
7623 {
7624     import std.algorithm.comparison : equal;
7625 
7626     auto r = [[1,2], [3], [4,5], [], [6]];
7627     assert(r.transposed.equal!equal([
7628         [1, 3, 4, 6],
7629         [2, 5]
7630     ]));
7631 }
7632 
7633 // https://issues.dlang.org/show_bug.cgi?id=17742
7634 @safe unittest
7635 {
7636     import std.algorithm.iteration : map;
7637     import std.algorithm.comparison : equal;
7638     auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
7639     assert(ror[3][2] == 6);
7640     auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
7641     assert(result[2][3] == 6);
7642 
7643     auto x = [[1,2,3],[4,5,6]];
7644     auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
7645     assert(y.front.equal([1,4]));
7646     assert(y[0].equal([1,4]));
7647     assert(y[0][0] == 1);
7648     assert(y[1].equal([2,5]));
7649     assert(y[1][1] == 5);
7650 
7651     auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
7652     assert(yy.front.equal([1,4]));
7653     assert(yy[0].equal([1,4]));
7654     assert(yy[0][0] == 1);
7655     assert(yy[1].equal([2,5]));
7656     assert(yy[1][1] == 5);
7657 
7658     auto z = x.transposed; // assumeJagged
7659     assert(z.front.equal([1,4]));
7660     assert(z[0].equal([1,4]));
7661     assert(!is(typeof(z[0][0])));
7662 }
7663 
7664 @safe unittest
7665 {
7666     import std.exception : assertThrown;
7667 
7668     auto r = [[1,2], [3], [4,5], [], [6]];
7669     assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
7670 }
7671 
7672 /**
7673 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
7674 contains the $(I i)'th elements of the original subranges.
7675 
7676 $(RED `Transposed` currently defines `save`, but does not work as a forward range.
7677 Consuming a copy made with `save` will consume all copies, even the original sub-ranges
7678 fed into `Transposed`.)
7679 
7680 Params:
7681     opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
7682     rr = Range of ranges
7683  */
7684 Transposed!(RangeOfRanges, opt) transposed
7685 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
7686 (RangeOfRanges rr)
7687 if (isForwardRange!RangeOfRanges &&
7688     isInputRange!(ElementType!RangeOfRanges) &&
7689     hasAssignableElements!RangeOfRanges)
7690 {
7691     return Transposed!(RangeOfRanges, opt)(rr);
7692 }
7693 
7694 ///
7695 @safe unittest
7696 {
7697     import std.algorithm.comparison : equal;
7698     int[][] ror = [
7699         [1, 2, 3],
7700         [4, 5, 6]
7701     ];
7702     auto xp = transposed(ror);
7703     assert(equal!"a.equal(b)"(xp, [
7704         [1, 4],
7705         [2, 5],
7706         [3, 6]
7707     ]));
7708 }
7709 
7710 ///
7711 @safe unittest
7712 {
7713     int[][] x = new int[][2];
7714     x[0] = [1, 2];
7715     x[1] = [3, 4];
7716     auto tr = transposed(x);
7717     int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
7718     uint i;
7719 
7720     foreach (e; tr)
7721     {
7722         assert(array(e) == witness[i++]);
7723     }
7724 }
7725 
7726 // https://issues.dlang.org/show_bug.cgi?id=8764
7727 @safe unittest
7728 {
7729     import std.algorithm.comparison : equal;
7730     ulong[1] t0 = [ 123 ];
7731 
7732     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
7733     assert(!is(typeof(transposed(t0[].chunks(1)))));
7734     assert(is(typeof(transposed(t0[].chunks(1).array()))));
7735 
7736     auto t1 = transposed(t0[].chunks(1).array());
7737     assert(equal!"a.equal(b)"(t1, [[123]]));
7738 }
7739 
7740 /**
7741 This struct takes two ranges, `source` and `indices`, and creates a view
7742 of `source` as if its elements were reordered according to `indices`.
7743 `indices` may include only a subset of the elements of `source` and
7744 may also repeat elements.
7745 
7746 `Source` must be a random access range.  The returned range will be
7747 bidirectional or random-access if `Indices` is bidirectional or
7748 random-access, respectively.
7749 */
7750 struct Indexed(Source, Indices)
7751 if (isRandomAccessRange!Source && isInputRange!Indices &&
7752     is(typeof(Source.init[ElementType!(Indices).init])))
7753 {
7754     this(Source source, Indices indices)
7755     {
7756         this._source = source;
7757         this._indices = indices;
7758     }
7759 
7760     /// Range primitives
7761     @property auto ref front()
7762     {
7763         assert(!empty, "Attempting to fetch the front of an empty Indexed");
7764         return _source[_indices.front];
7765     }
7766 
7767     /// Ditto
7768     void popFront()
7769     {
7770         assert(!empty, "Attempting to popFront an empty Indexed");
7771         _indices.popFront();
7772     }
7773 
7774     static if (isInfinite!Indices)
7775     {
7776         enum bool empty = false;
7777     }
7778     else
7779     {
7780         /// Ditto
7781         @property bool empty()
7782         {
7783             return _indices.empty;
7784         }
7785     }
7786 
7787     static if (isForwardRange!Indices)
7788     {
7789         /// Ditto
7790         @property typeof(this) save()
7791         {
7792             // Don't need to save _source because it's never consumed.
7793             return typeof(this)(_source, _indices.save);
7794         }
7795     }
7796 
7797     /// Ditto
7798     static if (hasAssignableElements!Source)
7799     {
7800         @property auto ref front(ElementType!Source newVal)
7801         {
7802             assert(!empty);
7803             return _source[_indices.front] = newVal;
7804         }
7805     }
7806 
7807 
7808     static if (hasMobileElements!Source)
7809     {
7810         /// Ditto
7811         auto moveFront()
7812         {
7813             assert(!empty);
7814             return _source.moveAt(_indices.front);
7815         }
7816     }
7817 
7818     static if (isBidirectionalRange!Indices)
7819     {
7820         /// Ditto
7821         @property auto ref back()
7822         {
7823             assert(!empty, "Attempting to fetch the back of an empty Indexed");
7824             return _source[_indices.back];
7825         }
7826 
7827         /// Ditto
7828         void popBack()
7829         {
7830            assert(!empty, "Attempting to popBack an empty Indexed");
7831            _indices.popBack();
7832         }
7833 
7834         /// Ditto
7835         static if (hasAssignableElements!Source)
7836         {
7837             @property auto ref back(ElementType!Source newVal)
7838             {
7839                 assert(!empty);
7840                 return _source[_indices.back] = newVal;
7841             }
7842         }
7843 
7844 
7845         static if (hasMobileElements!Source)
7846         {
7847             /// Ditto
7848             auto moveBack()
7849             {
7850                 assert(!empty);
7851                 return _source.moveAt(_indices.back);
7852             }
7853         }
7854     }
7855 
7856     static if (hasLength!Indices)
7857     {
7858         /// Ditto
7859          @property size_t length()
7860         {
7861             return _indices.length;
7862         }
7863 
7864         alias opDollar = length;
7865     }
7866 
7867     static if (isRandomAccessRange!Indices)
7868     {
7869         /// Ditto
7870         auto ref opIndex(size_t index)
7871         {
7872             return _source[_indices[index]];
7873         }
7874 
7875         static if (hasSlicing!Indices)
7876         {
7877             /// Ditto
7878             typeof(this) opSlice(size_t a, size_t b)
7879             {
7880                 return typeof(this)(_source, _indices[a .. b]);
7881             }
7882         }
7883 
7884 
7885         static if (hasAssignableElements!Source)
7886         {
7887             /// Ditto
7888             auto opIndexAssign(ElementType!Source newVal, size_t index)
7889             {
7890                 return _source[_indices[index]] = newVal;
7891             }
7892         }
7893 
7894 
7895         static if (hasMobileElements!Source)
7896         {
7897             /// Ditto
7898             auto moveAt(size_t index)
7899             {
7900                 return _source.moveAt(_indices[index]);
7901             }
7902         }
7903     }
7904 
7905     // All this stuff is useful if someone wants to index an Indexed
7906     // without adding a layer of indirection.
7907 
7908     /**
7909     Returns the source range.
7910     */
7911     @property Source source()
7912     {
7913         return _source;
7914     }
7915 
7916     /**
7917     Returns the indices range.
7918     */
7919      @property Indices indices()
7920     {
7921         return _indices;
7922     }
7923 
7924     static if (isRandomAccessRange!Indices)
7925     {
7926         /**
7927         Returns the physical index into the source range corresponding to a
7928         given logical index.  This is useful, for example, when indexing
7929         an `Indexed` without adding another layer of indirection.
7930         */
7931         size_t physicalIndex(size_t logicalIndex)
7932         {
7933             return _indices[logicalIndex];
7934         }
7935 
7936         ///
7937         @safe unittest
7938         {
7939             auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
7940             assert(ind.physicalIndex(0) == 1);
7941         }
7942     }
7943 
7944 private:
7945     Source _source;
7946     Indices _indices;
7947 
7948 }
7949 
7950 /// Ditto
7951 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
7952 {
7953     return typeof(return)(source, indices);
7954 }
7955 
7956 ///
7957 @safe unittest
7958 {
7959     import std.algorithm.comparison : equal;
7960     auto source = [1, 2, 3, 4, 5];
7961     auto indices = [4, 3, 1, 2, 0, 4];
7962     auto ind = indexed(source, indices);
7963     assert(equal(ind, [5, 4, 2, 3, 1, 5]));
7964     assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
7965 }
7966 
7967 @safe unittest
7968 {
7969     {
7970         auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
7971         assert(ind.physicalIndex(0) == 1);
7972     }
7973 
7974     auto source = [1, 2, 3, 4, 5];
7975     auto indices = [4, 3, 1, 2, 0, 4];
7976     auto ind = indexed(source, indices);
7977 
7978     // When elements of indices are duplicated and Source has lvalue elements,
7979     // these are aliased in ind.
7980     ind[0]++;
7981     assert(ind[0] == 6);
7982     assert(ind[5] == 6);
7983 }
7984 
7985 @safe unittest
7986 {
7987     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
7988         propagatesRangeType, RangeType;
7989 
7990     foreach (DummyType; AllDummyRanges)
7991     {
7992         auto d = DummyType.init;
7993         auto r = indexed([1, 2, 3, 4, 5], d);
7994         static assert(propagatesRangeType!(DummyType, typeof(r)));
7995         static assert(propagatesLength!(DummyType, typeof(r)));
7996     }
7997 }
7998 
7999 /**
8000 This range iterates over fixed-sized chunks of size `chunkSize` of a
8001 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8002 `chunkSize` must be greater than zero.
8003 
8004 If `!isInfinite!Source` and `source.walkLength` is not evenly
8005 divisible by `chunkSize`, the back element of this range will contain
8006 fewer than `chunkSize` elements.
8007 
8008 If `Source` is a forward range, the resulting range will be forward ranges as
8009 well. Otherwise, the resulting chunks will be input ranges consuming the same
8010 input: iterating over `front` will shrink the chunk such that subsequent
8011 invocations of `front` will no longer return the full chunk, and calling
8012 `popFront` on the outer range will invalidate any lingering references to
8013 previous values of `front`.
8014 
8015 Params:
8016     source = Range from which the chunks will be selected
8017     chunkSize = Chunk size
8018 
8019 See_Also: $(LREF slide)
8020 
8021 Returns: Range of chunks.
8022 */
8023 struct Chunks(Source)
8024 if (isInputRange!Source)
8025 {
8026     static if (isForwardRange!Source)
8027     {
8028         /// Standard constructor
8029         this(Source source, size_t chunkSize)
8030         {
8031             assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8032             _source = source;
8033             _chunkSize = chunkSize;
8034         }
8035 
8036         /// Input range primitives. Always present.
8037         @property auto front()
8038         {
8039             assert(!empty, "Attempting to fetch the front of an empty Chunks");
8040             return _source.save.take(_chunkSize);
8041         }
8042 
8043         /// Ditto
8044         void popFront()
8045         {
8046             assert(!empty, "Attempting to popFront and empty Chunks");
8047             _source.popFrontN(_chunkSize);
8048         }
8049 
8050         static if (!isInfinite!Source)
8051             /// Ditto
8052             @property bool empty()
8053             {
8054                 return _source.empty;
8055             }
8056         else
8057             // undocumented
8058             enum empty = false;
8059 
8060         /// Forward range primitives. Only present if `Source` is a forward range.
8061         @property typeof(this) save()
8062         {
8063             return typeof(this)(_source.save, _chunkSize);
8064         }
8065 
8066         static if (hasLength!Source)
8067         {
8068             /// Length. Only if `hasLength!Source` is `true`
8069             @property size_t length()
8070             {
8071                 // Note: _source.length + _chunkSize may actually overflow.
8072                 // We cast to ulong to mitigate the problem on x86 machines.
8073                 // For x64 machines, we just suppose we'll never overflow.
8074                 // The "safe" code would require either an extra branch, or a
8075                 //   modulo operation, which is too expensive for such a rare case
8076                 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8077             }
8078             //Note: No point in defining opDollar here without slicing.
8079             //opDollar is defined below in the hasSlicing!Source section
8080         }
8081 
8082         static if (hasSlicing!Source)
8083         {
8084             //Used for various purposes
8085             private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8086 
8087             /**
8088             Indexing and slicing operations. Provided only if
8089             `hasSlicing!Source` is `true`.
8090              */
8091             auto opIndex(size_t index)
8092             {
8093                 immutable start = index * _chunkSize;
8094                 immutable end   = start + _chunkSize;
8095 
8096                 static if (isInfinite!Source)
8097                     return _source[start .. end];
8098                 else
8099                 {
8100                     import std.algorithm.comparison : min;
8101                     immutable len = _source.length;
8102                     assert(start < len, "chunks index out of bounds");
8103                     return _source[start .. min(end, len)];
8104                 }
8105             }
8106 
8107             /// Ditto
8108             static if (hasLength!Source)
8109                 typeof(this) opSlice(size_t lower, size_t upper)
8110                 {
8111                     import std.algorithm.comparison : min;
8112                     assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8113                     immutable len = _source.length;
8114                     return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8115                 }
8116             else static if (hasSliceToEnd)
8117                 //For slicing an infinite chunk, we need to slice the source to the end.
8118                 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8119                 {
8120                     assert(lower <= upper, "chunks slicing index out of bounds");
8121                     return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8122                 }
8123 
8124             static if (isInfinite!Source)
8125             {
8126                 static if (hasSliceToEnd)
8127                 {
8128                     private static struct DollarToken{}
8129                     DollarToken opDollar()
8130                     {
8131                         return DollarToken();
8132                     }
8133                     //Slice to dollar
8134                     typeof(this) opSlice(size_t lower, DollarToken)
8135                     {
8136                         return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8137                     }
8138                 }
8139             }
8140             else
8141             {
8142                 //Dollar token carries a static type, with no extra information.
8143                 //It can lazily transform into _source.length on algorithmic
8144                 //operations such as : chunks[$/2, $-1];
8145                 private static struct DollarToken
8146                 {
8147                     Chunks!Source* mom;
8148                     @property size_t momLength()
8149                     {
8150                         return mom.length;
8151                     }
8152                     alias momLength this;
8153                 }
8154                 DollarToken opDollar()
8155                 {
8156                     return DollarToken(&this);
8157                 }
8158 
8159                 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8160                 //1. Evaluate chunks.length
8161                 //2. Multiply by _chunksSize
8162                 //3. To finally just compare it (with min) to the original length of source (!)
8163                 //These overloads avoid that.
8164                 typeof(this) opSlice(DollarToken, DollarToken)
8165                 {
8166                     static if (hasSliceToEnd)
8167                         return chunks(_source[$ .. $], _chunkSize);
8168                     else
8169                     {
8170                         immutable len = _source.length;
8171                         return chunks(_source[len .. len], _chunkSize);
8172                     }
8173                 }
8174                 typeof(this) opSlice(size_t lower, DollarToken)
8175                 {
8176                     import std.algorithm.comparison : min;
8177                     assert(lower <= length, "chunks slicing index out of bounds");
8178                     static if (hasSliceToEnd)
8179                         return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8180                     else
8181                     {
8182                         immutable len = _source.length;
8183                         return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8184                     }
8185                 }
8186                 typeof(this) opSlice(DollarToken, size_t upper)
8187                 {
8188                     assert(upper == length, "chunks slicing index out of bounds");
8189                     return this[$ .. $];
8190                 }
8191             }
8192         }
8193 
8194         //Bidirectional range primitives
8195         static if (hasSlicing!Source && hasLength!Source)
8196         {
8197             /**
8198             Bidirectional range primitives. Provided only if both
8199             `hasSlicing!Source` and `hasLength!Source` are `true`.
8200              */
8201             @property auto back()
8202             {
8203                 assert(!empty, "back called on empty chunks");
8204                 immutable len = _source.length;
8205                 immutable start = (len - 1) / _chunkSize * _chunkSize;
8206                 return _source[start .. len];
8207             }
8208 
8209             /// Ditto
8210             void popBack()
8211             {
8212                 assert(!empty, "popBack() called on empty chunks");
8213                 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8214                 _source = _source[0 .. end];
8215             }
8216         }
8217 
8218     private:
8219         Source _source;
8220         size_t _chunkSize;
8221     }
8222     else // is input range only
8223     {
8224         import std.typecons : RefCounted;
8225 
8226         static struct Chunk
8227         {
8228             private RefCounted!Impl impl;
8229 
8230             @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8231             @property auto front() { return impl.r.front; }
8232             void popFront()
8233             {
8234                 assert(impl.curSizeLeft > 0 && !impl.r.empty);
8235                 impl.curSizeLeft--;
8236                 impl.r.popFront();
8237             }
8238         }
8239 
8240         static struct Impl
8241         {
8242             private Source r;
8243             private size_t chunkSize;
8244             private size_t curSizeLeft;
8245         }
8246 
8247         private RefCounted!Impl impl;
8248 
8249         private this(Source r, size_t chunkSize)
8250         {
8251             impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8252         }
8253 
8254         @property bool empty() { return impl.chunkSize == 0; }
8255         @property Chunk front() return { return Chunk(impl); }
8256 
8257         void popFront()
8258         {
8259             impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8260             if (!impl.r.empty)
8261                 impl.curSizeLeft = impl.chunkSize;
8262             else
8263                 impl.chunkSize = 0;
8264         }
8265 
8266         static assert(isInputRange!(typeof(this)));
8267     }
8268 }
8269 
8270 /// Ditto
8271 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8272 if (isInputRange!Source)
8273 {
8274     return typeof(return)(source, chunkSize);
8275 }
8276 
8277 ///
8278 @safe unittest
8279 {
8280     import std.algorithm.comparison : equal;
8281     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8282     auto chunks = chunks(source, 4);
8283     assert(chunks[0] == [1, 2, 3, 4]);
8284     assert(chunks[1] == [5, 6, 7, 8]);
8285     assert(chunks[2] == [9, 10]);
8286     assert(chunks.back == chunks[2]);
8287     assert(chunks.front == chunks[0]);
8288     assert(chunks.length == 3);
8289     assert(equal(retro(array(chunks)), array(retro(chunks))));
8290 }
8291 
8292 /// Non-forward input ranges are supported, but with limited semantics.
8293 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8294 {
8295     import std.algorithm.comparison : equal;
8296 
8297     int i;
8298 
8299     // The generator doesn't save state, so it cannot be a forward range.
8300     auto inputRange = generate!(() => ++i).take(10);
8301 
8302     // We can still process it in chunks, but it will be single-pass only.
8303     auto chunked = inputRange.chunks(2);
8304 
8305     assert(chunked.front.equal([1, 2]));
8306     assert(chunked.front.empty); // Iterating the chunk has consumed it
8307     chunked.popFront;
8308     assert(chunked.front.equal([3, 4]));
8309 }
8310 
8311 @system /*@safe*/ unittest
8312 {
8313     import std.algorithm.comparison : equal;
8314     import std.internal.test.dummyrange : ReferenceInputRange;
8315 
8316     auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
8317     auto r = new ReferenceInputRange!int(data).chunks(3);
8318     assert(r.equal!equal([
8319         [ 1, 2, 3 ],
8320         [ 4, 5, 6 ],
8321         [ 7, 8, 9 ],
8322         [ 10 ]
8323     ]));
8324 
8325     auto data2 = [ 1, 2, 3, 4, 5, 6 ];
8326     auto r2 = new ReferenceInputRange!int(data2).chunks(3);
8327     assert(r2.equal!equal([
8328         [ 1, 2, 3 ],
8329         [ 4, 5, 6 ]
8330     ]));
8331 
8332     auto data3 = [ 1, 2, 3, 4, 5 ];
8333     auto r3 = new ReferenceInputRange!int(data3).chunks(2);
8334     assert(r3.front.equal([1, 2]));
8335     r3.popFront();
8336     assert(!r3.empty);
8337     r3.popFront();
8338     assert(r3.front.equal([5]));
8339 }
8340 
8341 @safe unittest
8342 {
8343     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8344     auto chunks = chunks(source, 4);
8345     auto chunks2 = chunks.save;
8346     chunks.popFront();
8347     assert(chunks[0] == [5, 6, 7, 8]);
8348     assert(chunks[1] == [9, 10]);
8349     chunks2.popBack();
8350     assert(chunks2[1] == [5, 6, 7, 8]);
8351     assert(chunks2.length == 2);
8352 
8353     static assert(isRandomAccessRange!(typeof(chunks)));
8354 }
8355 
8356 @safe unittest
8357 {
8358     import std.algorithm.comparison : equal;
8359 
8360     //Extra toying with slicing and indexing.
8361     auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
8362     auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
8363 
8364     assert(chunks1.length == 5);
8365     assert(chunks2.length == 5);
8366     assert(chunks1[4] == [4]);
8367     assert(chunks2[4] == [4, 4]);
8368     assert(chunks1.back == [4]);
8369     assert(chunks2.back == [4, 4]);
8370 
8371     assert(chunks1[0 .. 1].equal([[0, 0]]));
8372     assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
8373     assert(chunks1[4 .. 5].equal([[4]]));
8374     assert(chunks2[4 .. 5].equal([[4, 4]]));
8375 
8376     assert(chunks1[0 .. 0].equal((int[][]).init));
8377     assert(chunks1[5 .. 5].equal((int[][]).init));
8378     assert(chunks2[5 .. 5].equal((int[][]).init));
8379 
8380     //Fun with opDollar
8381     assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
8382     assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
8383     assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
8384     assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
8385     assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
8386     assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
8387 
8388     assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
8389 }
8390 
8391 @safe unittest
8392 {
8393     import std.algorithm.comparison : equal;
8394     import std.algorithm.iteration : filter;
8395 
8396     //ForwardRange
8397     auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
8398     assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
8399 
8400     //InfiniteRange w/o RA
8401     auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
8402     assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
8403 
8404     //InfiniteRange w/ RA and slicing
8405     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
8406     auto oddsByPairs = odds.chunks(2);
8407     assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
8408 
8409     //Requires phobos#991 for Sequence to have slice to end
8410     static assert(hasSlicing!(typeof(odds)));
8411     assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
8412     assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
8413 }
8414 
8415 
8416 
8417 /**
8418 This range splits a `source` range into `chunkCount` chunks of
8419 approximately equal length. `Source` must be a forward range with
8420 known length.
8421 
8422 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
8423 The returned range will contain zero or more $(D source.length /
8424 chunkCount + 1) elements followed by $(D source.length / chunkCount)
8425 elements. If $(D source.length < chunkCount), some chunks will be empty.
8426 
8427 `chunkCount` must not be zero, unless `source` is also empty.
8428 */
8429 struct EvenChunks(Source)
8430 if (isForwardRange!Source && hasLength!Source)
8431 {
8432     /// Standard constructor
8433     this(Source source, size_t chunkCount)
8434     {
8435         assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
8436         _source = source;
8437         _chunkCount = chunkCount;
8438     }
8439 
8440     /// Forward range primitives. Always present.
8441     @property auto front()
8442     {
8443         assert(!empty, "Attempting to fetch the front of an empty evenChunks");
8444         return _source.save.take(_chunkPos(1));
8445     }
8446 
8447     /// Ditto
8448     void popFront()
8449     {
8450         assert(!empty, "Attempting to popFront an empty evenChunks");
8451         _source.popFrontN(_chunkPos(1));
8452         _chunkCount--;
8453     }
8454 
8455     /// Ditto
8456     @property bool empty()
8457     {
8458         return _source.empty;
8459     }
8460 
8461     /// Ditto
8462     @property typeof(this) save()
8463     {
8464         return typeof(this)(_source.save, _chunkCount);
8465     }
8466 
8467     /// Length
8468     @property size_t length() const
8469     {
8470         return _chunkCount;
8471     }
8472     //Note: No point in defining opDollar here without slicing.
8473     //opDollar is defined below in the hasSlicing!Source section
8474 
8475     static if (hasSlicing!Source)
8476     {
8477         /**
8478         Indexing, slicing and bidirectional operations and range primitives.
8479         Provided only if `hasSlicing!Source` is `true`.
8480          */
8481         auto opIndex(size_t index)
8482         {
8483             assert(index < _chunkCount, "evenChunks index out of bounds");
8484             return _source[_chunkPos(index) .. _chunkPos(index+1)];
8485         }
8486 
8487         /// Ditto
8488         typeof(this) opSlice(size_t lower, size_t upper)
8489         {
8490             assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
8491             return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
8492         }
8493 
8494         /// Ditto
8495         @property auto back()
8496         {
8497             assert(!empty, "back called on empty evenChunks");
8498             return _source[_chunkPos(_chunkCount - 1) .. _source.length];
8499         }
8500 
8501         /// Ditto
8502         void popBack()
8503         {
8504             assert(!empty, "popBack() called on empty evenChunks");
8505             _source = _source[0 .. _chunkPos(_chunkCount - 1)];
8506             _chunkCount--;
8507         }
8508     }
8509 
8510 private:
8511     Source _source;
8512     size_t _chunkCount;
8513 
8514     size_t _chunkPos(size_t i)
8515     {
8516         /*
8517             _chunkCount = 5, _source.length = 13:
8518 
8519                chunk0
8520                  |   chunk3
8521                  |     |
8522                  v     v
8523                 +-+-+-+-+-+   ^
8524                 |0|3|.| | |   |
8525                 +-+-+-+-+-+   | div
8526                 |1|4|.| | |   |
8527                 +-+-+-+-+-+   v
8528                 |2|5|.|
8529                 +-+-+-+
8530 
8531                 <----->
8532                   mod
8533 
8534                 <--------->
8535                 _chunkCount
8536 
8537             One column is one chunk.
8538             popFront and popBack pop the left-most
8539             and right-most column, respectively.
8540         */
8541 
8542         auto div = _source.length / _chunkCount;
8543         auto mod = _source.length % _chunkCount;
8544         auto pos = i <= mod
8545             ? i   * (div+1)
8546             : mod * (div+1) + (i-mod) * div
8547         ;
8548         //auto len = i < mod
8549         //    ? div+1
8550         //    : div
8551         //;
8552         return pos;
8553     }
8554 }
8555 
8556 /// Ditto
8557 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
8558 if (isForwardRange!Source && hasLength!Source)
8559 {
8560     return typeof(return)(source, chunkCount);
8561 }
8562 
8563 ///
8564 @safe unittest
8565 {
8566     import std.algorithm.comparison : equal;
8567     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8568     auto chunks = evenChunks(source, 3);
8569     assert(chunks[0] == [1, 2, 3, 4]);
8570     assert(chunks[1] == [5, 6, 7]);
8571     assert(chunks[2] == [8, 9, 10]);
8572 }
8573 
8574 @safe unittest
8575 {
8576     import std.algorithm.comparison : equal;
8577 
8578     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8579     auto chunks = evenChunks(source, 3);
8580     assert(chunks.back == chunks[2]);
8581     assert(chunks.front == chunks[0]);
8582     assert(chunks.length == 3);
8583     assert(equal(retro(array(chunks)), array(retro(chunks))));
8584 
8585     auto chunks2 = chunks.save;
8586     chunks.popFront();
8587     assert(chunks[0] == [5, 6, 7]);
8588     assert(chunks[1] == [8, 9, 10]);
8589     chunks2.popBack();
8590     assert(chunks2[1] == [5, 6, 7]);
8591     assert(chunks2.length == 2);
8592 
8593     static assert(isRandomAccessRange!(typeof(chunks)));
8594 }
8595 
8596 @safe unittest
8597 {
8598     import std.algorithm.comparison : equal;
8599 
8600     int[] source = [];
8601     auto chunks = source.evenChunks(0);
8602     assert(chunks.length == 0);
8603     chunks = source.evenChunks(3);
8604     assert(equal(chunks, [[], [], []]));
8605     chunks = [1, 2, 3].evenChunks(5);
8606     assert(equal(chunks, [[1], [2], [3], [], []]));
8607 }
8608 
8609 /**
8610 A fixed-sized sliding window iteration
8611 of size `windowSize` over a `source` range by a custom `stepSize`.
8612 
8613 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
8614 and the `windowSize` must be greater than zero.
8615 
8616 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
8617 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
8618 
8619 Params:
8620     f = Whether the last element has fewer elements than `windowSize`
8621         it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
8622     source = Range from which the slide will be selected
8623     windowSize = Sliding window size
8624     stepSize = Steps between the windows (by default 1)
8625 
8626 Returns: Range of all sliding windows with propagated bi-directionality,
8627          forwarding, random access, and slicing.
8628 
8629 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
8630       is only available when $(REF hasSlicing, std,range,primitives)
8631       and $(REF hasLength, std,range,primitives) are true.
8632 
8633 See_Also: $(LREF chunks)
8634 */
8635 auto slide(Flag!"withPartial" f = Yes.withPartial,
8636             Source)(Source source, size_t windowSize, size_t stepSize = 1)
8637 if (isForwardRange!Source)
8638 {
8639     return Slides!(f, Source)(source, windowSize, stepSize);
8640 }
8641 
8642 /// Iterate over ranges with windows
8643 @safe pure nothrow unittest
8644 {
8645     import std.algorithm.comparison : equal;
8646 
8647     assert([0, 1, 2, 3].slide(2).equal!equal(
8648         [[0, 1], [1, 2], [2, 3]]
8649     ));
8650 
8651     assert(5.iota.slide(3).equal!equal(
8652         [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
8653     ));
8654 }
8655 
8656 /// set a custom stepsize (default 1)
8657 @safe pure nothrow unittest
8658 {
8659     import std.algorithm.comparison : equal;
8660 
8661     assert(6.iota.slide(1, 2).equal!equal(
8662         [[0], [2], [4]]
8663     ));
8664 
8665     assert(6.iota.slide(2, 4).equal!equal(
8666         [[0, 1], [4, 5]]
8667     ));
8668 
8669     assert(iota(7).slide(2, 2).equal!equal(
8670         [[0, 1], [2, 3], [4, 5], [6]]
8671     ));
8672 
8673     assert(iota(12).slide(2, 4).equal!equal(
8674         [[0, 1], [4, 5], [8, 9]]
8675     ));
8676 }
8677 
8678 /// Allow the last slide to have fewer elements than windowSize
8679 @safe pure nothrow unittest
8680 {
8681     import std.algorithm.comparison : equal;
8682 
8683     assert(3.iota.slide!(No.withPartial)(4).empty);
8684     assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
8685         [[0, 1, 2]]
8686     ));
8687 }
8688 
8689 /// Count all the possible substrings of length 2
8690 @safe pure nothrow unittest
8691 {
8692     import std.algorithm.iteration : each;
8693 
8694     int[dstring] d;
8695     "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
8696     assert(d == ["AG"d: 2, "GA"d: 2]);
8697 }
8698 
8699 /// withPartial only has an effect if last element in the range doesn't have the full size
8700 @safe pure nothrow unittest
8701 {
8702     import std.algorithm.comparison : equal;
8703 
8704     assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
8705     assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
8706     assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
8707 
8708     assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
8709     assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
8710     assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
8711 }
8712 
8713 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
8714 if (isForwardRange!Source)
8715 {
8716 private:
8717     Source source;
8718     size_t windowSize;
8719     size_t stepSize;
8720 
8721     static if (hasLength!Source)
8722     {
8723         enum needsEndTracker = false;
8724     }
8725     else
8726     {
8727         // If there's no information about the length, track needs to be kept manually
8728         Source nextSource;
8729         enum needsEndTracker = true;
8730     }
8731 
8732     bool _empty;
8733 
8734     static if (hasSlicing!Source)
8735         enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
8736 
8737     static if (withPartial)
8738         bool hasShownPartialBefore;
8739 
8740 public:
8741     /// Standard constructor
8742     this(Source source, size_t windowSize, size_t stepSize)
8743     {
8744         assert(windowSize > 0, "windowSize must be greater than zero");
8745         assert(stepSize > 0, "stepSize must be greater than zero");
8746         this.source = source;
8747         this.windowSize = windowSize;
8748         this.stepSize = stepSize;
8749 
8750         static if (needsEndTracker)
8751         {
8752             // `nextSource` is used to "look one step into the future" and check for the end
8753             // this means `nextSource` is advanced by `stepSize` on every `popFront`
8754             nextSource = source.save.drop(windowSize);
8755         }
8756 
8757         if (source.empty)
8758         {
8759             _empty = true;
8760             return;
8761         }
8762 
8763         static if (withPartial)
8764         {
8765             static if (needsEndTracker)
8766             {
8767                 if (nextSource.empty)
8768                     hasShownPartialBefore = true;
8769             }
8770             else
8771             {
8772                 if (source.length <= windowSize)
8773                     hasShownPartialBefore = true;
8774             }
8775 
8776         }
8777         else
8778         {
8779             // empty source range is needed, s.t. length, slicing etc. works properly
8780             static if (needsEndTracker)
8781             {
8782                 if (nextSource.empty)
8783                      _empty = true;
8784             }
8785             else
8786             {
8787                 if (source.length < windowSize)
8788                      _empty = true;
8789             }
8790         }
8791     }
8792 
8793     /// Forward range primitives. Always present.
8794     @property auto front()
8795     {
8796         assert(!empty, "Attempting to access front on an empty slide.");
8797         static if (hasSlicing!Source && hasLength!Source)
8798         {
8799             static if (withPartial)
8800             {
8801                 import std.algorithm.comparison : min;
8802                 return source[0 .. min(windowSize, source.length)];
8803             }
8804             else
8805             {
8806                 assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
8807                 return source[0 .. windowSize];
8808             }
8809         }
8810         else
8811         {
8812             static if (withPartial)
8813                 return source.save.take(windowSize);
8814             else
8815                 return source.save.takeExactly(windowSize);
8816         }
8817     }
8818 
8819     /// Ditto
8820     void popFront()
8821     {
8822         assert(!empty, "Attempting to call popFront() on an empty slide.");
8823         source.popFrontN(stepSize);
8824 
8825         if (source.empty)
8826         {
8827             _empty = true;
8828             return;
8829         }
8830 
8831         static if (withPartial)
8832         {
8833             if (hasShownPartialBefore)
8834                 _empty = true;
8835         }
8836 
8837         static if (needsEndTracker)
8838         {
8839             // Check the upcoming slide
8840             auto poppedElements = nextSource.popFrontN(stepSize);
8841             static if (withPartial)
8842             {
8843                 if (poppedElements < stepSize || nextSource.empty)
8844                     hasShownPartialBefore = true;
8845             }
8846             else
8847             {
8848                 if (poppedElements < stepSize)
8849                     _empty = true;
8850             }
8851         }
8852         else
8853         {
8854             static if (withPartial)
8855             {
8856                 if (source.length <= windowSize)
8857                     hasShownPartialBefore = true;
8858             }
8859             else
8860             {
8861                 if (source.length < windowSize)
8862                     _empty = true;
8863             }
8864         }
8865     }
8866 
8867     static if (!isInfinite!Source)
8868     {
8869         /// Ditto
8870         @property bool empty() const
8871         {
8872             return _empty;
8873         }
8874     }
8875     else
8876     {
8877         // undocumented
8878         enum empty = false;
8879     }
8880 
8881     /// Ditto
8882     @property typeof(this) save()
8883     {
8884         return typeof(this)(source.save, windowSize, stepSize);
8885     }
8886 
8887     static if (hasLength!Source)
8888     {
8889         // gaps between the last element and the end of the range
8890         private size_t gap()
8891         {
8892             /*
8893             * Note:
8894             * - In the following `end` is the exclusive end as used in opSlice
8895             * - For the trivial case with `stepSize = 1`  `end` is at `len`:
8896             *
8897             *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]]    (end = 4)
8898             *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]      (end = 4)
8899             *
8900             * - For the non-trivial cases, we need to calculate the gap
8901             *   between `len` and `end` - this is the number of missing elements
8902             *   from the input range:
8903             *
8904             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
8905             *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
8906             *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
8907             *
8908             *   As it can be seen `gap` can be at most `stepSize - 1`
8909             *   More generally the elements of the sliding window with
8910             *   `w = windowSize` and `s = stepSize` are:
8911             *
8912             *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
8913             *
8914             *  We can thus calculate the gap between the `end` and `len` as:
8915             *
8916             *     gap = len - (n * s + w) = len - w - (n * s)
8917             *
8918             *  As we aren't interested in exact value of `n`, but the best
8919             *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
8920             *
8921             *     gap = len - w - (s - s ... - s) = (len - w) % s
8922             *
8923             *  So for example:
8924             *
8925             *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
8926             *      gap: (7 - 2) % 3 = 5 % 3 = 2
8927             *      end: 7 - 2 = 5
8928             *
8929             *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
8930             *      gap: (7 - 4) % 2 = 3 % 2 = 1
8931             *      end: 7 - 1 = 6
8932             */
8933             return (source.length - windowSize)  % stepSize;
8934         }
8935 
8936         private size_t numberOfFullFrames()
8937         {
8938             /**
8939             5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
8940             7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (3)
8941             7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (2)
8942             6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5]         (2)
8943             7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (2)
8944 
8945             As the last window is only added iff its complete,
8946             we don't count the last window except if it's full due to integer rounding.
8947             */
8948             return 1 + (source.length - windowSize) / stepSize;
8949         }
8950 
8951         // Whether the last slide frame size is less than windowSize
8952         private bool hasPartialElements()
8953         {
8954             static if (withPartial)
8955                 return gap != 0 && source.length > numberOfFullFrames * stepSize;
8956             else
8957                 return 0;
8958         }
8959 
8960         /// Length. Only if `hasLength!Source` is `true`
8961         @property size_t length()
8962         {
8963             if (source.length < windowSize)
8964             {
8965                 static if (withPartial)
8966                     return source.length > 0;
8967                 else
8968                     return 0;
8969             }
8970             else
8971             {
8972                 /***
8973                   We bump the pointer by stepSize for every element.
8974                   If withPartial, we don't count the last element if its size
8975                   isn't windowSize
8976 
8977                   At most:
8978                       [p, p + stepSize, ..., p + stepSize * n]
8979 
8980                 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
8981                 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (4)
8982                 7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (3)
8983                 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6]      (3)
8984                 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (3)
8985                 */
8986                 return numberOfFullFrames + hasPartialElements;
8987             }
8988         }
8989     }
8990 
8991     static if (hasSlicing!Source)
8992     {
8993         /**
8994         Indexing and slicing operations. Provided only if
8995         `hasSlicing!Source` is `true`.
8996          */
8997         auto opIndex(size_t index)
8998         {
8999             immutable start = index * stepSize;
9000 
9001             static if (isInfinite!Source)
9002             {
9003                 immutable end = start + windowSize;
9004             }
9005             else
9006             {
9007                 import std.algorithm.comparison : min;
9008 
9009                 immutable len = source.length;
9010                 assert(start < len, "slide index out of bounds");
9011                 immutable end = min(start + windowSize, len);
9012             }
9013 
9014             return source[start .. end];
9015         }
9016 
9017         static if (!isInfinite!Source)
9018         {
9019             /// ditto
9020             typeof(this) opSlice(size_t lower, size_t upper)
9021             {
9022                 import std.algorithm.comparison : min;
9023 
9024                 assert(upper <= length, "slide slicing index out of bounds");
9025                 assert(lower <= upper, "slide slicing index out of bounds");
9026 
9027                 lower *= stepSize;
9028                 upper *= stepSize;
9029 
9030                 immutable len = source.length;
9031 
9032                 static if (withPartial)
9033                 {
9034                     import std.algorithm.comparison : max;
9035 
9036                     if (lower == upper)
9037                         return this[$ .. $];
9038 
9039                     /*
9040                     A) If `stepSize` >= `windowSize` => `rightPos = upper`
9041 
9042                        [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9043                          rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9044                          6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9045 
9046                     B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9047 
9048                        [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9049                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9050                          1.iota.slide(2) = [[0]]
9051 
9052                          rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9053                          1.iota.slide(2) = [[0, 1]]
9054 
9055                        More complex:
9056 
9057                        20.iota.slide(7, 6)[0 .. 2]
9058                          rightPos: (upper=2) * (stepSize=6) = 12.iota
9059                          12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9060 
9061                        Now we add up for the difference between `windowSize` and `stepSize`:
9062 
9063                          rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9064                          13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9065                     */
9066                     immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9067                 }
9068                 else
9069                 {
9070                     /*
9071                     After we have normalized `lower` and `upper` by `stepSize`,
9072                     we only need to look at the case of `stepSize=1`.
9073                     As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9074                     Notice that starting from `upper`,
9075                     we only need to move for `windowSize - 1` to the right:
9076 
9077                       - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9078                         rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9079 
9080                       - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9081                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9082 
9083                       - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9084                         rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9085                     */
9086                     immutable rightPos = min(upper + windowSize - 1, len);
9087                 }
9088 
9089                 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9090             }
9091         }
9092         else static if (hasSliceToEnd)
9093         {
9094             // For slicing an infinite chunk, we need to slice the source to the infinite end.
9095             auto opSlice(size_t lower, size_t upper)
9096             {
9097                 assert(lower <= upper, "slide slicing index out of bounds");
9098                 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9099                                     .takeExactly(upper - lower);
9100             }
9101         }
9102 
9103         static if (isInfinite!Source)
9104         {
9105             static if (hasSliceToEnd)
9106             {
9107                 private static struct DollarToken{}
9108                 DollarToken opDollar()
9109                 {
9110                     return DollarToken();
9111                 }
9112                 //Slice to dollar
9113                 typeof(this) opSlice(size_t lower, DollarToken)
9114                 {
9115                     return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9116                 }
9117             }
9118         }
9119         else
9120         {
9121             // Dollar token carries a static type, with no extra information.
9122             // It can lazily transform into source.length on algorithmic
9123             // operations such as : slide[$/2, $-1];
9124             private static struct DollarToken
9125             {
9126                 private size_t _length;
9127                 alias _length this;
9128             }
9129 
9130             DollarToken opDollar()
9131             {
9132                 return DollarToken(this.length);
9133             }
9134 
9135             // Optimized slice overloads optimized for using dollar.
9136             typeof(this) opSlice(DollarToken, DollarToken)
9137             {
9138                 static if (hasSliceToEnd)
9139                 {
9140                     return typeof(this)(source[$ .. $], windowSize, stepSize);
9141                 }
9142                 else
9143                 {
9144                     immutable len = source.length;
9145                     return typeof(this)(source[len .. len], windowSize, stepSize);
9146                 }
9147             }
9148 
9149             // Optimized slice overloads optimized for using dollar.
9150             typeof(this) opSlice(size_t lower, DollarToken)
9151             {
9152                 import std.algorithm.comparison : min;
9153                 assert(lower <= length, "slide slicing index out of bounds");
9154                 lower *= stepSize;
9155                 static if (hasSliceToEnd)
9156                 {
9157                     return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9158                 }
9159                 else
9160                 {
9161                     immutable len = source.length;
9162                     return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9163                 }
9164             }
9165 
9166             // Optimized slice overloads optimized for using dollar.
9167             typeof(this) opSlice(DollarToken, size_t upper)
9168             {
9169                 assert(upper == length, "slide slicing index out of bounds");
9170                 return this[$ .. $];
9171             }
9172         }
9173 
9174         // Bidirectional range primitives
9175         static if (!isInfinite!Source)
9176         {
9177             /**
9178             Bidirectional range primitives. Provided only if both
9179             `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9180              */
9181             @property auto back()
9182             {
9183                 import std.algorithm.comparison : max;
9184 
9185                 assert(!empty, "Attempting to access front on an empty slide");
9186 
9187                 immutable len = source.length;
9188 
9189                 static if (withPartial)
9190                 {
9191                     if (source.length <= windowSize)
9192                         return source[0 .. source.length];
9193 
9194                     if (hasPartialElements)
9195                         return source[numberOfFullFrames * stepSize .. len];
9196                 }
9197 
9198                 // check for underflow
9199                 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9200                 return source[start .. len - gap];
9201             }
9202 
9203             /// Ditto
9204             void popBack()
9205             {
9206                 assert(!empty, "Attempting to call popBack() on an empty slide");
9207 
9208                 // Move by stepSize
9209                 immutable end = source.length > stepSize ? source.length - stepSize : 0;
9210 
9211                 static if (withPartial)
9212                 {
9213                     if (hasShownPartialBefore || source.empty)
9214                     {
9215                         _empty = true;
9216                         return;
9217                     }
9218 
9219                     // pop by stepSize, except for the partial frame at the end
9220                     if (hasPartialElements)
9221                         source = source[0 .. source.length - gap];
9222                     else
9223                         source = source[0 .. end];
9224                 }
9225                 else
9226                 {
9227                     source = source[0 .. end];
9228                 }
9229 
9230                 if (source.length < windowSize)
9231                     _empty = true;
9232             }
9233         }
9234     }
9235 }
9236 
9237 // test @nogc
9238 @safe pure nothrow @nogc unittest
9239 {
9240     import std.algorithm.comparison : equal;
9241 
9242     static immutable res1 = [[0], [1], [2], [3]];
9243     assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9244 
9245     static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9246     assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9247 }
9248 
9249 // test different window sizes
9250 @safe pure nothrow unittest
9251 {
9252     import std.array : array;
9253     import std.algorithm.comparison : equal;
9254 
9255     assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9256     assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9257     assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9258     assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9259     assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9260     assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9261 
9262     assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9263     assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9264     assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9265     assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9266     assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9267     assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9268     assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9269 }
9270 
9271 // test combinations
9272 @safe pure nothrow unittest
9273 {
9274     import std.algorithm.comparison : equal;
9275     import std.typecons : tuple;
9276 
9277     alias t = tuple;
9278     auto list = [
9279         t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9280         t(t(1, 2), [[0], [2], [4]]),
9281         t(t(1, 3), [[0], [3]]),
9282         t(t(1, 4), [[0], [4]]),
9283         t(t(1, 5), [[0], [5]]),
9284         t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9285         t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9286         t(t(2, 3), [[0, 1], [3, 4]]),
9287         t(t(2, 4), [[0, 1], [4, 5]]),
9288         t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9289         t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9290         t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9291         t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9292         t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9293     ];
9294 
9295     static foreach (Partial; [Yes.withPartial, No.withPartial])
9296         foreach (e; list)
9297             assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9298 
9299     auto listSpecial = [
9300         t(t(2, 5), [[0, 1], [5]]),
9301         t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9302         t(t(3, 4), [[0, 1, 2], [4, 5]]),
9303         t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9304         t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9305         t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9306     ];
9307     foreach (e; listSpecial)
9308     {
9309         assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
9310         assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
9311     }
9312 }
9313 
9314 // test emptiness and copyability
9315 @safe pure nothrow unittest
9316 {
9317     import std.algorithm.comparison : equal;
9318     import std.algorithm.iteration : map;
9319 
9320     // check with empty input
9321     int[] d;
9322     assert(d.slide!(Yes.withPartial)(2).empty);
9323     assert(d.slide!(Yes.withPartial)(2, 2).empty);
9324 
9325     // is copyable?
9326     auto e = iota(5).slide!(Yes.withPartial)(2);
9327     e.popFront;
9328     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9329     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9330     assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
9331 }
9332 
9333 // test with strings
9334 @safe pure nothrow unittest
9335 {
9336     import std.algorithm.iteration : each;
9337 
9338     int[dstring] f;
9339     "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
9340     assert(f == ["AGA"d: 2, "GAG"d: 1]);
9341 
9342     int[dstring] g;
9343     "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
9344     assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
9345     g = null;
9346     "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
9347     assert(g == ["ABC"d:1, "DEF"d:1]);
9348 }
9349 
9350 // test with utf8 strings
9351 @safe unittest
9352 {
9353     import std.stdio;
9354     import std.algorithm.comparison : equal;
9355 
9356     assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."]));
9357     assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"]));
9358 
9359     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
9360     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
9361     "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]);
9362     "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]);
9363 }
9364 
9365 // test length
9366 @safe pure nothrow unittest
9367 {
9368     // Slides with fewer elements are empty or 1 for Yes.withPartial
9369     static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
9370     {{
9371         assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
9372         assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
9373         assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
9374     }}
9375 
9376     static immutable list = [
9377     //  iota   slide    expected
9378         [4,    2, 1,     3, 3],
9379         [5,    3, 1,     3, 3],
9380         [7,    2, 2,     4, 3],
9381         [12,   2, 4,     3, 3],
9382         [6,    1, 2,     3, 3],
9383         [6,    2, 4,     2, 2],
9384         [3,    2, 4,     1, 1],
9385         [5,    2, 1,     4, 4],
9386         [7,    2, 2,     4, 3],
9387         [7,    2, 3,     3, 2],
9388         [7,    3, 2,     3, 3],
9389         [7,    3, 3,     3, 2],
9390     ];
9391     foreach (e; list)
9392     {
9393         assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
9394         assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
9395     }
9396 }
9397 
9398 // test index and slicing
9399 @safe pure nothrow unittest
9400 {
9401     import std.algorithm.comparison : equal;
9402     import std.array : array;
9403 
9404     static foreach (Partial; [Yes.withPartial, No.withPartial])
9405     {
9406         foreach (s; [5, 7, 10, 15, 20])
9407         foreach (windowSize; 1 .. 10)
9408         foreach (stepSize; 1 .. 10)
9409         {
9410             auto r = s.iota.slide!Partial(windowSize, stepSize);
9411             auto arr = r.array;
9412             assert(r.length == arr.length);
9413 
9414             // test indexing
9415             foreach (i; 0 .. arr.length)
9416                 assert(r[i] == arr[i]);
9417 
9418             // test slicing
9419             foreach (i; 0 .. arr.length)
9420             {
9421                 foreach (j; i .. arr.length)
9422                     assert(r[i .. j].equal(arr[i .. j]));
9423 
9424                 assert(r[i .. $].equal(arr[i .. $]));
9425             }
9426 
9427             // test opDollar slicing
9428             assert(r[$/2 .. $].equal(arr[$/2 .. $]));
9429             assert(r[$ .. $].empty);
9430             if (arr.empty)
9431             {
9432                 assert(r[$ .. 0].empty);
9433                 assert(r[$/2 .. $].empty);
9434 
9435             }
9436         }
9437     }
9438 }
9439 
9440 // test with infinite ranges
9441 @safe pure nothrow unittest
9442 {
9443     import std.algorithm.comparison : equal;
9444 
9445     static foreach (Partial; [Yes.withPartial, No.withPartial])
9446     {{
9447         // InfiniteRange without RandomAccess
9448         auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
9449         assert(fibs.slide!Partial(2).take(2).equal!equal([[1,  1], [1,  2]]));
9450         assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
9451 
9452         // InfiniteRange with RandomAccess and slicing
9453         auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9454         auto oddsByPairs = odds.slide!Partial(2);
9455         assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
9456         assert(oddsByPairs[1].equal([3, 5]));
9457         assert(oddsByPairs[4].equal([9, 11]));
9458 
9459         static assert(hasSlicing!(typeof(odds)));
9460         assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
9461         assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
9462 
9463         auto oddsWithGaps = odds.slide!Partial(2, 4);
9464         assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
9465         assert(oddsWithGaps[2].equal([17, 19]));
9466         assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
9467         assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
9468     }}
9469 }
9470 
9471 // test reverse
9472 @safe pure nothrow unittest
9473 {
9474     import std.algorithm.comparison : equal;
9475 
9476     static foreach (Partial; [Yes.withPartial, No.withPartial])
9477     {{
9478         foreach (windowSize; 1 .. 15)
9479         foreach (stepSize; 1 .. 15)
9480         {
9481             auto r = 20.iota.slide!Partial(windowSize, stepSize);
9482             auto rArr = r.array.retro;
9483             auto rRetro = r.retro;
9484 
9485             assert(rRetro.length == rArr.length);
9486             assert(rRetro.equal(rArr));
9487             assert(rRetro.array.retro.equal(r));
9488         }
9489     }}
9490 }
9491 
9492 // test with dummy ranges
9493 @safe pure nothrow unittest
9494 {
9495     import std.algorithm.comparison : equal;
9496     import std.internal.test.dummyrange : AllDummyRanges;
9497     import std.meta : Filter;
9498 
9499     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9500     {{
9501         Range r;
9502 
9503         static foreach (Partial; [Yes.withPartial, No.withPartial])
9504         {
9505             assert(r.slide!Partial(1).equal!equal(
9506                 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
9507             ));
9508             assert(r.slide!Partial(2).equal!equal(
9509                 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
9510             ));
9511             assert(r.slide!Partial(3).equal!equal(
9512                 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
9513                 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
9514             ));
9515             assert(r.slide!Partial(6).equal!equal(
9516                 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
9517                 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
9518             ));
9519         }
9520 
9521         // special cases
9522         assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
9523         assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
9524         assert(r.slide!(No.withPartial)(15).empty);
9525         assert(r.slide!(No.withPartial)(15).walkLength == 0);
9526     }}
9527 }
9528 
9529 // test with dummy ranges
9530 @safe pure nothrow unittest
9531 {
9532     import std.algorithm.comparison : equal;
9533     import std.internal.test.dummyrange : AllDummyRanges;
9534     import std.meta : Filter;
9535     import std.typecons : tuple;
9536 
9537     alias t = tuple;
9538     static immutable list = [
9539     // iota   slide    expected
9540         t(6,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
9541         t(6,  t(4, 6), [[1, 2, 3, 4]]),
9542         t(6,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
9543         t(7,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
9544         t(7,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
9545         t(8,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
9546         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]]),
9547         t(8,  t(3, 4), [[1, 2, 3], [5, 6, 7]]),
9548         t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
9549     ];
9550 
9551     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9552     static foreach (Partial; [Yes.withPartial, No.withPartial])
9553     foreach (e; list)
9554         assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
9555 
9556     static immutable listSpecial = [
9557     // iota   slide    expected
9558         t(6,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
9559         t(7,  t(4, 5), [[1, 2, 3, 4], [6, 7]]),
9560         t(7,  t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
9561         t(7,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
9562         t(8,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
9563         t(8,  t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
9564         t(8,  t(3, 6), [[1, 2, 3], [7, 8]]),
9565         t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
9566         t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
9567     ];
9568     static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9569     static foreach (Partial; [Yes.withPartial, No.withPartial])
9570     foreach (e; listSpecial)
9571     {
9572         Range r;
9573         assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
9574         assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
9575     }
9576 }
9577 
9578 // test reverse with dummy ranges
9579 @safe pure nothrow unittest
9580 {
9581     import std.algorithm.comparison : equal;
9582     import std.internal.test.dummyrange : AllDummyRanges;
9583     import std.meta : Filter, templateAnd;
9584     import std.typecons : tuple;
9585     alias t = tuple;
9586 
9587     static immutable list = [
9588     //   slide   expected
9589         t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
9590         t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
9591         t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
9592                  [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
9593         t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
9594         t(2, 4, [[9, 10], [5, 6], [1, 2]]),
9595     ];
9596 
9597     static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
9598     {{
9599         Range r;
9600         static foreach (Partial; [Yes.withPartial, No.withPartial])
9601         {
9602             foreach (e; list)
9603                 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
9604 
9605             // front = back
9606             foreach (windowSize; 1 .. 10)
9607             foreach (stepSize; 1 .. 10)
9608             {
9609                 auto slider = r.slide!Partial(windowSize, stepSize);
9610                 auto sliderRetro = slider.retro.array;
9611                 assert(slider.length == sliderRetro.length);
9612                 assert(sliderRetro.retro.equal!equal(slider));
9613             }
9614         }
9615 
9616         // special cases
9617         assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
9618         assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
9619     }}
9620 }
9621 
9622 // test different sliceable ranges
9623 @safe pure nothrow unittest
9624 {
9625     import std.algorithm.comparison : equal;
9626     import std.internal.test.dummyrange : AllDummyRanges;
9627     import std.meta : AliasSeq;
9628 
9629     struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
9630                                  Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
9631     {
9632         Range arr = 10.iota.array; // similar to DummyRange
9633         @property auto save() { return typeof(this)(arr); }
9634         @property auto front() { return arr[0]; }
9635         void popFront() { arr.popFront(); }
9636         auto opSlice(size_t i, size_t j)
9637         {
9638             // subslices can't be infinite
9639             return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
9640         }
9641 
9642         static if (withInfiniteness)
9643         {
9644             enum empty = false;
9645         }
9646         else
9647         {
9648             @property bool empty() { return arr.empty; }
9649             @property auto length() { return arr.length; }
9650         }
9651 
9652         static if (withOpDollar)
9653         {
9654             static if (withInfiniteness)
9655             {
9656                 struct Dollar {}
9657                 Dollar opDollar() const { return Dollar.init; }
9658 
9659                 // Slice to dollar
9660                 typeof(this) opSlice(size_t lower, Dollar)
9661                 {
9662                     return typeof(this)(arr[lower .. $]);
9663                 }
9664 
9665             }
9666             else
9667             {
9668                 alias opDollar = length;
9669             }
9670         }
9671     }
9672 
9673     import std.meta : Filter,  templateNot;
9674     alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
9675 
9676     static foreach (Partial; [Yes.withPartial, No.withPartial])
9677     {{
9678         static foreach (Range; SliceableDummyRanges)
9679         {{
9680             Range r;
9681             r.reinit;
9682             r.arr[] -= 1; // use a 0-based array (for clarity)
9683 
9684             assert(r.slide!Partial(2)[0].equal([0, 1]));
9685             assert(r.slide!Partial(2)[1].equal([1, 2]));
9686 
9687             // saveable
9688             auto s = r.slide!Partial(2);
9689             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
9690             s.save.popFront;
9691             assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
9692 
9693             assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
9694         }}
9695 
9696         static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
9697         {{
9698             Range r;
9699             r.reinit;
9700             r.arr[] -= 1; // use a 0-based array (for clarity)
9701 
9702             assert(r.slide!(No.withPartial)(6).equal!equal(
9703                 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
9704                 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
9705             ));
9706             assert(r.slide!(No.withPartial)(16).empty);
9707 
9708             assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
9709             assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
9710             assert(r.slide!Partial(2)[$ .. $].empty);
9711 
9712             assert(r.slide!Partial(3).retro.equal!equal(
9713                 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
9714             ));
9715         }}
9716 
9717         alias T = int[];
9718 
9719         // separate checks for infinity
9720         auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
9721         assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
9722         assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
9723 
9724         auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
9725         assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
9726         assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
9727         assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
9728     }}
9729 }
9730 
9731 // https://issues.dlang.org/show_bug.cgi?id=19082
9732 @safe unittest
9733 {
9734     import std.algorithm.comparison : equal;
9735     import std.algorithm.iteration : map;
9736     assert([1].map!(x => x).slide(2).equal!equal([[1]]));
9737 }
9738 
9739 private struct OnlyResult(T, size_t arity)
9740 {
9741     private this(Values...)(return scope auto ref Values values)
9742     {
9743         this.data = [values];
9744         this.backIndex = arity;
9745     }
9746 
9747     bool empty() @property
9748     {
9749         return frontIndex >= backIndex;
9750     }
9751 
9752     T front() @property
9753     {
9754         assert(!empty, "Attempting to fetch the front of an empty Only range");
9755         return data[frontIndex];
9756     }
9757 
9758     void popFront()
9759     {
9760         assert(!empty, "Attempting to popFront an empty Only range");
9761         ++frontIndex;
9762     }
9763 
9764     T back() @property
9765     {
9766         assert(!empty, "Attempting to fetch the back of an empty Only range");
9767         return data[backIndex - 1];
9768     }
9769 
9770     void popBack()
9771     {
9772         assert(!empty, "Attempting to popBack an empty Only range");
9773         --backIndex;
9774     }
9775 
9776     OnlyResult save() @property
9777     {
9778         return this;
9779     }
9780 
9781     size_t length() const @property
9782     {
9783         return backIndex - frontIndex;
9784     }
9785 
9786     alias opDollar = length;
9787 
9788     T opIndex(size_t idx)
9789     {
9790         // when i + idx points to elements popped
9791         // with popBack
9792         assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
9793         return data[frontIndex + idx];
9794     }
9795 
9796     OnlyResult opSlice()
9797     {
9798         return this;
9799     }
9800 
9801     OnlyResult opSlice(size_t from, size_t to)
9802     {
9803         OnlyResult result = this;
9804         result.frontIndex += from;
9805         result.backIndex = this.frontIndex + to;
9806         assert(
9807             from <= to,
9808             "Attempting to slice an Only range with a larger first argument than the second."
9809         );
9810         assert(
9811             to <= length,
9812             "Attempting to slice using an out of bounds index on an Only range"
9813         );
9814         return result;
9815     }
9816 
9817     private size_t frontIndex = 0;
9818     private size_t backIndex = 0;
9819 
9820     // https://issues.dlang.org/show_bug.cgi?id=10643
9821     version (none)
9822     {
9823         import std.traits : hasElaborateAssign;
9824         static if (hasElaborateAssign!T)
9825             private T[arity] data;
9826         else
9827             private T[arity] data = void;
9828     }
9829     else
9830         private T[arity] data;
9831 }
9832 
9833 // Specialize for single-element results
9834 private struct OnlyResult(T, size_t arity : 1)
9835 {
9836     @property T front()
9837     {
9838         assert(!empty, "Attempting to fetch the front of an empty Only range");
9839         return _value;
9840     }
9841     @property T back()
9842     {
9843         assert(!empty, "Attempting to fetch the back of an empty Only range");
9844         return _value;
9845     }
9846     @property bool empty() const { return _empty; }
9847     @property size_t length() const { return !_empty; }
9848     @property auto save() { return this; }
9849     void popFront()
9850     {
9851         assert(!_empty, "Attempting to popFront an empty Only range");
9852         _empty = true;
9853     }
9854     void popBack()
9855     {
9856         assert(!_empty, "Attempting to popBack an empty Only range");
9857         _empty = true;
9858     }
9859     alias opDollar = length;
9860 
9861     private this()(return scope auto ref T value)
9862     {
9863         this._value = value;
9864         this._empty = false;
9865     }
9866 
9867     T opIndex(size_t i)
9868     {
9869         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
9870         return _value;
9871     }
9872 
9873     OnlyResult opSlice()
9874     {
9875         return this;
9876     }
9877 
9878     OnlyResult opSlice(size_t from, size_t to)
9879     {
9880         assert(
9881             from <= to,
9882             "Attempting to slice an Only range with a larger first argument than the second."
9883         );
9884         assert(
9885             to <= length,
9886             "Attempting to slice using an out of bounds index on an Only range"
9887         );
9888         OnlyResult copy = this;
9889         copy._empty = _empty || from == to;
9890         return copy;
9891     }
9892 
9893     private Unqual!T _value;
9894     private bool _empty = true;
9895 }
9896 
9897 // Specialize for the empty range
9898 private struct OnlyResult(T, size_t arity : 0)
9899 {
9900     private static struct EmptyElementType {}
9901 
9902     bool empty() @property { return true; }
9903     size_t length() const @property { return 0; }
9904     alias opDollar = length;
9905     EmptyElementType front() @property { assert(false); }
9906     void popFront() { assert(false); }
9907     EmptyElementType back() @property { assert(false); }
9908     void popBack() { assert(false); }
9909     OnlyResult save() @property { return this; }
9910 
9911     EmptyElementType opIndex(size_t i)
9912     {
9913         assert(false);
9914     }
9915 
9916     OnlyResult opSlice() { return this; }
9917 
9918     OnlyResult opSlice(size_t from, size_t to)
9919     {
9920         assert(from == 0 && to == 0);
9921         return this;
9922     }
9923 }
9924 
9925 /**
9926 Assemble `values` into a range that carries all its
9927 elements in-situ.
9928 
9929 Useful when a single value or multiple disconnected values
9930 must be passed to an algorithm expecting a range, without
9931 having to perform dynamic memory allocation.
9932 
9933 As copying the range means copying all elements, it can be
9934 safely returned from functions. For the same reason, copying
9935 the returned range may be expensive for a large number of arguments.
9936 
9937 Params:
9938     values = the values to assemble together
9939 
9940 Returns:
9941     A `RandomAccessRange` of the assembled values.
9942 
9943 See_Also: $(LREF chain) to chain ranges
9944  */
9945 auto only(Values...)(return scope Values values)
9946 if (!is(CommonType!Values == void) || Values.length == 0)
9947 {
9948     return OnlyResult!(CommonType!Values, Values.length)(values);
9949 }
9950 
9951 ///
9952 @safe unittest
9953 {
9954     import std.algorithm.comparison : equal;
9955     import std.algorithm.iteration : filter, joiner, map;
9956     import std.algorithm.searching : findSplitBefore;
9957     import std.uni : isUpper;
9958 
9959     assert(equal(only('♡'), "♡"));
9960     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
9961 
9962     assert(only("one", "two", "three").joiner(" ").equal("one two three"));
9963 
9964     string title = "The D Programming Language";
9965     assert(title
9966         .filter!isUpper // take the upper case letters
9967         .map!only       // make each letter its own range
9968         .joiner(".")    // join the ranges together lazily
9969         .equal("T.D.P.L"));
9970 }
9971 
9972 @safe unittest
9973 {
9974     // Verify that the same common type and same arity
9975     // results in the same template instantiation
9976     static assert(is(typeof(only(byte.init, int.init)) ==
9977         typeof(only(int.init, byte.init))));
9978 
9979     static assert(is(typeof(only((const(char)[]).init, string.init)) ==
9980         typeof(only((const(char)[]).init, (const(char)[]).init))));
9981 }
9982 
9983 // https://issues.dlang.org/show_bug.cgi?id=20314
9984 @safe unittest
9985 {
9986     import std.algorithm.iteration : joiner;
9987 
9988     const string s = "foo", t = "bar";
9989 
9990     assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
9991 }
9992 
9993 // Tests the zero-element result
9994 @safe unittest
9995 {
9996     import std.algorithm.comparison : equal;
9997 
9998     auto emptyRange = only();
9999 
10000     alias EmptyRange = typeof(emptyRange);
10001     static assert(isInputRange!EmptyRange);
10002     static assert(isForwardRange!EmptyRange);
10003     static assert(isBidirectionalRange!EmptyRange);
10004     static assert(isRandomAccessRange!EmptyRange);
10005     static assert(hasLength!EmptyRange);
10006     static assert(hasSlicing!EmptyRange);
10007 
10008     assert(emptyRange.empty);
10009     assert(emptyRange.length == 0);
10010     assert(emptyRange.equal(emptyRange[]));
10011     assert(emptyRange.equal(emptyRange.save));
10012     assert(emptyRange[0 .. 0].equal(emptyRange));
10013 }
10014 
10015 // Tests the single-element result
10016 @safe unittest
10017 {
10018     import std.algorithm.comparison : equal;
10019     import std.typecons : tuple;
10020     foreach (x; tuple(1, '1', 1.0, "1", [1]))
10021     {
10022         auto a = only(x);
10023         typeof(x)[] e = [];
10024         assert(a.front == x);
10025         assert(a.back == x);
10026         assert(!a.empty);
10027         assert(a.length == 1);
10028         assert(equal(a, a[]));
10029         assert(equal(a, a[0 .. 1]));
10030         assert(equal(a[0 .. 0], e));
10031         assert(equal(a[1 .. 1], e));
10032         assert(a[0] == x);
10033 
10034         auto b = a.save;
10035         assert(equal(a, b));
10036         a.popFront();
10037         assert(a.empty && a.length == 0 && a[].empty);
10038         b.popBack();
10039         assert(b.empty && b.length == 0 && b[].empty);
10040 
10041         alias A = typeof(a);
10042         static assert(isInputRange!A);
10043         static assert(isForwardRange!A);
10044         static assert(isBidirectionalRange!A);
10045         static assert(isRandomAccessRange!A);
10046         static assert(hasLength!A);
10047         static assert(hasSlicing!A);
10048     }
10049 
10050     auto imm = only!(immutable int)(1);
10051     immutable int[] imme = [];
10052     assert(imm.front == 1);
10053     assert(imm.back == 1);
10054     assert(!imm.empty);
10055     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10056     assert(imm.length == 1);
10057     assert(equal(imm, imm[]));
10058     assert(equal(imm, imm[0 .. 1]));
10059     assert(equal(imm[0 .. 0], imme));
10060     assert(equal(imm[1 .. 1], imme));
10061     assert(imm[0] == 1);
10062 }
10063 
10064 // Tests multiple-element results
10065 @safe unittest
10066 {
10067     import std.algorithm.comparison : equal;
10068     import std.algorithm.iteration : joiner;
10069     import std.meta : AliasSeq;
10070     static assert(!__traits(compiles, only(1, "1")));
10071 
10072     auto nums = only!(byte, uint, long)(1, 2, 3);
10073     static assert(is(ElementType!(typeof(nums)) == long));
10074     assert(nums.length == 3);
10075 
10076     foreach (i; 0 .. 3)
10077         assert(nums[i] == i + 1);
10078 
10079     auto saved = nums.save;
10080 
10081     foreach (i; 1 .. 4)
10082     {
10083         assert(nums.front == nums[0]);
10084         assert(nums.front == i);
10085         nums.popFront();
10086         assert(nums.length == 3 - i);
10087     }
10088 
10089     assert(nums.empty);
10090 
10091     assert(saved.equal(only(1, 2, 3)));
10092     assert(saved.equal(saved[]));
10093     assert(saved[0 .. 1].equal(only(1)));
10094     assert(saved[0 .. 2].equal(only(1, 2)));
10095     assert(saved[0 .. 3].equal(saved));
10096     assert(saved[1 .. 3].equal(only(2, 3)));
10097     assert(saved[2 .. 3].equal(only(3)));
10098     assert(saved[0 .. 0].empty);
10099     assert(saved[3 .. 3].empty);
10100 
10101     alias data = AliasSeq!("one", "two", "three", "four");
10102     static joined =
10103         ["one two", "one two three", "one two three four"];
10104     string[] joinedRange = joined;
10105 
10106     static foreach (argCount; 2 .. 5)
10107     {{
10108         auto values = only(data[0 .. argCount]);
10109         alias Values = typeof(values);
10110         static assert(is(ElementType!Values == string));
10111         static assert(isInputRange!Values);
10112         static assert(isForwardRange!Values);
10113         static assert(isBidirectionalRange!Values);
10114         static assert(isRandomAccessRange!Values);
10115         static assert(hasSlicing!Values);
10116         static assert(hasLength!Values);
10117 
10118         assert(values.length == argCount);
10119         assert(values[0 .. $].equal(values[0 .. values.length]));
10120         assert(values.joiner(" ").equal(joinedRange.front));
10121         joinedRange.popFront();
10122     }}
10123 
10124     assert(saved.retro.equal(only(3, 2, 1)));
10125     assert(saved.length == 3);
10126 
10127     assert(saved.back == 3);
10128     saved.popBack();
10129     assert(saved.length == 2);
10130     assert(saved.back == 2);
10131 
10132     assert(saved.front == 1);
10133     saved.popFront();
10134     assert(saved.length == 1);
10135     assert(saved.front == 2);
10136 
10137     saved.popBack();
10138     assert(saved.empty);
10139 
10140     auto imm = only!(immutable int, immutable int)(42, 24);
10141     alias Imm = typeof(imm);
10142     static assert(is(ElementType!Imm == immutable(int)));
10143     assert(!imm.empty);
10144     assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10145     assert(imm.front == 42);
10146     imm.popFront();
10147     assert(imm.front == 24);
10148     imm.popFront();
10149     assert(imm.empty);
10150 
10151     static struct Test { int* a; }
10152     immutable(Test) test;
10153     cast(void) only(test, test); // Works with mutable indirection
10154 }
10155 
10156 /**
10157 Iterate over `range` with an attached index variable.
10158 
10159 Each element is a $(REF Tuple, std,typecons) containing the index
10160 and the element, in that order, where the index member is named `index`
10161 and the element member is named `value`.
10162 
10163 The index starts at `start` and is incremented by one on every iteration.
10164 
10165 Overflow:
10166     If `range` has length, then it is an error to pass a value for `start`
10167     so that `start + range.length` is bigger than `Enumerator.max`, thus
10168     it is ensured that overflow cannot happen.
10169 
10170     If `range` does not have length, and `popFront` is called when
10171     `front.index == Enumerator.max`, the index will overflow and
10172     continue from `Enumerator.min`.
10173 
10174 Params:
10175     range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
10176     start = the number to start the index counter from
10177 
10178 Returns:
10179     At minimum, an input range. All other range primitives are given in the
10180     resulting range if `range` has them. The exceptions are the bidirectional
10181     primitives, which are propagated only if `range` has length.
10182 
10183 Example:
10184 Useful for using `foreach` with an index loop variable:
10185 ----
10186     import std.stdio : stdin, stdout;
10187     import std.range : enumerate;
10188 
10189     foreach (lineNum, line; stdin.byLine().enumerate(1))
10190         stdout.writefln("line #%s: %s", lineNum, line);
10191 ----
10192 */
10193 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
10194 if (isIntegral!Enumerator && isInputRange!Range)
10195 in
10196 {
10197     static if (hasLength!Range)
10198     {
10199         // TODO: core.checkedint supports mixed signedness yet?
10200         import core.checkedint : adds, addu;
10201         import std.conv : ConvException, to;
10202         import std.traits : isSigned, Largest, Signed;
10203 
10204         alias LengthType = typeof(range.length);
10205         bool overflow;
10206         static if (isSigned!Enumerator && isSigned!LengthType)
10207             auto result = adds(start, range.length, overflow);
10208         else static if (isSigned!Enumerator)
10209         {
10210             Largest!(Enumerator, Signed!LengthType) signedLength;
10211             try signedLength = to!(typeof(signedLength))(range.length);
10212             catch (ConvException)
10213                 overflow = true;
10214             catch (Exception)
10215                 assert(false);
10216 
10217             auto result = adds(start, signedLength, overflow);
10218         }
10219         else
10220         {
10221             static if (isSigned!LengthType)
10222                 assert(range.length >= 0);
10223             auto result = addu(start, range.length, overflow);
10224         }
10225 
10226         assert(!overflow && result <= Enumerator.max);
10227     }
10228 }
10229 do
10230 {
10231     // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
10232     static struct Result
10233     {
10234         import std.typecons : Tuple;
10235 
10236         private:
10237         alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
10238         Range range;
10239         Unqual!Enumerator index;
10240 
10241         public:
10242         ElemType front() @property
10243         {
10244             assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
10245             return typeof(return)(index, range.front);
10246         }
10247 
10248         static if (isInfinite!Range)
10249             enum bool empty = false;
10250         else
10251         {
10252             bool empty() @property
10253             {
10254                 return range.empty;
10255             }
10256         }
10257 
10258         void popFront()
10259         {
10260             assert(!range.empty, "Attempting to popFront an empty enumerate");
10261             range.popFront();
10262             ++index; // When !hasLength!Range, overflow is expected
10263         }
10264 
10265         static if (isForwardRange!Range)
10266         {
10267             Result save() @property
10268             {
10269                 return typeof(return)(range.save, index);
10270             }
10271         }
10272 
10273         static if (hasLength!Range)
10274         {
10275             size_t length() @property
10276             {
10277                 return range.length;
10278             }
10279 
10280             alias opDollar = length;
10281 
10282             static if (isBidirectionalRange!Range)
10283             {
10284                 ElemType back() @property
10285                 {
10286                     assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
10287                     return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
10288                 }
10289 
10290                 void popBack()
10291                 {
10292                     assert(!range.empty, "Attempting to popBack an empty enumerate");
10293                     range.popBack();
10294                 }
10295             }
10296         }
10297 
10298         static if (isRandomAccessRange!Range)
10299         {
10300              ElemType opIndex(size_t i)
10301              {
10302                 return typeof(return)(cast(Enumerator)(index + i), range[i]);
10303              }
10304         }
10305 
10306         static if (hasSlicing!Range)
10307         {
10308             static if (hasLength!Range)
10309             {
10310                 Result opSlice(size_t i, size_t j)
10311                 {
10312                     return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
10313                 }
10314             }
10315             else
10316             {
10317                 static struct DollarToken {}
10318                 enum opDollar = DollarToken.init;
10319 
10320                 Result opSlice(size_t i, DollarToken)
10321                 {
10322                     return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
10323                 }
10324 
10325                 auto opSlice(size_t i, size_t j)
10326                 {
10327                     return this[i .. $].takeExactly(j - 1);
10328                 }
10329             }
10330         }
10331     }
10332 
10333     return Result(range, start);
10334 }
10335 
10336 /// Can start enumeration from a negative position:
10337 pure @safe nothrow unittest
10338 {
10339     import std.array : assocArray;
10340     import std.range : enumerate;
10341 
10342     bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
10343     assert(aa[-1]);
10344     assert(aa[0]);
10345     assert(aa[1]);
10346 }
10347 
10348 // Make sure passing qualified types works
10349 pure @safe nothrow unittest
10350 {
10351     char[4] v;
10352     immutable start = 2;
10353     v[2 .. $].enumerate(start);
10354 }
10355 
10356 pure @safe nothrow unittest
10357 {
10358     import std.internal.test.dummyrange : AllDummyRanges;
10359     import std.meta : AliasSeq;
10360     import std.typecons : tuple;
10361 
10362     static struct HasSlicing
10363     {
10364         typeof(this) front() @property { return typeof(this).init; }
10365         bool empty() @property { return true; }
10366         void popFront() {}
10367 
10368         typeof(this) opSlice(size_t, size_t)
10369         {
10370             return typeof(this)();
10371         }
10372     }
10373 
10374     static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
10375     {{
10376         alias R = typeof(enumerate(DummyType.init));
10377         static assert(isInputRange!R);
10378         static assert(isForwardRange!R == isForwardRange!DummyType);
10379         static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
10380         static assert(!hasAssignableElements!R);
10381 
10382         static if (hasLength!DummyType)
10383         {
10384             static assert(hasLength!R);
10385             static assert(isBidirectionalRange!R ==
10386                 isBidirectionalRange!DummyType);
10387         }
10388 
10389         static assert(hasSlicing!R == hasSlicing!DummyType);
10390     }}
10391 
10392     static immutable values = ["zero", "one", "two", "three"];
10393     auto enumerated = values[].enumerate();
10394     assert(!enumerated.empty);
10395     assert(enumerated.front == tuple(0, "zero"));
10396     assert(enumerated.back == tuple(3, "three"));
10397 
10398     typeof(enumerated) saved = enumerated.save;
10399     saved.popFront();
10400     assert(enumerated.front == tuple(0, "zero"));
10401     assert(saved.front == tuple(1, "one"));
10402     assert(saved.length == enumerated.length - 1);
10403     saved.popBack();
10404     assert(enumerated.back == tuple(3, "three"));
10405     assert(saved.back == tuple(2, "two"));
10406     saved.popFront();
10407     assert(saved.front == tuple(2, "two"));
10408     assert(saved.back == tuple(2, "two"));
10409     saved.popFront();
10410     assert(saved.empty);
10411 
10412     size_t control = 0;
10413     foreach (i, v; enumerated)
10414     {
10415         static assert(is(typeof(i) == size_t));
10416         static assert(is(typeof(v) == typeof(values[0])));
10417         assert(i == control);
10418         assert(v == values[i]);
10419         assert(tuple(i, v) == enumerated[i]);
10420         ++control;
10421     }
10422 
10423     assert(enumerated[0 .. $].front == tuple(0, "zero"));
10424     assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
10425 
10426     foreach (i; 0 .. 10)
10427     {
10428         auto shifted = values[0 .. 2].enumerate(i);
10429         assert(shifted.front == tuple(i, "zero"));
10430         assert(shifted[0] == shifted.front);
10431 
10432         auto next = tuple(i + 1, "one");
10433         assert(shifted[1] == next);
10434         shifted.popFront();
10435         assert(shifted.front == next);
10436         shifted.popFront();
10437         assert(shifted.empty);
10438     }
10439 
10440     static foreach (T; AliasSeq!(ubyte, byte, uint, int))
10441     {{
10442         auto inf = 42.repeat().enumerate(T.max);
10443         alias Inf = typeof(inf);
10444         static assert(isInfinite!Inf);
10445         static assert(hasSlicing!Inf);
10446 
10447         // test overflow
10448         assert(inf.front == tuple(T.max, 42));
10449         inf.popFront();
10450         assert(inf.front == tuple(T.min, 42));
10451 
10452         // test slicing
10453         inf = inf[42 .. $];
10454         assert(inf.front == tuple(T.min + 42, 42));
10455         auto window = inf[0 .. 2];
10456         assert(window.length == 1);
10457         assert(window.front == inf.front);
10458         window.popFront();
10459         assert(window.empty);
10460     }}
10461 }
10462 
10463 pure @safe unittest
10464 {
10465     import std.algorithm.comparison : equal;
10466     import std.meta : AliasSeq;
10467     static immutable int[] values = [0, 1, 2, 3, 4];
10468     static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
10469     {{
10470         auto enumerated = values.enumerate!T();
10471         static assert(is(typeof(enumerated.front.index) == T));
10472         assert(enumerated.equal(values[].zip(values)));
10473 
10474         foreach (T i; 0 .. 5)
10475         {
10476             auto subset = values[cast(size_t) i .. $];
10477             auto offsetEnumerated = subset.enumerate(i);
10478             static assert(is(typeof(enumerated.front.index) == T));
10479             assert(offsetEnumerated.equal(subset.zip(subset)));
10480         }
10481     }}
10482 }
10483 
10484 // https://issues.dlang.org/show_bug.cgi?id=10939
10485 version (none)
10486 {
10487     // Re-enable (or remove) if 10939 is resolved.
10488     /+pure+/ @safe unittest // Impure because of std.conv.to
10489     {
10490         import core.exception : RangeError;
10491         import std.exception : assertNotThrown, assertThrown;
10492         import std.meta : AliasSeq;
10493 
10494         static immutable values = [42];
10495 
10496         static struct SignedLengthRange
10497         {
10498             immutable(int)[] _values = values;
10499 
10500             int front() @property { assert(false); }
10501             bool empty() @property { assert(false); }
10502             void popFront() { assert(false); }
10503 
10504             int length() @property
10505             {
10506                 return cast(int)_values.length;
10507             }
10508         }
10509 
10510         SignedLengthRange svalues;
10511         static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
10512         {
10513             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
10514             assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
10515             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
10516 
10517             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
10518             assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
10519             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
10520         }
10521 
10522         static foreach (Enumerator; AliasSeq!(byte, short, int))
10523         {
10524             assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
10525         }
10526 
10527         assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
10528     }
10529 }
10530 
10531 /**
10532   Returns true if `fn` accepts variables of type T1 and T2 in any order.
10533   The following code should compile:
10534   ---
10535   (ref T1 a, ref T2 b)
10536   {
10537     fn(a, b);
10538     fn(b, a);
10539   }
10540   ---
10541 */
10542 template isTwoWayCompatible(alias fn, T1, T2)
10543 {
10544     enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
10545         {
10546             cast(void) fn(a, b);
10547             cast(void) fn(b, a);
10548         }
10549     ));
10550 }
10551 
10552 ///
10553 @safe unittest
10554 {
10555     void func1(int a, int b);
10556     void func2(int a, float b);
10557 
10558     static assert(isTwoWayCompatible!(func1, int, int));
10559     static assert(isTwoWayCompatible!(func1, short, int));
10560     static assert(!isTwoWayCompatible!(func2, int, float));
10561 
10562     void func3(ref int a, ref int b);
10563     static assert( isTwoWayCompatible!(func3, int, int));
10564     static assert(!isTwoWayCompatible!(func3, short, int));
10565 }
10566 
10567 
10568 /**
10569    Policy used with the searching primitives `lowerBound`, $(D
10570    upperBound), and `equalRange` of $(LREF SortedRange) below.
10571  */
10572 enum SearchPolicy
10573 {
10574     /**
10575        Searches in a linear fashion.
10576     */
10577     linear,
10578 
10579     /**
10580        Searches with a step that is grows linearly (1, 2, 3,...)
10581        leading to a quadratic search schedule (indexes tried are 0, 1,
10582        3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
10583        the remaining interval is searched using binary search. The
10584        search is completed in $(BIGOH sqrt(n)) time. Use it when you
10585        are reasonably confident that the value is around the beginning
10586        of the range.
10587     */
10588     trot,
10589 
10590     /**
10591        Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
10592        galloping search algorithm), i.e. searches
10593        with a step that doubles every time, (1, 2, 4, 8, ...)  leading
10594        to an exponential search schedule (indexes tried are 0, 1, 3,
10595        7, 15, 31, 63,...) Once the search overshoots its target, the
10596        remaining interval is searched using binary search. A value is
10597        found in $(BIGOH log(n)) time.
10598     */
10599     gallop,
10600 
10601     /**
10602        Searches using a classic interval halving policy. The search
10603        starts in the middle of the range, and each search step cuts
10604        the range in half. This policy finds a value in $(BIGOH log(n))
10605        time but is less cache friendly than `gallop` for large
10606        ranges. The `binarySearch` policy is used as the last step
10607        of `trot`, `gallop`, `trotBackwards`, and $(D
10608        gallopBackwards) strategies.
10609     */
10610     binarySearch,
10611 
10612     /**
10613        Similar to `trot` but starts backwards. Use it when
10614        confident that the value is around the end of the range.
10615     */
10616     trotBackwards,
10617 
10618     /**
10619        Similar to `gallop` but starts backwards. Use it when
10620        confident that the value is around the end of the range.
10621     */
10622     gallopBackwards
10623 }
10624 
10625 ///
10626 @safe unittest
10627 {
10628     import std.algorithm.comparison : equal;
10629 
10630     auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
10631     auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
10632     assert(p1.equal([4, 5, 6, 7, 8, 9]));
10633 
10634     auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
10635     assert(p2.equal([0, 1, 2, 3]));
10636 }
10637 
10638 /**
10639    Options for $(LREF SortedRange) ranges (below).
10640 */
10641 enum SortedRangeOptions
10642 {
10643    /**
10644       Assume, that the range is sorted without checking.
10645    */
10646    assumeSorted,
10647 
10648    /**
10649       All elements of the range are checked to be sorted.
10650       The check is performed in O(n) time.
10651    */
10652    checkStrictly,
10653 
10654    /**
10655       Some elements of the range are checked to be sorted.
10656       For ranges with random order, this will almost surely
10657       detect, that it is not sorted. For almost sorted ranges
10658       it's more likely to fail. The checked elements are choosen
10659       in a deterministic manner, which makes this check reproducable.
10660       The check is performed in O(log(n)) time.
10661    */
10662    checkRoughly,
10663 }
10664 
10665 ///
10666 @safe pure unittest
10667 {
10668     // create a SortedRange, that's checked strictly
10669     SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
10670 }
10671 
10672 /**
10673    Represents a sorted range. In addition to the regular range
10674    primitives, supports additional operations that take advantage of the
10675    ordering, such as merge and binary search. To obtain a $(D
10676    SortedRange) from an unsorted range `r`, use
10677    $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
10678    corresponding `SortedRange`. To construct a `SortedRange` from a range
10679    `r` that is known to be already sorted, use $(LREF assumeSorted).
10680 
10681    Params:
10682        pred: The predicate used to define the sortedness
10683        opt: Controls how strongly the range is checked for sortedness.
10684             Will only be used for `RandomAccessRanges`.
10685             Will not be used in CTFE.
10686 */
10687 struct SortedRange(Range, alias pred = "a < b",
10688     SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
10689 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
10690 {
10691     import std.functional : binaryFun;
10692 
10693     private alias predFun = binaryFun!pred;
10694     private bool geq(L, R)(L lhs, R rhs)
10695     {
10696         return !predFun(lhs, rhs);
10697     }
10698     private bool gt(L, R)(L lhs, R rhs)
10699     {
10700         return predFun(rhs, lhs);
10701     }
10702     private Range _input;
10703 
10704     // Undocummented because a clearer way to invoke is by calling
10705     // assumeSorted.
10706     this(Range input)
10707     {
10708         static if (opt == SortedRangeOptions.checkRoughly)
10709         {
10710             roughlyVerifySorted(input);
10711         }
10712         static if (opt == SortedRangeOptions.checkStrictly)
10713         {
10714             strictlyVerifySorted(input);
10715         }
10716         this._input = input;
10717     }
10718 
10719     // Assertion only.
10720     static if (opt == SortedRangeOptions.checkRoughly)
10721     private void roughlyVerifySorted(Range r)
10722     {
10723         if (!__ctfe)
10724         {
10725             static if (isRandomAccessRange!Range && hasLength!Range)
10726             {
10727                 import core.bitop : bsr;
10728                 import std.algorithm.sorting : isSorted;
10729                 import std.exception : enforce;
10730 
10731                 // Check the sortedness of the input
10732                 if (r.length < 2) return;
10733 
10734                 immutable size_t msb = bsr(r.length) + 1;
10735                 assert(msb > 0 && msb <= r.length);
10736                 immutable step = r.length / msb;
10737                 auto st = stride(r, step);
10738 
10739                 enforce(isSorted!pred(st), "Range is not sorted");
10740             }
10741         }
10742     }
10743 
10744     // Assertion only.
10745     static if (opt == SortedRangeOptions.checkStrictly)
10746     private void strictlyVerifySorted(Range r)
10747     {
10748         if (!__ctfe)
10749         {
10750             static if (isRandomAccessRange!Range && hasLength!Range)
10751             {
10752                 import std.algorithm.sorting : isSorted;
10753                 import std.exception : enforce;
10754 
10755                 enforce(isSorted!pred(r), "Range is not sorted");
10756             }
10757         }
10758     }
10759 
10760     /// Range primitives.
10761     @property bool empty()             //const
10762     {
10763         return this._input.empty;
10764     }
10765 
10766     /// Ditto
10767     static if (isForwardRange!Range)
10768     @property auto save()
10769     {
10770         // Avoid the constructor
10771         typeof(this) result = this;
10772         result._input = _input.save;
10773         return result;
10774     }
10775 
10776     /// Ditto
10777     @property auto ref front()
10778     {
10779         return _input.front;
10780     }
10781 
10782     /// Ditto
10783     void popFront()
10784     {
10785         _input.popFront();
10786     }
10787 
10788     /// Ditto
10789     static if (isBidirectionalRange!Range)
10790     {
10791         @property auto ref back()
10792         {
10793             return _input.back;
10794         }
10795 
10796         /// Ditto
10797         void popBack()
10798         {
10799             _input.popBack();
10800         }
10801     }
10802 
10803     /// Ditto
10804     static if (isRandomAccessRange!Range)
10805         auto ref opIndex(size_t i)
10806         {
10807             return _input[i];
10808         }
10809 
10810     /// Ditto
10811     static if (hasSlicing!Range)
10812         auto opSlice(size_t a, size_t b) return scope
10813         {
10814             assert(
10815                 a <= b,
10816                 "Attempting to slice a SortedRange with a larger first argument than the second."
10817             );
10818             typeof(this) result = this;
10819             result._input = _input[a .. b];// skip checking
10820             return result;
10821         }
10822 
10823     /// Ditto
10824     static if (hasLength!Range)
10825     {
10826         @property size_t length()          //const
10827         {
10828             return _input.length;
10829         }
10830         alias opDollar = length;
10831     }
10832 
10833 /**
10834    Releases the controlled range and returns it.
10835 */
10836     auto release()
10837     {
10838         import std.algorithm.mutation : move;
10839         return move(_input);
10840     }
10841 
10842     // Assuming a predicate "test" that returns 0 for a left portion
10843     // of the range and then 1 for the rest, returns the index at
10844     // which the first 1 appears. Used internally by the search routines.
10845     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
10846     if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
10847     {
10848         size_t first = 0, count = _input.length;
10849         while (count > 0)
10850         {
10851             immutable step = count / 2, it = first + step;
10852             if (!test(_input[it], v))
10853             {
10854                 first = it + 1;
10855                 count -= step + 1;
10856             }
10857             else
10858             {
10859                 count = step;
10860             }
10861         }
10862         return first;
10863     }
10864 
10865     // Specialization for trot and gallop
10866     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
10867     if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
10868         && isRandomAccessRange!Range)
10869     {
10870         if (empty || test(front, v)) return 0;
10871         immutable count = length;
10872         if (count == 1) return 1;
10873         size_t below = 0, above = 1, step = 2;
10874         while (!test(_input[above], v))
10875         {
10876             // Still too small, update below and increase gait
10877             below = above;
10878             immutable next = above + step;
10879             if (next >= count)
10880             {
10881                 // Overshot - the next step took us beyond the end. So
10882                 // now adjust next and simply exit the loop to do the
10883                 // binary search thingie.
10884                 above = count;
10885                 break;
10886             }
10887             // Still in business, increase step and continue
10888             above = next;
10889             static if (sp == SearchPolicy.trot)
10890                 ++step;
10891             else
10892                 step <<= 1;
10893         }
10894         return below + this[below .. above].getTransitionIndex!(
10895             SearchPolicy.binarySearch, test, V)(v);
10896     }
10897 
10898     // Specialization for trotBackwards and gallopBackwards
10899     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
10900     if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
10901         && isRandomAccessRange!Range)
10902     {
10903         immutable count = length;
10904         if (empty || !test(back, v)) return count;
10905         if (count == 1) return 0;
10906         size_t below = count - 2, above = count - 1, step = 2;
10907         while (test(_input[below], v))
10908         {
10909             // Still too large, update above and increase gait
10910             above = below;
10911             if (below < step)
10912             {
10913                 // Overshot - the next step took us beyond the end. So
10914                 // now adjust next and simply fall through to do the
10915                 // binary search thingie.
10916                 below = 0;
10917                 break;
10918             }
10919             // Still in business, increase step and continue
10920             below -= step;
10921             static if (sp == SearchPolicy.trot)
10922                 ++step;
10923             else
10924                 step <<= 1;
10925         }
10926         return below + this[below .. above].getTransitionIndex!(
10927             SearchPolicy.binarySearch, test, V)(v);
10928     }
10929 
10930 // lowerBound
10931 /**
10932    This function uses a search with policy `sp` to find the
10933    largest left subrange on which $(D pred(x, value)) is `true` for
10934    all `x` (e.g., if `pred` is "less than", returns the portion of
10935    the range with elements strictly smaller than `value`). The search
10936    schedule and its complexity are documented in
10937    $(LREF SearchPolicy).
10938 */
10939     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
10940     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
10941          && hasSlicing!Range)
10942     {
10943         return this[0 .. getTransitionIndex!(sp, geq)(value)];
10944     }
10945 
10946     ///
10947     static if (is(Range : int[]))
10948     @safe unittest
10949     {
10950         import std.algorithm.comparison : equal;
10951         auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
10952         auto p = a.lowerBound(4);
10953         assert(equal(p, [ 0, 1, 2, 3 ]));
10954     }
10955 
10956 // upperBound
10957 /**
10958 This function searches with policy `sp` to find the largest right
10959 subrange on which $(D pred(value, x)) is `true` for all `x`
10960 (e.g., if `pred` is "less than", returns the portion of the range
10961 with elements strictly greater than `value`). The search schedule
10962 and its complexity are documented in $(LREF SearchPolicy).
10963 
10964 For ranges that do not offer random access, `SearchPolicy.linear`
10965 is the only policy allowed (and it must be specified explicitly lest it exposes
10966 user code to unexpected inefficiencies). For random-access searches, all
10967 policies are allowed, and `SearchPolicy.binarySearch` is the default.
10968 */
10969     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
10970     if (isTwoWayCompatible!(predFun, ElementType!Range, V))
10971     {
10972         static assert(hasSlicing!Range || sp == SearchPolicy.linear,
10973             "Specify SearchPolicy.linear explicitly for "
10974             ~ typeof(this).stringof);
10975         static if (sp == SearchPolicy.linear)
10976         {
10977             for (; !_input.empty && !predFun(value, _input.front);
10978                  _input.popFront())
10979             {
10980             }
10981             return this;
10982         }
10983         else
10984         {
10985             return this[getTransitionIndex!(sp, gt)(value) .. length];
10986         }
10987     }
10988 
10989     ///
10990     static if (is(Range : int[]))
10991     @safe unittest
10992     {
10993         import std.algorithm.comparison : equal;
10994         auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
10995         auto p = a.upperBound(3);
10996         assert(equal(p, [4, 4, 5, 6]));
10997     }
10998 
10999 
11000 // equalRange
11001 /**
11002    Returns the subrange containing all elements `e` for which both $(D
11003    pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11004    if `pred` is "less than", returns the portion of the range with
11005    elements equal to `value`). Uses a classic binary search with
11006    interval halving until it finds a value that satisfies the condition,
11007    then uses `SearchPolicy.gallopBackwards` to find the left boundary
11008    and `SearchPolicy.gallop` to find the right boundary. These
11009    policies are justified by the fact that the two boundaries are likely
11010    to be near the first found value (i.e., equal ranges are relatively
11011    small). Completes the entire search in $(BIGOH log(n)) time.
11012 */
11013     auto equalRange(V)(V value)
11014     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11015         && isRandomAccessRange!Range)
11016     {
11017         size_t first = 0, count = _input.length;
11018         while (count > 0)
11019         {
11020             immutable step = count / 2;
11021             auto it = first + step;
11022             if (predFun(_input[it], value))
11023             {
11024                 // Less than value, bump left bound up
11025                 first = it + 1;
11026                 count -= step + 1;
11027             }
11028             else if (predFun(value, _input[it]))
11029             {
11030                 // Greater than value, chop count
11031                 count = step;
11032             }
11033             else
11034             {
11035                 // Equal to value, do binary searches in the
11036                 // leftover portions
11037                 // Gallop towards the left end as it's likely nearby
11038                 immutable left = first
11039                     + this[first .. it]
11040                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11041                 first += count;
11042                 // Gallop towards the right end as it's likely nearby
11043                 immutable right = first
11044                     - this[it + 1 .. first]
11045                     .upperBound!(SearchPolicy.gallop)(value).length;
11046                 return this[left .. right];
11047             }
11048         }
11049         return this.init;
11050     }
11051 
11052     ///
11053     static if (is(Range : int[]))
11054     @safe unittest
11055     {
11056         import std.algorithm.comparison : equal;
11057         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11058         auto r = a.assumeSorted.equalRange(3);
11059         assert(equal(r, [ 3, 3, 3 ]));
11060     }
11061 
11062 // trisect
11063 /**
11064 Returns a tuple `r` such that `r[0]` is the same as the result
11065 of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11066 equalRange(value)), and `r[2]` is the same as the result of $(D
11067 upperBound(value)). The call is faster than computing all three
11068 separately. Uses a search schedule similar to $(D
11069 equalRange). Completes the entire search in $(BIGOH log(n)) time.
11070 */
11071     auto trisect(V)(V value)
11072     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11073         && isRandomAccessRange!Range && hasLength!Range)
11074     {
11075         import std.typecons : tuple;
11076         size_t first = 0, count = _input.length;
11077         while (count > 0)
11078         {
11079             immutable step = count / 2;
11080             auto it = first + step;
11081             if (predFun(_input[it], value))
11082             {
11083                 // Less than value, bump left bound up
11084                 first = it + 1;
11085                 count -= step + 1;
11086             }
11087             else if (predFun(value, _input[it]))
11088             {
11089                 // Greater than value, chop count
11090                 count = step;
11091             }
11092             else
11093             {
11094                 // Equal to value, do binary searches in the
11095                 // leftover portions
11096                 // Gallop towards the left end as it's likely nearby
11097                 immutable left = first
11098                     + this[first .. it]
11099                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11100                 first += count;
11101                 // Gallop towards the right end as it's likely nearby
11102                 immutable right = first
11103                     - this[it + 1 .. first]
11104                     .upperBound!(SearchPolicy.gallop)(value).length;
11105                 return tuple(this[0 .. left], this[left .. right],
11106                         this[right .. length]);
11107             }
11108         }
11109         // No equal element was found
11110         return tuple(this[0 .. first], this.init, this[first .. length]);
11111     }
11112 
11113     ///
11114     static if (is(Range : int[]))
11115     @safe unittest
11116     {
11117         import std.algorithm.comparison : equal;
11118         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11119         auto r = assumeSorted(a).trisect(3);
11120         assert(equal(r[0], [ 1, 2 ]));
11121         assert(equal(r[1], [ 3, 3, 3 ]));
11122         assert(equal(r[2], [ 4, 4, 5, 6 ]));
11123     }
11124 
11125 // contains
11126 /**
11127 Returns `true` if and only if `value` can be found in $(D
11128 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
11129 evaluations of `pred`.
11130  */
11131 
11132     bool contains(V)(V value)
11133     if (isRandomAccessRange!Range)
11134     {
11135         if (empty) return false;
11136         immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
11137         if (i >= length) return false;
11138         return !predFun(value, _input[i]);
11139     }
11140 
11141 /**
11142 Like `contains`, but the value is specified before the range.
11143 */
11144     bool opBinaryRight(string op, V)(V value)
11145     if (op == "in" && isRandomAccessRange!Range)
11146     {
11147         return contains(value);
11148     }
11149 
11150 // groupBy
11151 /**
11152 Returns a range of subranges of elements that are equivalent according to the
11153 sorting relation.
11154  */
11155     auto groupBy()()
11156     {
11157         import std.algorithm.iteration : chunkBy;
11158         return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
11159     }
11160 }
11161 
11162 /// ditto
11163 template SortedRange(Range, alias pred = "a < b",
11164                      SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11165 if (isInstanceOf!(SortedRange, Range))
11166 {
11167     // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
11168     alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
11169 }
11170 
11171 ///
11172 @safe unittest
11173 {
11174     import std.algorithm.sorting : sort;
11175     auto a = [ 1, 2, 3, 42, 52, 64 ];
11176     auto r = assumeSorted(a);
11177     assert(r.contains(3));
11178     assert(!(32 in r));
11179     auto r1 = sort!"a > b"(a);
11180     assert(3 in r1);
11181     assert(!r1.contains(32));
11182     assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
11183 }
11184 
11185 /**
11186 `SortedRange` could accept ranges weaker than random-access, but it
11187 is unable to provide interesting functionality for them. Therefore,
11188 `SortedRange` is currently restricted to random-access ranges.
11189 
11190 No copy of the original range is ever made. If the underlying range is
11191 changed concurrently with its corresponding `SortedRange` in ways
11192 that break its sorted-ness, `SortedRange` will work erratically.
11193 */
11194 @safe unittest
11195 {
11196     import std.algorithm.mutation : swap;
11197     auto a = [ 1, 2, 3, 42, 52, 64 ];
11198     auto r = assumeSorted(a);
11199     assert(r.contains(42));
11200     swap(a[3], a[5]);         // illegal to break sortedness of original range
11201     assert(!r.contains(42));  // passes although it shouldn't
11202 }
11203 
11204 @safe unittest
11205 {
11206     import std.exception : assertThrown, assertNotThrown;
11207 
11208     assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
11209     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
11210 
11211     // these two checks are implementation depended
11212     assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
11213     assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
11214 }
11215 
11216 @safe unittest
11217 {
11218     import std.algorithm.comparison : equal;
11219 
11220     auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
11221     auto r = assumeSorted(a).trisect(30);
11222     assert(equal(r[0], [ 10, 20 ]));
11223     assert(equal(r[1], [ 30, 30, 30 ]));
11224     assert(equal(r[2], [ 40, 40, 50, 60 ]));
11225 
11226     r = assumeSorted(a).trisect(35);
11227     assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
11228     assert(r[1].empty);
11229     assert(equal(r[2], [ 40, 40, 50, 60 ]));
11230 }
11231 
11232 @safe unittest
11233 {
11234     import std.algorithm.comparison : equal;
11235     auto a = [ "A", "AG", "B", "E", "F" ];
11236     auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
11237     assert(equal(r[0], [ "A", "AG" ]));
11238     assert(equal(r[1], [ "B" ]));
11239     assert(equal(r[2], [ "E", "F" ]));
11240     r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
11241     assert(r[0].empty);
11242     assert(equal(r[1], [ "A" ]));
11243     assert(equal(r[2], [ "AG", "B", "E", "F" ]));
11244 }
11245 
11246 @safe unittest
11247 {
11248     import std.algorithm.comparison : equal;
11249     static void test(SearchPolicy pol)()
11250     {
11251         auto a = [ 1, 2, 3, 42, 52, 64 ];
11252         auto r = assumeSorted(a);
11253         assert(equal(r.lowerBound(42), [1, 2, 3]));
11254 
11255         assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
11256         assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
11257         assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
11258         assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
11259         assert(equal(r.lowerBound!(pol)(3), [1, 2]));
11260         assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
11261         assert(equal(r.lowerBound!(pol)(420), a));
11262         assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
11263 
11264         assert(equal(r.upperBound!(pol)(42), [52, 64]));
11265         assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
11266         assert(equal(r.upperBound!(pol)(43), [52, 64]));
11267         assert(equal(r.upperBound!(pol)(51), [52, 64]));
11268         assert(equal(r.upperBound!(pol)(53), [64]));
11269         assert(equal(r.upperBound!(pol)(55), [64]));
11270         assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
11271         assert(equal(r.upperBound!(pol)(0), a));
11272     }
11273 
11274     test!(SearchPolicy.trot)();
11275     test!(SearchPolicy.gallop)();
11276     test!(SearchPolicy.trotBackwards)();
11277     test!(SearchPolicy.gallopBackwards)();
11278     test!(SearchPolicy.binarySearch)();
11279 }
11280 
11281 @safe unittest
11282 {
11283     // Check for small arrays
11284     int[] a;
11285     auto r = assumeSorted(a);
11286     a = [ 1 ];
11287     r = assumeSorted(a);
11288     a = [ 1, 2 ];
11289     r = assumeSorted(a);
11290     a = [ 1, 2, 3 ];
11291     r = assumeSorted(a);
11292 }
11293 
11294 @safe unittest
11295 {
11296     import std.algorithm.mutation : swap;
11297     auto a = [ 1, 2, 3, 42, 52, 64 ];
11298     auto r = assumeSorted(a);
11299     assert(r.contains(42));
11300     swap(a[3], a[5]);                  // illegal to break sortedness of original range
11301     assert(!r.contains(42));            // passes although it shouldn't
11302 }
11303 
11304 @betterC @nogc nothrow @safe unittest
11305 {
11306     static immutable(int)[] arr = [ 1, 2, 3 ];
11307     auto s = assumeSorted(arr);
11308 }
11309 
11310 @system unittest
11311 {
11312     import std.algorithm.comparison : equal;
11313     int[] arr = [100, 101, 102, 200, 201, 300];
11314     auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
11315     assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
11316 }
11317 
11318 // Test on an input range
11319 @system unittest
11320 {
11321     import std.conv : text;
11322     import std.file : exists, remove, tempDir;
11323     import std.path : buildPath;
11324     import std.stdio : File;
11325     import std.uuid : randomUUID;
11326     auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
11327                           "." ~ randomUUID().toString());
11328     auto f = File(name, "w");
11329     scope(exit) if (exists(name)) remove(name);
11330     // write a sorted range of lines to the file
11331     f.write("abc\ndef\nghi\njkl");
11332     f.close();
11333     f.open(name, "r");
11334     auto r = assumeSorted(f.byLine());
11335     auto r1 = r.upperBound!(SearchPolicy.linear)("def");
11336     assert(r1.front == "ghi", r1.front);
11337     f.close();
11338 }
11339 
11340 // https://issues.dlang.org/show_bug.cgi?id=19337
11341 @safe unittest
11342 {
11343     import std.algorithm.sorting : sort;
11344     auto a = [ 1, 2, 3, 42, 52, 64 ];
11345     a.sort.sort!"a > b";
11346 }
11347 
11348 /**
11349 Assumes `r` is sorted by predicate `pred` and returns the
11350 corresponding $(D SortedRange!(pred, R)) having `r` as support.
11351 To check for sorted-ness at
11352 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
11353  */
11354 auto assumeSorted(alias pred = "a < b", R)(R r)
11355 if (isInputRange!(Unqual!R))
11356 {
11357     // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
11358     static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
11359     {
11360         static if (isInputRange!R && __traits(isSame, pred, RPred))
11361             // If the predicate is the same and we don't need to cast away
11362             // constness for the result to be an input range.
11363             return r;
11364         else
11365             return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
11366     }
11367     else
11368     {
11369         return SortedRange!(Unqual!R, pred)(r);
11370     }
11371 }
11372 
11373 ///
11374 @safe unittest
11375 {
11376     import std.algorithm.comparison : equal;
11377 
11378     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
11379     auto p = assumeSorted(a);
11380 
11381     assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
11382     assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
11383     assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
11384     assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
11385 }
11386 
11387 @safe unittest
11388 {
11389     import std.algorithm.comparison : equal;
11390     static assert(isRandomAccessRange!(SortedRange!(int[])));
11391     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11392     auto p = assumeSorted(a).upperBound(3);
11393     assert(equal(p, [4, 4, 5, 6 ]));
11394     p = assumeSorted(a).upperBound(4.2);
11395     assert(equal(p, [ 5, 6 ]));
11396 
11397     // https://issues.dlang.org/show_bug.cgi?id=18933
11398     // don't create senselessly nested SortedRange types.
11399     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
11400     assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
11401 }
11402 
11403 @safe unittest
11404 {
11405     import std.algorithm.comparison : equal;
11406     import std.conv : text;
11407 
11408     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11409     auto p = assumeSorted(a).equalRange(3);
11410     assert(equal(p, [ 3, 3, 3 ]), text(p));
11411     p = assumeSorted(a).equalRange(4);
11412     assert(equal(p, [ 4, 4 ]), text(p));
11413     p = assumeSorted(a).equalRange(2);
11414     assert(equal(p, [ 2 ]));
11415     p = assumeSorted(a).equalRange(0);
11416     assert(p.empty);
11417     p = assumeSorted(a).equalRange(7);
11418     assert(p.empty);
11419     p = assumeSorted(a).equalRange(3.0);
11420     assert(equal(p, [ 3, 3, 3]));
11421 }
11422 
11423 @safe unittest
11424 {
11425     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11426     if (a.length)
11427     {
11428         auto b = a[a.length / 2];
11429         //auto r = sort(a);
11430         //assert(r.contains(b));
11431     }
11432 }
11433 
11434 @safe unittest
11435 {
11436     auto a = [ 5, 7, 34, 345, 677 ];
11437     auto r = assumeSorted(a);
11438     a = null;
11439     r = assumeSorted(a);
11440     a = [ 1 ];
11441     r = assumeSorted(a);
11442 }
11443 
11444 // https://issues.dlang.org/show_bug.cgi?id=15003
11445 @nogc @safe unittest
11446 {
11447     static immutable a = [1, 2, 3, 4];
11448     auto r = a.assumeSorted;
11449 }
11450 
11451 /++
11452     Wrapper which effectively makes it possible to pass a range by reference.
11453     Both the original range and the RefRange will always have the exact same
11454     elements. Any operation done on one will affect the other. So, for instance,
11455     if it's passed to a function which would implicitly copy the original range
11456     if it were passed to it, the original range is $(I not) copied but is
11457     consumed as if it were a reference type.
11458 
11459     Note:
11460         `save` works as normal and operates on a new range, so if
11461         `save` is ever called on the `RefRange`, then no operations on the
11462         saved range will affect the original.
11463 
11464     Params:
11465         range = the range to construct the `RefRange` from
11466 
11467     Returns:
11468         A `RefRange`. If the given range is a class type
11469         (and thus is already a reference type), then the original
11470         range is returned rather than a `RefRange`.
11471   +/
11472 struct RefRange(R)
11473 if (isInputRange!R)
11474 {
11475 public:
11476 
11477     /++ +/
11478     this(R* range) @safe pure nothrow
11479     {
11480         _range = range;
11481     }
11482 
11483 
11484     /++
11485         This does not assign the pointer of `rhs` to this `RefRange`.
11486         Rather it assigns the range pointed to by `rhs` to the range pointed
11487         to by this `RefRange`. This is because $(I any) operation on a
11488         `RefRange` is the same is if it occurred to the original range. The
11489         one exception is when a `RefRange` is assigned `null` either
11490         directly or because `rhs` is `null`. In that case, `RefRange`
11491         no longer refers to the original range but is `null`.
11492       +/
11493     auto opAssign(RefRange rhs)
11494     {
11495         if (_range && rhs._range)
11496             *_range = *rhs._range;
11497         else
11498             _range = rhs._range;
11499 
11500         return this;
11501     }
11502 
11503     /++ +/
11504     void opAssign(typeof(null) rhs)
11505     {
11506         _range = null;
11507     }
11508 
11509 
11510     /++
11511         A pointer to the wrapped range.
11512       +/
11513     @property inout(R*) ptr() @safe inout pure nothrow
11514     {
11515         return _range;
11516     }
11517 
11518 
11519     version (StdDdoc)
11520     {
11521         /++ +/
11522         @property auto front() {assert(0);}
11523         /++ Ditto +/
11524         @property auto front() const {assert(0);}
11525         /++ Ditto +/
11526         @property auto front(ElementType!R value) {assert(0);}
11527     }
11528     else
11529     {
11530         @property auto front()
11531         {
11532             return (*_range).front;
11533         }
11534 
11535         static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
11536         {
11537             return (*_range).front;
11538         }
11539 
11540         static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
11541         {
11542             return (*_range).front = value;
11543         }
11544     }
11545 
11546 
11547     version (StdDdoc)
11548     {
11549         @property bool empty(); ///
11550         @property bool empty() const; ///Ditto
11551     }
11552     else static if (isInfinite!R)
11553         enum empty = false;
11554     else
11555     {
11556         @property bool empty()
11557         {
11558             return (*_range).empty;
11559         }
11560 
11561         static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
11562         {
11563             return (*_range).empty;
11564         }
11565     }
11566 
11567 
11568     /++ +/
11569     void popFront()
11570     {
11571         return (*_range).popFront();
11572     }
11573 
11574 
11575     version (StdDdoc)
11576     {
11577         /++
11578             Only defined if `isForwardRange!R` is `true`.
11579           +/
11580         @property auto save() {assert(0);}
11581         /++ Ditto +/
11582         @property auto save() const {assert(0);}
11583         /++ Ditto +/
11584         auto opSlice() {assert(0);}
11585         /++ Ditto +/
11586         auto opSlice() const {assert(0);}
11587     }
11588     else static if (isForwardRange!R)
11589     {
11590         import std.traits : isSafe;
11591         private alias S = typeof((*_range).save);
11592 
11593         static if (is(typeof((*cast(const R*)_range).save)))
11594             private alias CS = typeof((*cast(const R*)_range).save);
11595 
11596         static if (isSafe!((R* r) => (*r).save))
11597         {
11598             @property RefRange!S save() @trusted
11599             {
11600                 mixin(_genSave());
11601             }
11602 
11603             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
11604             {
11605                 mixin(_genSave());
11606             }
11607         }
11608         else
11609         {
11610             @property RefRange!S save()
11611             {
11612                 mixin(_genSave());
11613             }
11614 
11615             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
11616             {
11617                 mixin(_genSave());
11618             }
11619         }
11620 
11621         auto opSlice()()
11622         {
11623             return save;
11624         }
11625 
11626         auto opSlice()() const
11627         {
11628             return save;
11629         }
11630 
11631         private static string _genSave() @safe pure nothrow
11632         {
11633             return `import std.conv : emplace;` ~
11634                    `alias S = typeof((*_range).save);` ~
11635                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
11636                    `auto mem = new void[S.sizeof];` ~
11637                    `emplace!S(mem, cast(S)(*_range).save);` ~
11638                    `return RefRange!S(cast(S*) mem.ptr);`;
11639         }
11640 
11641         static assert(isForwardRange!RefRange);
11642     }
11643 
11644 
11645     version (StdDdoc)
11646     {
11647         /++
11648             Only defined if `isBidirectionalRange!R` is `true`.
11649           +/
11650         @property auto back() {assert(0);}
11651         /++ Ditto +/
11652         @property auto back() const {assert(0);}
11653         /++ Ditto +/
11654         @property auto back(ElementType!R value) {assert(0);}
11655     }
11656     else static if (isBidirectionalRange!R)
11657     {
11658         @property auto back()
11659         {
11660             return (*_range).back;
11661         }
11662 
11663         static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
11664         {
11665             return (*_range).back;
11666         }
11667 
11668         static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
11669         {
11670             return (*_range).back = value;
11671         }
11672     }
11673 
11674 
11675     /++ Ditto +/
11676     static if (isBidirectionalRange!R) void popBack()
11677     {
11678         return (*_range).popBack();
11679     }
11680 
11681 
11682     version (StdDdoc)
11683     {
11684         /++
11685             Only defined if `isRandomAccesRange!R` is `true`.
11686           +/
11687         auto ref opIndex(IndexType)(IndexType index) {assert(0);}
11688 
11689         /++ Ditto +/
11690         auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
11691     }
11692     else static if (isRandomAccessRange!R)
11693     {
11694         auto ref opIndex(IndexType)(IndexType index)
11695             if (is(typeof((*_range)[index])))
11696         {
11697             return (*_range)[index];
11698         }
11699 
11700         auto ref opIndex(IndexType)(IndexType index) const
11701             if (is(typeof((*cast(const R*)_range)[index])))
11702         {
11703             return (*_range)[index];
11704         }
11705     }
11706 
11707 
11708     /++
11709         Only defined if `hasMobileElements!R` and `isForwardRange!R` are
11710         `true`.
11711       +/
11712     static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
11713     {
11714         return (*_range).moveFront();
11715     }
11716 
11717 
11718     /++
11719         Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
11720         are `true`.
11721       +/
11722     static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
11723     {
11724         return (*_range).moveBack();
11725     }
11726 
11727 
11728     /++
11729         Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
11730         are `true`.
11731       +/
11732     static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
11733     {
11734         return (*_range).moveAt(index);
11735     }
11736 
11737 
11738     version (StdDdoc)
11739     {
11740         /++
11741             Only defined if `hasLength!R` is `true`.
11742           +/
11743         @property auto length() {assert(0);}
11744 
11745         /++ Ditto +/
11746         @property auto length() const {assert(0);}
11747 
11748         /++ Ditto +/
11749         alias opDollar = length;
11750     }
11751     else static if (hasLength!R)
11752     {
11753         @property auto length()
11754         {
11755             return (*_range).length;
11756         }
11757 
11758         static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
11759         {
11760             return (*_range).length;
11761         }
11762 
11763         alias opDollar = length;
11764     }
11765 
11766 
11767     version (StdDdoc)
11768     {
11769         /++
11770             Only defined if `hasSlicing!R` is `true`.
11771           +/
11772         auto opSlice(IndexType1, IndexType2)
11773                     (IndexType1 begin, IndexType2 end) {assert(0);}
11774 
11775         /++ Ditto +/
11776         auto opSlice(IndexType1, IndexType2)
11777                     (IndexType1 begin, IndexType2 end) const {assert(0);}
11778     }
11779     else static if (hasSlicing!R)
11780     {
11781         private alias T = typeof((*_range)[1 .. 2]);
11782         static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
11783         {
11784             private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
11785         }
11786 
11787         RefRange!T opSlice(IndexType1, IndexType2)
11788                     (IndexType1 begin, IndexType2 end)
11789             if (is(typeof((*_range)[begin .. end])))
11790         {
11791             mixin(_genOpSlice());
11792         }
11793 
11794         RefRange!CT opSlice(IndexType1, IndexType2)
11795                     (IndexType1 begin, IndexType2 end) const
11796             if (is(typeof((*cast(const R*)_range)[begin .. end])))
11797         {
11798             mixin(_genOpSlice());
11799         }
11800 
11801         private static string _genOpSlice() @safe pure nothrow
11802         {
11803             return `import std.conv : emplace;` ~
11804                    `alias S = typeof((*_range)[begin .. end]);` ~
11805                    `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
11806                    `auto mem = new void[S.sizeof];` ~
11807                    `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
11808                    `return RefRange!S(cast(S*) mem.ptr);`;
11809         }
11810     }
11811 
11812 
11813 private:
11814 
11815     R* _range;
11816 }
11817 
11818 /// Basic Example
11819 @system unittest
11820 {
11821     import std.algorithm.searching : find;
11822     ubyte[] buffer = [1, 9, 45, 12, 22];
11823     auto found1 = find(buffer, 45);
11824     assert(found1 == [45, 12, 22]);
11825     assert(buffer == [1, 9, 45, 12, 22]);
11826 
11827     auto wrapped1 = refRange(&buffer);
11828     auto found2 = find(wrapped1, 45);
11829     assert(*found2.ptr == [45, 12, 22]);
11830     assert(buffer == [45, 12, 22]);
11831 
11832     auto found3 = find(wrapped1.save, 22);
11833     assert(*found3.ptr == [22]);
11834     assert(buffer == [45, 12, 22]);
11835 
11836     string str = "hello world";
11837     auto wrappedStr = refRange(&str);
11838     assert(str.front == 'h');
11839     str.popFrontN(5);
11840     assert(str == " world");
11841     assert(wrappedStr.front == ' ');
11842     assert(*wrappedStr.ptr == " world");
11843 }
11844 
11845 /// opAssign Example.
11846 @system unittest
11847 {
11848     ubyte[] buffer1 = [1, 2, 3, 4, 5];
11849     ubyte[] buffer2 = [6, 7, 8, 9, 10];
11850     auto wrapped1 = refRange(&buffer1);
11851     auto wrapped2 = refRange(&buffer2);
11852     assert(wrapped1.ptr is &buffer1);
11853     assert(wrapped2.ptr is &buffer2);
11854     assert(wrapped1.ptr !is wrapped2.ptr);
11855     assert(buffer1 != buffer2);
11856 
11857     wrapped1 = wrapped2;
11858 
11859     //Everything points to the same stuff as before.
11860     assert(wrapped1.ptr is &buffer1);
11861     assert(wrapped2.ptr is &buffer2);
11862     assert(wrapped1.ptr !is wrapped2.ptr);
11863 
11864     //But buffer1 has changed due to the assignment.
11865     assert(buffer1 == [6, 7, 8, 9, 10]);
11866     assert(buffer2 == [6, 7, 8, 9, 10]);
11867 
11868     buffer2 = [11, 12, 13, 14, 15];
11869 
11870     //Everything points to the same stuff as before.
11871     assert(wrapped1.ptr is &buffer1);
11872     assert(wrapped2.ptr is &buffer2);
11873     assert(wrapped1.ptr !is wrapped2.ptr);
11874 
11875     //But buffer2 has changed due to the assignment.
11876     assert(buffer1 == [6, 7, 8, 9, 10]);
11877     assert(buffer2 == [11, 12, 13, 14, 15]);
11878 
11879     wrapped2 = null;
11880 
11881     //The pointer changed for wrapped2 but not wrapped1.
11882     assert(wrapped1.ptr is &buffer1);
11883     assert(wrapped2.ptr is null);
11884     assert(wrapped1.ptr !is wrapped2.ptr);
11885 
11886     //buffer2 is not affected by the assignment.
11887     assert(buffer1 == [6, 7, 8, 9, 10]);
11888     assert(buffer2 == [11, 12, 13, 14, 15]);
11889 }
11890 
11891 @system unittest
11892 {
11893     import std.algorithm.iteration : filter;
11894     {
11895         ubyte[] buffer = [1, 2, 3, 4, 5];
11896         auto wrapper = refRange(&buffer);
11897         auto p = wrapper.ptr;
11898         auto f = wrapper.front;
11899         wrapper.front = f;
11900         auto e = wrapper.empty;
11901         wrapper.popFront();
11902         auto s = wrapper.save;
11903         auto b = wrapper.back;
11904         wrapper.back = b;
11905         wrapper.popBack();
11906         auto i = wrapper[0];
11907         wrapper.moveFront();
11908         wrapper.moveBack();
11909         wrapper.moveAt(0);
11910         auto l = wrapper.length;
11911         auto sl = wrapper[0 .. 1];
11912         assert(wrapper[0 .. $].length == buffer[0 .. $].length);
11913     }
11914 
11915     {
11916         ubyte[] buffer = [1, 2, 3, 4, 5];
11917         const wrapper = refRange(&buffer);
11918         const p = wrapper.ptr;
11919         const f = wrapper.front;
11920         const e = wrapper.empty;
11921         const s = wrapper.save;
11922         const b = wrapper.back;
11923         const i = wrapper[0];
11924         const l = wrapper.length;
11925         const sl = wrapper[0 .. 1];
11926     }
11927 
11928     {
11929         ubyte[] buffer = [1, 2, 3, 4, 5];
11930         auto filtered = filter!"true"(buffer);
11931         auto wrapper = refRange(&filtered);
11932         auto p = wrapper.ptr;
11933         auto f = wrapper.front;
11934         wrapper.front = f;
11935         auto e = wrapper.empty;
11936         wrapper.popFront();
11937         auto s = wrapper.save;
11938         wrapper.moveFront();
11939     }
11940 
11941     {
11942         ubyte[] buffer = [1, 2, 3, 4, 5];
11943         auto filtered = filter!"true"(buffer);
11944         const wrapper = refRange(&filtered);
11945         const p = wrapper.ptr;
11946 
11947         //Cannot currently be const. filter needs to be updated to handle const.
11948         /+
11949         const f = wrapper.front;
11950         const e = wrapper.empty;
11951         const s = wrapper.save;
11952         +/
11953     }
11954 
11955     {
11956         string str = "hello world";
11957         auto wrapper = refRange(&str);
11958         auto p = wrapper.ptr;
11959         auto f = wrapper.front;
11960         auto e = wrapper.empty;
11961         wrapper.popFront();
11962         auto s = wrapper.save;
11963         auto b = wrapper.back;
11964         wrapper.popBack();
11965     }
11966 
11967     {
11968         // https://issues.dlang.org/show_bug.cgi?id=16534
11969         // opDollar should be defined if the wrapped range defines length.
11970         auto range = 10.iota.takeExactly(5);
11971         auto wrapper = refRange(&range);
11972         assert(wrapper.length == 5);
11973         assert(wrapper[0 .. $ - 1].length == 4);
11974     }
11975 }
11976 
11977 //Test assignment.
11978 @system unittest
11979 {
11980     ubyte[] buffer1 = [1, 2, 3, 4, 5];
11981     ubyte[] buffer2 = [6, 7, 8, 9, 10];
11982     RefRange!(ubyte[]) wrapper1;
11983     RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
11984     assert(wrapper1.ptr is null);
11985     assert(wrapper2.ptr is &buffer2);
11986 
11987     wrapper1 = refRange(&buffer1);
11988     assert(wrapper1.ptr is &buffer1);
11989 
11990     wrapper1 = wrapper2;
11991     assert(wrapper1.ptr is &buffer1);
11992     assert(buffer1 == buffer2);
11993 
11994     wrapper1 = RefRange!(ubyte[]).init;
11995     assert(wrapper1.ptr is null);
11996     assert(wrapper2.ptr is &buffer2);
11997     assert(buffer1 == buffer2);
11998     assert(buffer1 == [6, 7, 8, 9, 10]);
11999 
12000     wrapper2 = null;
12001     assert(wrapper2.ptr is null);
12002     assert(buffer2 == [6, 7, 8, 9, 10]);
12003 }
12004 
12005 @system unittest
12006 {
12007     import std.algorithm.comparison : equal;
12008     import std.algorithm.mutation : bringToFront;
12009     import std.algorithm.searching : commonPrefix, find, until;
12010     import std.algorithm.sorting : sort;
12011 
12012     //Test that ranges are properly consumed.
12013     {
12014         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12015         auto wrapper = refRange(&arr);
12016 
12017         assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12018         assert(arr == [41, 3, 40, 4, 42, 9]);
12019 
12020         assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12021         assert(arr == [40, 4, 42, 9]);
12022 
12023         assert(equal(until(wrapper, 42), [40, 4]));
12024         assert(arr == [42, 9]);
12025 
12026         assert(find(wrapper, 12).empty);
12027         assert(arr.empty);
12028     }
12029 
12030     {
12031         string str = "Hello, world-like object.";
12032         auto wrapper = refRange(&str);
12033 
12034         assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12035         assert(str == "llo, world-like object.");
12036 
12037         assert(equal(take(wrapper, 5), "llo, "));
12038         assert(str == "world-like object.");
12039     }
12040 
12041     //Test that operating on saved ranges does not consume the original.
12042     {
12043         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12044         auto wrapper = refRange(&arr);
12045         auto saved = wrapper.save;
12046         saved.popFrontN(3);
12047         assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12048         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12049     }
12050 
12051     {
12052         string str = "Hello, world-like object.";
12053         auto wrapper = refRange(&str);
12054         auto saved = wrapper.save;
12055         saved.popFrontN(13);
12056         assert(*saved.ptr == "like object.");
12057         assert(str == "Hello, world-like object.");
12058     }
12059 
12060     //Test that functions which use save work properly.
12061     {
12062         int[] arr = [1, 42];
12063         auto wrapper = refRange(&arr);
12064         assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12065     }
12066 
12067     {
12068         int[] arr = [4, 5, 6, 7, 1, 2, 3];
12069         auto wrapper = refRange(&arr);
12070         assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12071         assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12072     }
12073 
12074     //Test bidirectional functions.
12075     {
12076         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12077         auto wrapper = refRange(&arr);
12078 
12079         assert(wrapper.back == 9);
12080         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12081 
12082         wrapper.popBack();
12083         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12084     }
12085 
12086     {
12087         string str = "Hello, world-like object.";
12088         auto wrapper = refRange(&str);
12089 
12090         assert(wrapper.back == '.');
12091         assert(str == "Hello, world-like object.");
12092 
12093         wrapper.popBack();
12094         assert(str == "Hello, world-like object");
12095     }
12096 
12097     //Test random access functions.
12098     {
12099         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12100         auto wrapper = refRange(&arr);
12101 
12102         assert(wrapper[2] == 2);
12103         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12104 
12105         assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
12106         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12107     }
12108 
12109     //Test move functions.
12110     {
12111         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12112         auto wrapper = refRange(&arr);
12113 
12114         auto t1 = wrapper.moveFront();
12115         auto t2 = wrapper.moveBack();
12116         wrapper.front = t2;
12117         wrapper.back = t1;
12118         assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
12119 
12120         sort(wrapper.save);
12121         assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
12122     }
12123 }
12124 
12125 @system unittest
12126 {
12127     struct S
12128     {
12129         @property int front() @safe const pure nothrow { return 0; }
12130         enum bool empty = false;
12131         void popFront() @safe pure nothrow { }
12132         @property auto save() @safe pure nothrow { return this; }
12133     }
12134 
12135     S s;
12136     auto wrapper = refRange(&s);
12137     static assert(isInfinite!(typeof(wrapper)));
12138 }
12139 
12140 @system unittest
12141 {
12142     class C
12143     {
12144         @property int front() @safe const pure nothrow { return 0; }
12145         @property bool empty() @safe const pure nothrow { return false; }
12146         void popFront() @safe pure nothrow { }
12147         @property auto save() @safe pure nothrow { return this; }
12148     }
12149     static assert(isForwardRange!C);
12150 
12151     auto c = new C;
12152     auto cWrapper = refRange(&c);
12153     static assert(is(typeof(cWrapper) == C));
12154     assert(cWrapper is c);
12155 }
12156 
12157 // https://issues.dlang.org/show_bug.cgi?id=14373
12158 @system unittest
12159 {
12160     static struct R
12161     {
12162         @property int front() {return 0;}
12163         void popFront() {empty = true;}
12164         bool empty = false;
12165     }
12166     R r;
12167     refRange(&r).popFront();
12168     assert(r.empty);
12169 }
12170 
12171 // https://issues.dlang.org/show_bug.cgi?id=14575
12172 @system unittest
12173 {
12174     struct R
12175     {
12176         Object front;
12177         alias back = front;
12178         bool empty = false;
12179         void popFront() {empty = true;}
12180         alias popBack = popFront;
12181         @property R save() {return this;}
12182     }
12183     static assert(isBidirectionalRange!R);
12184     R r;
12185     auto rr = refRange(&r);
12186 
12187     struct R2
12188     {
12189         @property Object front() {return null;}
12190         @property const(Object) front() const {return null;}
12191         alias back = front;
12192         bool empty = false;
12193         void popFront() {empty = true;}
12194         alias popBack = popFront;
12195         @property R2 save() {return this;}
12196     }
12197     static assert(isBidirectionalRange!R2);
12198     R2 r2;
12199     auto rr2 = refRange(&r2);
12200 }
12201 
12202 /// ditto
12203 auto refRange(R)(R* range)
12204 if (isInputRange!R)
12205 {
12206     static if (!is(R == class))
12207         return RefRange!R(range);
12208     else
12209         return *range;
12210 }
12211 
12212 // https://issues.dlang.org/show_bug.cgi?id=9060
12213 @safe unittest
12214 {
12215     import std.algorithm.iteration : map, joiner, group;
12216     import std.algorithm.searching : until;
12217     // fix for std.algorithm
12218     auto r = map!(x => 0)([1]);
12219     chain(r, r);
12220     zip(r, r);
12221     roundRobin(r, r);
12222 
12223     struct NRAR {
12224         typeof(r) input;
12225         @property empty() { return input.empty; }
12226         @property front() { return input.front; }
12227         void popFront()   { input.popFront(); }
12228         @property save()  { return NRAR(input.save); }
12229     }
12230     auto n1 = NRAR(r);
12231     cycle(n1);  // non random access range version
12232 
12233     assumeSorted(r);
12234 
12235     // fix for std.range
12236     joiner([r], [9]);
12237 
12238     struct NRAR2 {
12239         NRAR input;
12240         @property empty() { return true; }
12241         @property front() { return input; }
12242         void popFront() { }
12243         @property save()  { return NRAR2(input.save); }
12244     }
12245     auto n2 = NRAR2(n1);
12246     joiner(n2);
12247 
12248     group(r);
12249 
12250     until(r, 7);
12251     static void foo(R)(R r) { until!(x => x > 7)(r); }
12252     foo(r);
12253 }
12254 
12255 private struct Bitwise(R)
12256 if (isInputRange!R && isIntegral!(ElementType!R))
12257 {
12258     import std.traits : Unsigned;
12259 private:
12260     alias ElemType = ElementType!R;
12261     alias UnsignedElemType = Unsigned!ElemType;
12262 
12263     R parent;
12264     enum bitsNum = ElemType.sizeof * 8;
12265     size_t maskPos = 1;
12266 
12267     static if (isBidirectionalRange!R)
12268     {
12269         size_t backMaskPos = bitsNum;
12270     }
12271 
12272 public:
12273     this()(auto ref R range)
12274     {
12275         parent = range;
12276     }
12277 
12278     static if (isInfinite!R)
12279     {
12280         enum empty = false;
12281     }
12282     else
12283     {
12284         /**
12285          * Check if the range is empty
12286          *
12287          * Returns: a boolean true or false
12288          */
12289         bool empty()
12290         {
12291             static if (hasLength!R)
12292             {
12293                 return length == 0;
12294             }
12295             else static if (isBidirectionalRange!R)
12296             {
12297                 if (parent.empty)
12298                 {
12299                     return true;
12300                 }
12301                 else
12302                 {
12303                     /*
12304                        If we have consumed the last element of the range both from
12305                        the front and the back, then the masks positions will overlap
12306                      */
12307                     return parent.save.dropOne.empty && (maskPos > backMaskPos);
12308                 }
12309             }
12310             else
12311             {
12312                 /*
12313                    If we consumed the last element of the range, but not all the
12314                    bits in the last element
12315                  */
12316                 return parent.empty;
12317             }
12318         }
12319     }
12320 
12321     bool front()
12322     {
12323         assert(!empty);
12324         return (parent.front & mask(maskPos)) != 0;
12325     }
12326 
12327     void popFront()
12328     {
12329         assert(!empty);
12330         ++maskPos;
12331         if (maskPos > bitsNum)
12332         {
12333             parent.popFront;
12334             maskPos = 1;
12335         }
12336     }
12337 
12338     static if (hasLength!R)
12339     {
12340         size_t length()
12341         {
12342             auto len = parent.length * bitsNum - (maskPos - 1);
12343             static if (isBidirectionalRange!R)
12344             {
12345                 len -= bitsNum - backMaskPos;
12346             }
12347             return len;
12348         }
12349 
12350         alias opDollar = length;
12351     }
12352 
12353     static if (isForwardRange!R)
12354     {
12355         typeof(this) save()
12356         {
12357             auto result = this;
12358             result.parent = parent.save;
12359             return result;
12360         }
12361     }
12362 
12363     static if (isBidirectionalRange!R)
12364     {
12365         bool back()
12366         {
12367             assert(!empty);
12368             return (parent.back & mask(backMaskPos)) != 0;
12369         }
12370 
12371         void popBack()
12372         {
12373             assert(!empty);
12374             --backMaskPos;
12375             if (backMaskPos == 0)
12376             {
12377                 parent.popBack;
12378                 backMaskPos = bitsNum;
12379             }
12380         }
12381     }
12382 
12383     static if (isRandomAccessRange!R)
12384     {
12385         /**
12386           Return the `n`th bit within the range
12387          */
12388         bool opIndex(size_t n)
12389         in
12390         {
12391             /*
12392                If it does not have the length property, it means that R is
12393                an infinite range
12394              */
12395             static if (hasLength!R)
12396             {
12397                 assert(n < length, "Index out of bounds");
12398             }
12399         }
12400         do
12401         {
12402             immutable size_t remainingBits = bitsNum - maskPos + 1;
12403             // If n >= maskPos, then the bit sign will be 1, otherwise 0
12404             immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12405             /*
12406                By truncating n with remainingBits bits we have skipped the
12407                remaining bits in parent[0], so we need to add 1 to elemIndex.
12408 
12409                Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
12410              */
12411             import core.bitop : bsf;
12412             immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12413 
12414             /*
12415                Since the indexing is from LSB to MSB, we need to index at the
12416                remainder of (n - remainingBits).
12417 
12418                Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
12419              */
12420             immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12421                              + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12422 
12423             return (parent[elemIndex] & mask(elemMaskPos)) != 0;
12424         }
12425 
12426         static if (hasAssignableElements!R)
12427         {
12428             /**
12429               Assigns `flag` to the `n`th bit within the range
12430              */
12431             void opIndexAssign(bool flag, size_t n)
12432                 in
12433                 {
12434                     static if (hasLength!R)
12435                     {
12436                         assert(n < length, "Index out of bounds");
12437                     }
12438                 }
12439             do
12440             {
12441                 import core.bitop : bsf;
12442 
12443                 immutable size_t remainingBits = bitsNum - maskPos + 1;
12444                 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12445                 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12446                 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12447                     + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12448 
12449                 auto elem = parent[elemIndex];
12450                 auto elemMask = mask(elemMaskPos);
12451                 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
12452                         + (flag ^ 1) * (elem & ~elemMask));
12453             }
12454         }
12455 
12456         Bitwise!R opSlice()
12457         {
12458             return this.save;
12459         }
12460 
12461         Bitwise!R opSlice(size_t start, size_t end)
12462         in
12463         {
12464             assert(start < end, "Invalid bounds: end <= start");
12465         }
12466         do
12467         {
12468             import core.bitop : bsf;
12469 
12470             size_t remainingBits = bitsNum - maskPos + 1;
12471             ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12472             immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
12473             immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
12474                                               + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
12475 
12476             immutable size_t sliceLen = end - start - 1;
12477             remainingBits = bitsNum - startElemMaskPos + 1;
12478             sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12479             immutable size_t endElemIndex = startElemIndex
12480                                           + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
12481             immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
12482                                             + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
12483 
12484             typeof(return) result;
12485             // Get the slice to be returned from the parent
12486             result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
12487             result.maskPos = startElemMaskPos;
12488             static if (isBidirectionalRange!R)
12489             {
12490                 result.backMaskPos = endElemMaskPos;
12491             }
12492             return result;
12493         }
12494     }
12495 
12496 private:
12497     auto mask(size_t maskPos)
12498     {
12499         return (1UL << (maskPos - 1UL));
12500     }
12501 }
12502 
12503 /**
12504 Bitwise adapter over an integral type range. Consumes the range elements bit by
12505 bit, from the least significant bit to the most significant bit.
12506 
12507 Params:
12508     R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
12509     range = range to consume bit by by
12510 
12511 Returns:
12512     A `Bitwise` input range with propagated forward, bidirectional
12513     and random access capabilities
12514 */
12515 auto bitwise(R)(auto ref R range)
12516 if (isInputRange!R && isIntegral!(ElementType!R))
12517 {
12518     return Bitwise!R(range);
12519 }
12520 
12521 ///
12522 @safe pure unittest
12523 {
12524     import std.algorithm.comparison : equal;
12525     import std.format : format;
12526 
12527     // 00000011 00001001
12528     ubyte[] arr = [3, 9];
12529     auto r = arr.bitwise;
12530 
12531     // iterate through it as with any other range
12532     assert(format("%(%d%)", r) == "1100000010010000");
12533     assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
12534 
12535     auto r2 = r[5 .. $];
12536     // set a bit
12537     r[2] = 1;
12538     assert(arr[0] == 7);
12539     assert(r[5] == r2[0]);
12540 }
12541 
12542 /// You can use bitwise to implement an uniform bool generator
12543 @safe unittest
12544 {
12545     import std.algorithm.comparison : equal;
12546     import std.random : rndGen;
12547 
12548     auto rb = rndGen.bitwise;
12549     static assert(isInfinite!(typeof(rb)));
12550 
12551     auto rb2 = rndGen.bitwise;
12552     // Don't forget that structs are passed by value
12553     assert(rb.take(10).equal(rb2.take(10)));
12554 }
12555 
12556 // Test nogc inference
12557 @safe @nogc unittest
12558 {
12559     static ubyte[] arr = [3, 9];
12560     auto bw = arr.bitwise;
12561     auto bw2 = bw[];
12562     auto bw3 = bw[8 .. $];
12563     bw3[2] = true;
12564 
12565     assert(arr[1] == 13);
12566     assert(bw[$ - 6]);
12567     assert(bw[$ - 6] == bw2[$ - 6]);
12568     assert(bw[$ - 6] == bw3[$ - 6]);
12569 }
12570 
12571 // Test all range types over all integral types
12572 @safe pure nothrow unittest
12573 {
12574     import std.meta : AliasSeq;
12575     import std.internal.test.dummyrange;
12576 
12577     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
12578             long, ulong);
12579     foreach (IntegralType; IntegralTypes)
12580     {
12581         foreach (T; AllDummyRangesType!(IntegralType[]))
12582         {
12583             T a;
12584             auto bw = Bitwise!T(a);
12585 
12586             static if (isForwardRange!T)
12587             {
12588                 auto bwFwdSave = bw.save;
12589             }
12590 
12591             static if (isBidirectionalRange!T)
12592             {
12593                 auto bwBack = bw.save;
12594                 auto bwBackSave = bw.save;
12595             }
12596 
12597             static if (hasLength!T)
12598             {
12599                 auto bwLength = bw.length;
12600                 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
12601                 static if (isForwardRange!T)
12602                 {
12603                     assert(bw.length == bwFwdSave.length);
12604                 }
12605             }
12606 
12607             // Make sure front and back are not the mechanisms that modify the range
12608             long numCalls = 42;
12609             bool initialFrontValue;
12610 
12611             if (!bw.empty)
12612             {
12613                 initialFrontValue = bw.front;
12614             }
12615 
12616             while (!bw.empty && (--numCalls))
12617             {
12618                 bw.front;
12619                 assert(bw.front == initialFrontValue);
12620             }
12621 
12622             /*
12623                Check that empty works properly and that popFront does not get called
12624                more times than it should
12625              */
12626             numCalls = 0;
12627             while (!bw.empty)
12628             {
12629                 ++numCalls;
12630 
12631                 static if (hasLength!T)
12632                 {
12633                     assert(bw.length == bwLength);
12634                     --bwLength;
12635                 }
12636 
12637                 static if (isForwardRange!T)
12638                 {
12639                     assert(bw.front == bwFwdSave.front);
12640                     bwFwdSave.popFront();
12641                 }
12642 
12643                 static if (isBidirectionalRange!T)
12644                 {
12645                     assert(bwBack.front == bwBackSave.front);
12646                     bwBack.popBack();
12647                     bwBackSave.popBack();
12648                 }
12649                 bw.popFront();
12650             }
12651 
12652             auto rangeLen = numCalls / (IntegralType.sizeof * 8);
12653             assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
12654             assert(bw.empty);
12655             static if (isForwardRange!T)
12656             {
12657                 assert(bwFwdSave.empty);
12658             }
12659 
12660             static if (isBidirectionalRange!T)
12661             {
12662                 assert(bwBack.empty);
12663             }
12664         }
12665     }
12666 }
12667 
12668 // Test opIndex and opSlice
12669 @system unittest
12670 {
12671     import std.meta : AliasSeq;
12672     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
12673             long, ulong);
12674     foreach (IntegralType; IntegralTypes)
12675     {
12676         size_t bitsNum = IntegralType.sizeof * 8;
12677 
12678         auto first = cast(IntegralType)(1);
12679 
12680         // 2 ^ (bitsNum - 1)
12681         auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
12682 
12683         IntegralType[] a = [first, second];
12684         auto bw = Bitwise!(IntegralType[])(a);
12685 
12686         // Check against lsb of a[0]
12687         assert(bw[0] == true);
12688         // Check against msb - 1 of a[1]
12689         assert(bw[2 * bitsNum - 2] == true);
12690 
12691         bw.popFront();
12692         assert(bw[2 * bitsNum - 3] == true);
12693 
12694         import std.exception : assertThrown;
12695 
12696         // Check out of bounds error
12697         assertThrown!Error(bw[2 * bitsNum - 1]);
12698 
12699         bw[2] = true;
12700         assert(bw[2] == true);
12701         bw.popFront();
12702         assert(bw[1] == true);
12703 
12704         auto bw2 = bw[0 .. $ - 5];
12705         auto bw3 = bw2[];
12706         assert(bw2.length == (bw.length - 5));
12707         assert(bw2.length == bw3.length);
12708         bw2.popFront();
12709         assert(bw2.length != bw3.length);
12710     }
12711 }
12712 
12713 /*********************************
12714  * An OutputRange that discards the data it receives.
12715  */
12716 struct NullSink
12717 {
12718     void put(E)(scope const E) pure @safe @nogc nothrow {}
12719 }
12720 
12721 /// ditto
12722 auto ref nullSink()
12723 {
12724     static NullSink sink;
12725     return sink;
12726 }
12727 
12728 ///
12729 @safe nothrow unittest
12730 {
12731     import std.algorithm.iteration : map;
12732     import std.algorithm.mutation : copy;
12733     [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
12734 }
12735 
12736 ///
12737 @safe unittest
12738 {
12739     import std.csv : csvNextToken;
12740 
12741     string line = "a,b,c";
12742 
12743     // ignore the first column
12744     line.csvNextToken(nullSink, ',', '"');
12745     line.popFront;
12746 
12747     // look at the second column
12748     Appender!string app;
12749     line.csvNextToken(app, ',', '"');
12750     assert(app.data == "b");
12751 }
12752 
12753 @safe unittest
12754 {
12755     auto r = 10.iota
12756                 .tee(nullSink)
12757                 .dropOne;
12758 
12759     assert(r.front == 1);
12760 }
12761 
12762 /++
12763 
12764   Implements a "tee" style pipe, wrapping an input range so that elements of the
12765   range can be passed to a provided function or $(LREF OutputRange) as they are
12766   iterated over. This is useful for printing out intermediate values in a long
12767   chain of range code, performing some operation with side-effects on each call
12768   to `front` or `popFront`, or diverting the elements of a range into an
12769   auxiliary $(LREF OutputRange).
12770 
12771   It is important to note that as the resultant range is evaluated lazily,
12772   in the case of the version of `tee` that takes a function, the function
12773   will not actually be executed until the range is "walked" using functions
12774   that evaluate ranges, such as $(REF array, std,array) or
12775   $(REF fold, std,algorithm,iteration).
12776 
12777   Params:
12778   pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
12779   calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
12780   respectively, `fun`). Note that each `popFront()` call will mirror the
12781   old `front` value, not the new one. This means that the last value will
12782   not be forwarded if the range isn't iterated until empty. If
12783   `No.pipeOnPop`, only elements for which `front` does get called will be
12784   also sent to `outputRange`/`fun`. If `front` is called twice for the same
12785   element, it will still be sent only once. If this caching is undesired,
12786   consider using $(REF map, std,algorithm,iteration) instead.
12787   inputRange = The input range being passed through.
12788   outputRange = This range will receive elements of `inputRange` progressively
12789   as iteration proceeds.
12790   fun = This function will be called with elements of `inputRange`
12791   progressively as iteration proceeds.
12792 
12793   Returns:
12794   An input range that offers the elements of `inputRange`. Regardless of
12795   whether `inputRange` is a more powerful range (forward, bidirectional etc),
12796   the result is always an input range. Reading this causes `inputRange` to be
12797   iterated and returns its elements in turn. In addition, the same elements
12798   will be passed to `outputRange` or `fun` as well.
12799 
12800   See_Also: $(REF each, std,algorithm,iteration)
12801 +/
12802 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
12803 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
12804 {
12805     static struct Result
12806     {
12807         private R1 _input;
12808         private R2 _output;
12809         static if (!pipeOnPop)
12810         {
12811             private bool _frontAccessed;
12812         }
12813 
12814         static if (hasLength!R1)
12815         {
12816             @property auto length()
12817             {
12818                 return _input.length;
12819             }
12820         }
12821 
12822         static if (isInfinite!R1)
12823         {
12824             enum bool empty = false;
12825         }
12826         else
12827         {
12828             @property bool empty() { return _input.empty; }
12829         }
12830 
12831         void popFront()
12832         {
12833             assert(!_input.empty, "Attempting to popFront an empty tee");
12834             static if (pipeOnPop)
12835             {
12836                 put(_output, _input.front);
12837             }
12838             else
12839             {
12840                 _frontAccessed = false;
12841             }
12842             _input.popFront();
12843         }
12844 
12845         @property auto ref front()
12846         {
12847             assert(!_input.empty, "Attempting to fetch the front of an empty tee");
12848             static if (!pipeOnPop)
12849             {
12850                 if (!_frontAccessed)
12851                 {
12852                     _frontAccessed = true;
12853                     put(_output, _input.front);
12854                 }
12855             }
12856             return _input.front;
12857         }
12858     }
12859 
12860     return Result(inputRange, outputRange);
12861 }
12862 
12863 /// Ditto
12864 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
12865 if (is(typeof(fun) == void) || isSomeFunction!fun)
12866 {
12867     import std.traits : isDelegate, isFunctionPointer;
12868     /*
12869         Distinguish between function literals and template lambdas
12870         when using either as an $(LREF OutputRange). Since a template
12871         has no type, typeof(template) will always return void.
12872         If it's a template lambda, it's first necessary to instantiate
12873         it with `ElementType!R1`.
12874     */
12875     static if (is(typeof(fun) == void))
12876         alias _fun = fun!(ElementType!R1);
12877     else
12878         alias _fun = fun;
12879 
12880     static if (isFunctionPointer!_fun || isDelegate!_fun)
12881     {
12882         return tee!pipeOnPop(inputRange, _fun);
12883     }
12884     else
12885     {
12886         return tee!pipeOnPop(inputRange, &_fun);
12887     }
12888 }
12889 
12890 ///
12891 @safe unittest
12892 {
12893     import std.algorithm.comparison : equal;
12894     import std.algorithm.iteration : filter, map;
12895 
12896     // Sum values while copying
12897     int[] values = [1, 4, 9, 16, 25];
12898     int sum = 0;
12899     auto newValues = values.tee!(a => sum += a).array;
12900     assert(equal(newValues, values));
12901     assert(sum == 1 + 4 + 9 + 16 + 25);
12902 
12903     // Count values that pass the first filter
12904     int count = 0;
12905     auto newValues4 = values.filter!(a => a < 10)
12906                             .tee!(a => count++)
12907                             .map!(a => a + 1)
12908                             .filter!(a => a < 10);
12909 
12910     //Fine, equal also evaluates any lazy ranges passed to it.
12911     //count is not 3 until equal evaluates newValues4
12912     assert(equal(newValues4, [2, 5]));
12913     assert(count == 3);
12914 }
12915 
12916 //
12917 @safe unittest
12918 {
12919     import std.algorithm.comparison : equal;
12920     import std.algorithm.iteration : filter, map;
12921 
12922     int[] values = [1, 4, 9, 16, 25];
12923 
12924     int count = 0;
12925     auto newValues = values.filter!(a => a < 10)
12926         .tee!(a => count++, No.pipeOnPop)
12927         .map!(a => a + 1)
12928         .filter!(a => a < 10);
12929 
12930     auto val = newValues.front;
12931     assert(count == 1);
12932     //front is only evaluated once per element
12933     val = newValues.front;
12934     assert(count == 1);
12935 
12936     //popFront() called, fun will be called
12937     //again on the next access to front
12938     newValues.popFront();
12939     newValues.front;
12940     assert(count == 2);
12941 
12942     int[] preMap = new int[](3), postMap = [];
12943     auto mappedValues = values.filter!(a => a < 10)
12944         //Note the two different ways of using tee
12945         .tee(preMap)
12946         .map!(a => a + 1)
12947         .tee!(a => postMap ~= a)
12948         .filter!(a => a < 10);
12949     assert(equal(mappedValues, [2, 5]));
12950     assert(equal(preMap, [1, 4, 9]));
12951     assert(equal(postMap, [2, 5, 10]));
12952 }
12953 
12954 //
12955 @safe unittest
12956 {
12957     import std.algorithm.comparison : equal;
12958     import std.algorithm.iteration : filter, map;
12959 
12960     char[] txt = "Line one, Line 2".dup;
12961 
12962     bool isVowel(dchar c)
12963     {
12964         import std..string : indexOf;
12965         return "AaEeIiOoUu".indexOf(c) != -1;
12966     }
12967 
12968     int vowelCount = 0;
12969     int shiftedCount = 0;
12970     auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
12971                                 .filter!(c => !isVowel(c))
12972                                 .map!(c => (c == ' ') ? c : c + 1)
12973                                 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
12974     assert(equal(removeVowels, "Mo o- Mo 3"));
12975     assert(vowelCount == 6);
12976     assert(shiftedCount == 3);
12977 }
12978 
12979 @safe unittest
12980 {
12981     // Manually stride to test different pipe behavior.
12982     void testRange(Range)(Range r)
12983     {
12984         const int strideLen = 3;
12985         int i = 0;
12986         ElementType!Range elem1;
12987         ElementType!Range elem2;
12988         while (!r.empty)
12989         {
12990             if (i % strideLen == 0)
12991             {
12992                 //Make sure front is only
12993                 //evaluated once per item
12994                 elem1 = r.front;
12995                 elem2 = r.front;
12996                 assert(elem1 == elem2);
12997             }
12998             r.popFront();
12999             i++;
13000         }
13001     }
13002 
13003     string txt = "abcdefghijklmnopqrstuvwxyz";
13004 
13005     int popCount = 0;
13006     auto pipeOnPop = txt.tee!(a => popCount++);
13007     testRange(pipeOnPop);
13008     assert(popCount == 26);
13009 
13010     int frontCount = 0;
13011     auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13012     testRange(pipeOnFront);
13013     assert(frontCount == 9);
13014 }
13015 
13016 @safe unittest
13017 {
13018     import std.algorithm.comparison : equal;
13019     import std.meta : AliasSeq;
13020 
13021     //Test diverting elements to an OutputRange
13022     string txt = "abcdefghijklmnopqrstuvwxyz";
13023 
13024     dchar[] asink1 = [];
13025     auto fsink = (dchar c) { asink1 ~= c; };
13026     auto result1 = txt.tee(fsink).array;
13027     assert(equal(txt, result1) && (equal(result1, asink1)));
13028 
13029     dchar[] _asink1 = [];
13030     auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13031     assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13032 
13033     dchar[] asink2 = new dchar[](txt.length);
13034     void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13035     auto result2 = txt.tee(&fsink2).array;
13036     assert(equal(txt, result2) && equal(result2, asink2));
13037 
13038     dchar[] asink3 = new dchar[](txt.length);
13039     auto result3 = txt.tee(asink3).array;
13040     assert(equal(txt, result3) && equal(result3, asink3));
13041 
13042     static foreach (CharType; AliasSeq!(char, wchar, dchar))
13043     {{
13044         auto appSink = appender!(CharType[])();
13045         auto appResult = txt.tee(appSink).array;
13046         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13047     }}
13048 
13049     static foreach (StringType; AliasSeq!(string, wstring, dstring))
13050     {{
13051         auto appSink = appender!StringType();
13052         auto appResult = txt.tee(appSink).array;
13053         assert(equal(txt, appResult) && equal(appResult, appSink.data));
13054     }}
13055 }
13056 
13057 // https://issues.dlang.org/show_bug.cgi?id=13483
13058 @safe unittest
13059 {
13060     static void func1(T)(T x) {}
13061     void func2(int x) {}
13062 
13063     auto r = [1, 2, 3, 4].tee!func1.tee!func2;
13064 }
13065 
13066 /**
13067 Extends the length of the input range `r` by padding out the start of the
13068 range with the element `e`. The element `e` must be of a common type with
13069 the element type of the range `r` as defined by $(REF CommonType, std, traits).
13070 If `n` is less than the length of of `r`, then `r` is returned unmodified.
13071 
13072 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
13073 about length for strings, which is not the number of characters, or
13074 graphemes, but instead the number of encoding units. If you want to treat each
13075 grapheme as only one encoding unit long, then call
13076 $(REF byGrapheme, std, uni) before calling this function.
13077 
13078 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
13079 
13080 Params:
13081     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
13082     e = element to pad the range with
13083     n = the length to pad to
13084 
13085 Returns:
13086     A range containing the elements of the original range with the extra padding
13087 
13088 See Also:
13089     $(REF leftJustifier, std, string)
13090 */
13091 auto padLeft(R, E)(R r, E e, size_t n)
13092 if (
13093     ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
13094     !is(CommonType!(ElementType!R, E) == void)
13095 )
13096 {
13097     static if (hasLength!R)
13098         auto dataLength = r.length;
13099     else
13100         auto dataLength = r.save.walkLength(n);
13101 
13102     return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
13103 }
13104 
13105 ///
13106 @safe pure unittest
13107 {
13108     import std.algorithm.comparison : equal;
13109 
13110     assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
13111     assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
13112 
13113     assert("abc".padLeft('_', 6).equal("___abc"));
13114 }
13115 
13116 @safe pure nothrow unittest
13117 {
13118     import std.algorithm.comparison : equal;
13119     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
13120     import std.meta : AliasSeq;
13121 
13122     alias DummyRanges = AliasSeq!(
13123         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
13124         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
13125         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
13126         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
13127         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
13128         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
13129         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
13130         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
13131         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
13132         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
13133     );
13134 
13135     foreach (Range; DummyRanges)
13136     {
13137         Range r;
13138         assert(r
13139             .padLeft(0, 12)
13140             .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13141         );
13142     }
13143 }
13144 
13145 // Test nogc inference
13146 @safe @nogc pure unittest
13147 {
13148     import std.algorithm.comparison : equal;
13149 
13150     static immutable r1 = [1, 2, 3, 4];
13151     static immutable r2 = [0, 0, 1, 2, 3, 4];
13152     assert(r1.padLeft(0, 6).equal(r2));
13153 }
13154 
13155 /**
13156 Extend the length of the input range `r` by padding out the end of the range
13157 with the element `e`. The element `e` must be of a common type with the
13158 element type of the range `r` as defined by $(REF CommonType, std, traits).
13159 If `n` is less than the length of of `r`, then the contents of `r` are
13160 returned.
13161 
13162 The range primitives that the resulting range provides depends whether or not `r`
13163 provides them. Except the functions `back` and `popBack`, which also require
13164 the range to have a length as well as `back` and `popBack`
13165 
13166 Params:
13167     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
13168     e = element to pad the range with
13169     n = the length to pad to
13170 
13171 Returns:
13172     A range containing the elements of the original range with the extra padding
13173 
13174 See Also:
13175     $(REF rightJustifier, std, string)
13176 */
13177 auto padRight(R, E)(R r, E e, size_t n)
13178 if (
13179     isInputRange!R &&
13180     !isInfinite!R &&
13181     !is(CommonType!(ElementType!R, E) == void))
13182 {
13183     static struct Result
13184     {
13185         private:
13186         R data;
13187         E element;
13188         static if (hasLength!R)
13189         {
13190             size_t padLength;
13191         }
13192         else
13193         {
13194             size_t minLength;
13195             size_t consumed;
13196         }
13197 
13198         public:
13199         bool empty() @property
13200         {
13201             static if (hasLength!R)
13202             {
13203                 return data.empty && padLength == 0;
13204             }
13205             else
13206             {
13207                 return data.empty && consumed >= minLength;
13208             }
13209         }
13210 
13211         auto front() @property
13212         {
13213             assert(!empty, "Attempting to fetch the front of an empty padRight");
13214             return data.empty ? element : data.front;
13215         }
13216 
13217         void popFront()
13218         {
13219             assert(!empty, "Attempting to popFront an empty padRight");
13220 
13221             static if (hasLength!R)
13222             {
13223                 if (!data.empty)
13224                 {
13225                     data.popFront;
13226                 }
13227                 else
13228                 {
13229                     --padLength;
13230                 }
13231             }
13232             else
13233             {
13234                 ++consumed;
13235                 if (!data.empty)
13236                 {
13237                     data.popFront;
13238                 }
13239             }
13240         }
13241 
13242         static if (hasLength!R)
13243         {
13244             size_t length() @property
13245             {
13246                 return data.length + padLength;
13247             }
13248         }
13249 
13250         static if (isForwardRange!R)
13251         {
13252             auto save() @property
13253             {
13254                 typeof(this) result = this;
13255                 data = data.save;
13256                 return result;
13257             }
13258         }
13259 
13260         static if (isBidirectionalRange!R && hasLength!R)
13261         {
13262             auto back() @property
13263             {
13264                 assert(!empty, "Attempting to fetch the back of an empty padRight");
13265                 return padLength > 0 ? element : data.back;
13266             }
13267 
13268             void popBack()
13269             {
13270                 assert(!empty, "Attempting to popBack an empty padRight");
13271                 if (padLength > 0)
13272                 {
13273                     --padLength;
13274                 }
13275                 else
13276                 {
13277                     data.popBack;
13278                 }
13279             }
13280         }
13281 
13282         static if (isRandomAccessRange!R && hasLength!R)
13283         {
13284             E opIndex(size_t index)
13285             {
13286                 assert(index <= this.length, "Index out of bounds");
13287                 return index >= data.length ? element : data[index];
13288             }
13289         }
13290 
13291         static if (hasSlicing!R && hasLength!R)
13292         {
13293             auto opSlice(size_t a, size_t b)
13294             {
13295                 assert(
13296                     a <= b,
13297                     "Attempting to slice a padRight with a larger first argument than the second."
13298                 );
13299                 assert(
13300                     b <= length,
13301                     "Attempting to slice using an out of bounds index on a padRight"
13302                 );
13303                 return Result(
13304                     a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
13305                     element, b - a);
13306             }
13307 
13308             alias opDollar = length;
13309         }
13310 
13311         this(R r, E e, size_t n)
13312         {
13313             data = r;
13314             element = e;
13315             static if (hasLength!R)
13316             {
13317                 padLength = n > data.length ? n - data.length : 0;
13318             }
13319             else
13320             {
13321                 minLength = n;
13322             }
13323         }
13324 
13325         @disable this();
13326     }
13327 
13328     return Result(r, e, n);
13329 }
13330 
13331 ///
13332 @safe pure unittest
13333 {
13334     import std.algorithm.comparison : equal;
13335 
13336     assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
13337     assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
13338 
13339     assert("abc".padRight('_', 6).equal("abc___"));
13340 }
13341 
13342 pure @safe unittest
13343 {
13344     import std.algorithm.comparison : equal;
13345     import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
13346     import std.meta : AliasSeq;
13347 
13348     auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
13349     dchar padding = '_';
13350     assert(string_input_range.padRight(padding, 6).equal("abc___"));
13351 
13352     foreach (RangeType; AllDummyRanges)
13353     {
13354         RangeType r1;
13355         assert(r1
13356             .padRight(0, 12)
13357             .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13358         );
13359 
13360         // test if Result properly uses random access ranges
13361         static if (isRandomAccessRange!RangeType)
13362         {
13363             RangeType r3;
13364             assert(r3.padRight(0, 12)[0] == 1);
13365             assert(r3.padRight(0, 12)[2] == 3);
13366             assert(r3.padRight(0, 12)[9] == 10);
13367             assert(r3.padRight(0, 12)[10] == 0);
13368             assert(r3.padRight(0, 12)[11] == 0);
13369         }
13370 
13371         // test if Result properly uses slicing and opDollar
13372         static if (hasSlicing!RangeType)
13373         {
13374             RangeType r4;
13375             assert(r4
13376                 .padRight(0, 12)[0 .. 3]
13377                 .equal([1, 2, 3])
13378             );
13379             assert(r4
13380                 .padRight(0, 12)[0 .. 10]
13381                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13382             );
13383             assert(r4
13384                 .padRight(0, 12)[0 .. 11]
13385                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
13386             );
13387             assert(r4
13388                 .padRight(0, 12)[2 .. $]
13389                 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13390             );
13391             assert(r4
13392                 .padRight(0, 12)[0 .. $]
13393                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13394             );
13395         }
13396 
13397         // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
13398         RangeType r5;
13399         foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
13400     }
13401 }
13402 
13403 // Test nogc inference
13404 @safe @nogc pure unittest
13405 {
13406     import std.algorithm.comparison : equal;
13407 
13408     static immutable r1 = [1, 2, 3, 4];
13409     static immutable r2 = [1, 2, 3, 4, 0, 0];
13410     assert(r1.padRight(0, 6).equal(r2));
13411 }
13412 
13413 // Test back, popBack, and save
13414 @safe pure unittest
13415 {
13416     import std.algorithm.comparison : equal;
13417 
13418     auto r1 = [1, 2, 3, 4].padRight(0, 6);
13419     assert(r1.back == 0);
13420 
13421     r1.popBack;
13422     auto r2 = r1.save;
13423     assert(r1.equal([1, 2, 3, 4, 0]));
13424     assert(r2.equal([1, 2, 3, 4, 0]));
13425 
13426     r1.popBackN(2);
13427     assert(r1.back == 3);
13428     assert(r1.length == 3);
13429     assert(r2.length == 5);
13430     assert(r2.equal([1, 2, 3, 4, 0]));
13431 
13432     r2.popFront;
13433     assert(r2.length == 4);
13434     assert(r2[0] == 2);
13435     assert(r2[1] == 3);
13436     assert(r2[2] == 4);
13437     assert(r2[3] == 0);
13438     assert(r2.equal([2, 3, 4, 0]));
13439 
13440     r2.popBack;
13441     assert(r2.equal([2, 3, 4]));
13442 
13443     auto r3 = [1, 2, 3, 4].padRight(0, 6);
13444     size_t len = 0;
13445     while (!r3.empty)
13446     {
13447         ++len;
13448         r3.popBack;
13449     }
13450     assert(len == 6);
13451 }
13452 
13453 // https://issues.dlang.org/show_bug.cgi?id=19042
13454 @safe pure unittest
13455 {
13456     import std.algorithm.comparison : equal;
13457 
13458     assert([2, 5, 13].padRight(42, 10).chunks(5)
13459            .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
13460 
13461     assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
13462 }
Suggestion Box / Bug Report