1// Written in the D programming language.
2
3/**
4This module defines the notion of a range. Ranges generalize the concept of
5arrays, lists, or anything that involves sequential access. This abstraction
6enables the same set of algorithms (see $(MREF std, algorithm)) to be used
7with a vast variety of different concrete types. For example,
8a linear search algorithm such as $(REF find, std, algorithm, searching)
9works not just for arrays, but for linked-lists, input files,
10incoming network data, etc.
11
12Guides:
13
14There 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
32Submodules:
33
34This module has two submodules:
35
36The $(MREF std, range, primitives) submodule
37provides basic range functionality. It defines several templates for testing
38whether a given object is a range, what kind of range it is, and provides
39some common range operations.
40
41The $(MREF std, range, interfaces) submodule
42provides object-based interfaces for working with ranges via runtime
43polymorphism.
44
45The remainder of this module provides a rich set of range creation and
46composition 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
212Sortedness:
213
214Ranges whose elements are sorted afford better efficiency with certain
215operations. For this, the $(LREF assumeSorted) function can be used to
216construct a $(LREF SortedRange) from a pre-sorted range. The $(REF
217sort, std, algorithm, sorting) function also conveniently
218returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional
219range operations that take advantage of the fact that the range is sorted.
220
221Source: $(PHOBOSSRC std/range/package.d)
222
223License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
224
225Authors: $(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 */
230module std.range;
231
232public import std.array;
233public import std.range.interfaces;
234public import std.range.primitives;
235public import std.typecons : Flag, Yes, No;
236
237import std.internal.attributes : betterC;
238import std.meta : allSatisfy, anySatisfy, staticMap;
239import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral,
240    isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf;
241
242
243/**
244Iterates a bidirectional range backwards. The original range can be
245accessed by using the `source` property. Applying retro twice to
246the same range yields the original range.
247
248Params:
249    r = the bidirectional range to iterate backwards
250
251Returns:
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.
255See_Also:
256    $(REF reverse, std,algorithm,mutation) for mutating the source range directly.
257 */
258auto retro(Range)(Range r)
259if (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            mixin ImplementLength!source;
353        }
354
355        return Result!()(r);
356    }
357}
358
359
360///
361pure @safe nothrow @nogc unittest
362{
363    import std.algorithm.comparison : equal;
364    int[5] a = [ 1, 2, 3, 4, 5 ];
365    int[5] b = [ 5, 4, 3, 2, 1 ];
366    assert(equal(retro(a[]), b[]));
367    assert(retro(a[]).source is a[]);
368    assert(retro(retro(a[])) is a[]);
369}
370
371pure @safe nothrow unittest
372{
373    import std.algorithm.comparison : equal;
374    static assert(isBidirectionalRange!(typeof(retro("hello"))));
375    int[] a;
376    static assert(is(typeof(a) == typeof(retro(retro(a)))));
377    assert(retro(retro(a)) is a);
378    static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
379    void test(int[] input, int[] witness)
380    {
381        auto r = retro(input);
382        assert(r.front == witness.front);
383        assert(r.back == witness.back);
384        assert(equal(r, witness));
385    }
386    test([ 1 ], [ 1 ]);
387    test([ 1, 2 ], [ 2, 1 ]);
388    test([ 1, 2, 3 ], [ 3, 2, 1 ]);
389    test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
390    test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
391    test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
392
393    immutable foo = [1,2,3].idup;
394    auto r = retro(foo);
395    assert(equal(r, [3, 2, 1]));
396}
397
398pure @safe nothrow unittest
399{
400    import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
401        ReturnBy;
402
403    foreach (DummyType; AllDummyRanges)
404    {
405        static if (!isBidirectionalRange!DummyType)
406        {
407            static assert(!__traits(compiles, Retro!DummyType));
408        }
409        else
410        {
411            DummyType dummyRange;
412            dummyRange.reinit();
413
414            auto myRetro = retro(dummyRange);
415            static assert(propagatesRangeType!(typeof(myRetro), DummyType));
416            assert(myRetro.front == 10);
417            assert(myRetro.back == 1);
418            assert(myRetro.moveFront() == 10);
419            assert(myRetro.moveBack() == 1);
420
421            static if (isRandomAccessRange!DummyType && hasLength!DummyType)
422            {
423                assert(myRetro[0] == myRetro.front);
424                assert(myRetro.moveAt(2) == 8);
425
426                static if (DummyType.r == ReturnBy.Reference)
427                {
428                    {
429                        myRetro[9]++;
430                        scope(exit) myRetro[9]--;
431                        assert(dummyRange[0] == 2);
432                        myRetro.front++;
433                        scope(exit) myRetro.front--;
434                        assert(myRetro.front == 11);
435                        myRetro.back++;
436                        scope(exit) myRetro.back--;
437                        assert(myRetro.back == 3);
438                    }
439
440                    {
441                        myRetro.front = 0xFF;
442                        scope(exit) myRetro.front = 10;
443                        assert(dummyRange.back == 0xFF);
444
445                        myRetro.back = 0xBB;
446                        scope(exit) myRetro.back = 1;
447                        assert(dummyRange.front == 0xBB);
448
449                        myRetro[1] = 11;
450                        scope(exit) myRetro[1] = 8;
451                        assert(dummyRange[8] == 11);
452                    }
453                }
454            }
455        }
456    }
457}
458
459pure @safe nothrow @nogc unittest
460{
461    import std.algorithm.comparison : equal;
462    auto LL = iota(1L, 4L);
463    auto r = retro(LL);
464    long[3] excepted = [3, 2, 1];
465    assert(equal(r, excepted[]));
466}
467
468// https://issues.dlang.org/show_bug.cgi?id=12662
469pure @safe nothrow @nogc unittest
470{
471    int[3] src = [1,2,3];
472    int[] data = src[];
473    foreach_reverse (x; data) {}
474    foreach (x; data.retro) {}
475}
476
477
478/**
479Iterates range `r` with stride `n`. If the range is a
480random-access range, moves by indexing into the range; otherwise,
481moves by successive calls to `popFront`. Applying stride twice to
482the same range results in a stride with a step that is the
483product of the two applications. It is an error for `n` to be 0.
484
485Params:
486    r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over
487    n = the number of elements to skip over
488
489Returns:
490    At minimum, an input range. The resulting range will adopt the
491    range primitives of the underlying range as long as
492    $(REF hasLength, std,range,primitives) is `true`.
493 */
494auto stride(Range)(Range r, size_t n)
495if (isInputRange!(Unqual!Range))
496in
497{
498    assert(n != 0, "stride cannot have step zero.");
499}
500do
501{
502    import std.algorithm.comparison : min;
503
504    static if (is(typeof(stride(r.source, n)) == Range))
505    {
506        // stride(stride(r, n1), n2) is stride(r, n1 * n2)
507        return stride(r.source, r._n * n);
508    }
509    else
510    {
511        static struct Result
512        {
513            private alias R = Unqual!Range;
514            public R source;
515            private size_t _n;
516
517            // Chop off the slack elements at the end
518            static if (hasLength!R &&
519                    (isRandomAccessRange!R && hasSlicing!R
520                            || isBidirectionalRange!R))
521                private void eliminateSlackElements()
522                {
523                    auto slack = source.length % _n;
524
525                    if (slack)
526                    {
527                        slack--;
528                    }
529                    else if (!source.empty)
530                    {
531                        slack = min(_n, source.length) - 1;
532                    }
533                    else
534                    {
535                        slack = 0;
536                    }
537                    if (!slack) return;
538                    static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
539                    {
540                        source = source[0 .. source.length - slack];
541                    }
542                    else static if (isBidirectionalRange!R)
543                    {
544                        foreach (i; 0 .. slack)
545                        {
546                            source.popBack();
547                        }
548                    }
549                }
550
551            static if (isForwardRange!R)
552            {
553                @property auto save()
554                {
555                    return Result(source.save, _n);
556                }
557            }
558
559            static if (isInfinite!R)
560            {
561                enum bool empty = false;
562            }
563            else
564            {
565                @property bool empty()
566                {
567                    return source.empty;
568                }
569            }
570
571            @property auto ref front()
572            {
573                return source.front;
574            }
575
576            static if (is(typeof(.moveFront(source))))
577            {
578                ElementType!R moveFront()
579                {
580                    return source.moveFront();
581                }
582            }
583
584            static if (hasAssignableElements!R)
585            {
586                @property void front(ElementType!R val)
587                {
588                    source.front = val;
589                }
590            }
591
592            void popFront()
593            {
594                source.popFrontN(_n);
595            }
596
597            static if (isBidirectionalRange!R && hasLength!R)
598            {
599                void popBack()
600                {
601                    popBackN(source, _n);
602                }
603
604                @property auto ref back()
605                {
606                    eliminateSlackElements();
607                    return source.back;
608                }
609
610                static if (is(typeof(.moveBack(source))))
611                {
612                    ElementType!R moveBack()
613                    {
614                        eliminateSlackElements();
615                        return source.moveBack();
616                    }
617                }
618
619                static if (hasAssignableElements!R)
620                {
621                    @property void back(ElementType!R val)
622                    {
623                        eliminateSlackElements();
624                        source.back = val;
625                    }
626                }
627            }
628
629            static if (isRandomAccessRange!R && hasLength!R)
630            {
631                auto ref opIndex(size_t n)
632                {
633                    return source[_n * n];
634                }
635
636                /**
637                   Forwards to $(D moveAt(source, n)).
638                */
639                static if (is(typeof(source.moveAt(0))))
640                {
641                    ElementType!R moveAt(size_t n)
642                    {
643                        return source.moveAt(_n * n);
644                    }
645                }
646
647                static if (hasAssignableElements!R)
648                {
649                    void opIndexAssign(ElementType!R val, size_t n)
650                    {
651                        source[_n * n] = val;
652                    }
653                }
654            }
655
656            static if (hasSlicing!R && hasLength!R)
657                typeof(this) opSlice(size_t lower, size_t upper)
658                {
659                    assert(upper >= lower && upper <= length,
660                        "Attempt to get out-of-bounds slice of `stride` range");
661                    immutable translatedUpper = (upper == 0) ? 0 :
662                        (upper * _n - (_n - 1));
663                    immutable translatedLower = min(lower * _n, translatedUpper);
664
665                    assert(translatedLower <= translatedUpper,
666                        "Overflow when calculating slice of `stride` range");
667
668                    return typeof(this)(source[translatedLower .. translatedUpper], _n);
669                }
670
671            static if (hasLength!R)
672            {
673                @property auto length()
674                {
675                    return (source.length + _n - 1) / _n;
676                }
677
678                alias opDollar = length;
679            }
680        }
681        return Result(r, n);
682    }
683}
684
685///
686pure @safe nothrow unittest
687{
688    import std.algorithm.comparison : equal;
689
690    int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
691    assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
692    assert(stride(stride(a, 2), 3) == stride(a, 6));
693}
694
695pure @safe nothrow @nogc unittest
696{
697    import std.algorithm.comparison : equal;
698
699    int[4] testArr = [1,2,3,4];
700    static immutable result = [1, 3];
701    assert(equal(testArr[].stride(2), result));
702}
703
704debug pure nothrow @system unittest
705{//check the contract
706    int[4] testArr = [1,2,3,4];
707    bool passed = false;
708    scope (success) assert(passed);
709    import core.exception : AssertError;
710    //std.exception.assertThrown won't do because it can't infer nothrow
711    // https://issues.dlang.org/show_bug.cgi?id=12647
712    try
713    {
714        auto unused = testArr[].stride(0);
715    }
716    catch (AssertError unused)
717    {
718        passed = true;
719    }
720}
721
722pure @safe nothrow unittest
723{
724    import std.algorithm.comparison : equal;
725    import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
726        ReturnBy;
727
728    static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
729    void test(size_t n, int[] input, int[] witness)
730    {
731        assert(equal(stride(input, n), witness));
732    }
733    test(1, [], []);
734    int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
735    assert(stride(stride(arr, 2), 3) is stride(arr, 6));
736    test(1, arr, arr);
737    test(2, arr, [1, 3, 5, 7, 9]);
738    test(3, arr, [1, 4, 7, 10]);
739    test(4, arr, [1, 5, 9]);
740
741    // Test slicing.
742    auto s1 = stride(arr, 1);
743    assert(equal(s1[1 .. 4], [2, 3, 4]));
744    assert(s1[1 .. 4].length == 3);
745    assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
746    assert(s1[1 .. 5].length == 4);
747    assert(s1[0 .. 0].empty);
748    assert(s1[3 .. 3].empty);
749    // assert(s1[$ .. $].empty);
750    assert(s1[s1.opDollar .. s1.opDollar].empty);
751
752    auto s2 = stride(arr, 2);
753    assert(equal(s2[0 .. 2], [1,3]));
754    assert(s2[0 .. 2].length == 2);
755    assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
756    assert(s2[1 .. 5].length == 4);
757    assert(s2[0 .. 0].empty);
758    assert(s2[3 .. 3].empty);
759    // assert(s2[$ .. $].empty);
760    assert(s2[s2.opDollar .. s2.opDollar].empty);
761
762    // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035
763    auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
764    auto col = stride(m, 4);
765    assert(equal(col, [1, 1, 1]));
766    assert(equal(retro(col), [1, 1, 1]));
767
768    immutable int[] immi = [ 1, 2, 3 ];
769    static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
770
771    // Check for infiniteness propagation.
772    static assert(isInfinite!(typeof(stride(repeat(1), 3))));
773
774    foreach (DummyType; AllDummyRanges)
775    {
776        DummyType dummyRange;
777        dummyRange.reinit();
778
779        auto myStride = stride(dummyRange, 4);
780
781        // Should fail if no length and bidirectional b/c there's no way
782        // to know how much slack we have.
783        static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
784        {
785            static assert(propagatesRangeType!(typeof(myStride), DummyType));
786        }
787        assert(myStride.front == 1);
788        assert(myStride.moveFront() == 1);
789        assert(equal(myStride, [1, 5, 9]));
790
791        static if (hasLength!DummyType)
792        {
793            assert(myStride.length == 3);
794        }
795
796        static if (isBidirectionalRange!DummyType && hasLength!DummyType)
797        {
798            assert(myStride.back == 9);
799            assert(myStride.moveBack() == 9);
800        }
801
802        static if (isRandomAccessRange!DummyType && hasLength!DummyType)
803        {
804            assert(myStride[0] == 1);
805            assert(myStride[1] == 5);
806            assert(myStride.moveAt(1) == 5);
807            assert(myStride[2] == 9);
808
809            static assert(hasSlicing!(typeof(myStride)));
810        }
811
812        static if (DummyType.r == ReturnBy.Reference)
813        {
814            // Make sure reference is propagated.
815
816            {
817                myStride.front++;
818                scope(exit) myStride.front--;
819                assert(dummyRange.front == 2);
820            }
821            {
822                myStride.front = 4;
823                scope(exit) myStride.front = 1;
824                assert(dummyRange.front == 4);
825            }
826
827            static if (isBidirectionalRange!DummyType && hasLength!DummyType)
828            {
829                {
830                    myStride.back++;
831                    scope(exit) myStride.back--;
832                    assert(myStride.back == 10);
833                }
834                {
835                    myStride.back = 111;
836                    scope(exit) myStride.back = 9;
837                    assert(myStride.back == 111);
838                }
839
840                static if (isRandomAccessRange!DummyType)
841                {
842                    {
843                        myStride[1]++;
844                        scope(exit) myStride[1]--;
845                        assert(dummyRange[4] == 6);
846                    }
847                    {
848                        myStride[1] = 55;
849                        scope(exit) myStride[1] = 5;
850                        assert(dummyRange[4] == 55);
851                    }
852                }
853            }
854        }
855    }
856}
857
858pure @safe nothrow unittest
859{
860    import std.algorithm.comparison : equal;
861
862    auto LL = iota(1L, 10L);
863    auto s = stride(LL, 3);
864    assert(equal(s, [1L, 4L, 7L]));
865}
866
867/**
868Spans multiple ranges in sequence. The function `chain` takes any
869number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
870ranges may be different, but they must have the same element type. The
871result is a range that offers the `front`, `popFront`, and $(D
872empty) primitives. If all input ranges offer random access and $(D
873length), `Chain` offers them as well.
874
875If only one range is offered to `Chain` or `chain`, the $(D
876Chain) type exits the picture by aliasing itself directly to that
877range's type.
878
879Params:
880    rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together
881
882Returns:
883    An input range at minimum. If all of the ranges in `rs` provide
884    a range primitive, the returned range will also provide that range
885    primitive.
886
887See_Also: $(LREF only) to chain values to a range
888 */
889auto chain(Ranges...)(Ranges rs)
890if (Ranges.length > 0 &&
891    allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
892    !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
893{
894    static if (Ranges.length == 1)
895    {
896        return rs[0];
897    }
898    else
899    {
900        static struct Result
901        {
902        private:
903            alias R = staticMap!(Unqual, Ranges);
904            alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
905            template sameET(A)
906            {
907                enum sameET = is(.ElementType!A == RvalueElementType);
908            }
909
910            enum bool allSameType = allSatisfy!(sameET, R);
911            alias ElementType = RvalueElementType;
912
913            static if (allSameType && allSatisfy!(hasLvalueElements, R))
914            {
915                static ref RvalueElementType fixRef(ref RvalueElementType val)
916                {
917                    return val;
918                }
919            }
920            else
921            {
922                static RvalueElementType fixRef(RvalueElementType val)
923                {
924                    return val;
925                }
926            }
927
928            // This is the entire state
929            R source;
930            // TODO: use a vtable (or more) instead of linear iteration
931
932        public:
933            this(R input)
934            {
935                // Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
936                static foreach (i, v; input)
937                {
938                    source[i] = v;
939                }
940            }
941
942            import std.meta : anySatisfy;
943
944            static if (anySatisfy!(isInfinite, R))
945            {
946                // Propagate infiniteness.
947                enum bool empty = false;
948            }
949            else
950            {
951                @property bool empty()
952                {
953                    foreach (i, Unused; R)
954                    {
955                        if (!source[i].empty) return false;
956                    }
957                    return true;
958                }
959            }
960
961            static if (allSatisfy!(isForwardRange, R))
962                @property auto save()
963                {
964                    auto saveSource(size_t len)()
965                    {
966                        import std.typecons : tuple;
967                        static assert(len > 0);
968                        static if (len == 1)
969                        {
970                            return tuple(source[0].save);
971                        }
972                        else
973                        {
974                            return saveSource!(len - 1)() ~
975                                tuple(source[len - 1].save);
976                        }
977                    }
978                    return Result(saveSource!(R.length).expand);
979                }
980
981            void popFront()
982            {
983                foreach (i, Unused; R)
984                {
985                    if (source[i].empty) continue;
986                    source[i].popFront();
987                    return;
988                }
989                assert(false, "Attempt to `popFront` of empty `chain` range");
990            }
991
992            @property auto ref front()
993            {
994                foreach (i, Unused; R)
995                {
996                    if (source[i].empty) continue;
997                    return fixRef(source[i].front);
998                }
999                assert(false, "Attempt to get `front` of empty `chain` range");
1000            }
1001
1002            static if (allSameType && allSatisfy!(hasAssignableElements, R))
1003            {
1004                // @@@BUG@@@
1005                //@property void front(T)(T v) if (is(T : RvalueElementType))
1006
1007                @property void front(RvalueElementType v)
1008                {
1009                    foreach (i, Unused; R)
1010                    {
1011                        if (source[i].empty) continue;
1012                        source[i].front = v;
1013                        return;
1014                    }
1015                    assert(false, "Attempt to set `front` of empty `chain` range");
1016                }
1017            }
1018
1019            static if (allSatisfy!(hasMobileElements, R))
1020            {
1021                RvalueElementType moveFront()
1022                {
1023                    foreach (i, Unused; R)
1024                    {
1025                        if (source[i].empty) continue;
1026                        return source[i].moveFront();
1027                    }
1028                    assert(false, "Attempt to `moveFront` of empty `chain` range");
1029                }
1030            }
1031
1032            static if (allSatisfy!(isBidirectionalRange, R))
1033            {
1034                @property auto ref back()
1035                {
1036                    foreach_reverse (i, Unused; R)
1037                    {
1038                        if (source[i].empty) continue;
1039                        return fixRef(source[i].back);
1040                    }
1041                    assert(false, "Attempt to get `back` of empty `chain` range");
1042                }
1043
1044                void popBack()
1045                {
1046                    foreach_reverse (i, Unused; R)
1047                    {
1048                        if (source[i].empty) continue;
1049                        source[i].popBack();
1050                        return;
1051                    }
1052                    assert(false, "Attempt to `popBack` of empty `chain` range");
1053                }
1054
1055                static if (allSatisfy!(hasMobileElements, R))
1056                {
1057                    RvalueElementType moveBack()
1058                    {
1059                        foreach_reverse (i, Unused; R)
1060                        {
1061                            if (source[i].empty) continue;
1062                            return source[i].moveBack();
1063                        }
1064                        assert(false, "Attempt to `moveBack` of empty `chain` range");
1065                    }
1066                }
1067
1068                static if (allSameType && allSatisfy!(hasAssignableElements, R))
1069                {
1070                    @property void back(RvalueElementType v)
1071                    {
1072                        foreach_reverse (i, Unused; R)
1073                        {
1074                            if (source[i].empty) continue;
1075                            source[i].back = v;
1076                            return;
1077                        }
1078                        assert(false, "Attempt to set `back` of empty `chain` range");
1079                    }
1080                }
1081            }
1082
1083            static if (allSatisfy!(hasLength, R))
1084            {
1085                @property size_t length()
1086                {
1087                    size_t result;
1088                    foreach (i, Unused; R)
1089                    {
1090                        result += source[i].length;
1091                    }
1092                    return result;
1093                }
1094
1095                alias opDollar = length;
1096            }
1097
1098            static if (allSatisfy!(isRandomAccessRange, R))
1099            {
1100                auto ref opIndex(size_t index)
1101                {
1102                    foreach (i, Range; R)
1103                    {
1104                        static if (isInfinite!(Range))
1105                        {
1106                            return source[i][index];
1107                        }
1108                        else
1109                        {
1110                            immutable length = source[i].length;
1111                            if (index < length) return fixRef(source[i][index]);
1112                            index -= length;
1113                        }
1114                    }
1115                    assert(false, "Attempt to access out-of-bounds index of `chain` range");
1116                }
1117
1118                static if (allSatisfy!(hasMobileElements, R))
1119                {
1120                    RvalueElementType moveAt(size_t index)
1121                    {
1122                        foreach (i, Range; R)
1123                        {
1124                            static if (isInfinite!(Range))
1125                            {
1126                                return source[i].moveAt(index);
1127                            }
1128                            else
1129                            {
1130                                immutable length = source[i].length;
1131                                if (index < length) return source[i].moveAt(index);
1132                                index -= length;
1133                            }
1134                        }
1135                        assert(false, "Attempt to move out-of-bounds index of `chain` range");
1136                    }
1137                }
1138
1139                static if (allSameType && allSatisfy!(hasAssignableElements, R))
1140                    void opIndexAssign(ElementType v, size_t index)
1141                    {
1142                        foreach (i, Range; R)
1143                        {
1144                            static if (isInfinite!(Range))
1145                            {
1146                                source[i][index] = v;
1147                            }
1148                            else
1149                            {
1150                                immutable length = source[i].length;
1151                                if (index < length)
1152                                {
1153                                    source[i][index] = v;
1154                                    return;
1155                                }
1156                                index -= length;
1157                            }
1158                        }
1159                        assert(false, "Attempt to write out-of-bounds index of `chain` range");
1160                    }
1161            }
1162
1163            static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
1164                auto opSlice(size_t begin, size_t end) return scope
1165                {
1166                    auto result = this;
1167                    foreach (i, Unused; R)
1168                    {
1169                        immutable len = result.source[i].length;
1170                        if (len < begin)
1171                        {
1172                            result.source[i] = result.source[i]
1173                                [len .. len];
1174                            begin -= len;
1175                        }
1176                        else
1177                        {
1178                            result.source[i] = result.source[i]
1179                                [begin .. len];
1180                            break;
1181                        }
1182                    }
1183                    auto cut = length;
1184                    cut = cut <= end ? 0 : cut - end;
1185                    foreach_reverse (i, Unused; R)
1186                    {
1187                        immutable len = result.source[i].length;
1188                        if (cut > len)
1189                        {
1190                            result.source[i] = result.source[i]
1191                                [0 .. 0];
1192                            cut -= len;
1193                        }
1194                        else
1195                        {
1196                            result.source[i] = result.source[i]
1197                                [0 .. len - cut];
1198                            break;
1199                        }
1200                    }
1201                    return result;
1202                }
1203        }
1204        return Result(rs);
1205    }
1206}
1207
1208///
1209pure @safe nothrow unittest
1210{
1211    import std.algorithm.comparison : equal;
1212
1213    int[] arr1 = [ 1, 2, 3, 4 ];
1214    int[] arr2 = [ 5, 6 ];
1215    int[] arr3 = [ 7 ];
1216    auto s = chain(arr1, arr2, arr3);
1217    assert(s.length == 7);
1218    assert(s[5] == 6);
1219    assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1220}
1221
1222/**
1223 * Range primitives are carried over to the returned range if
1224 * all of the ranges provide them
1225 */
1226pure @safe nothrow unittest
1227{
1228    import std.algorithm.comparison : equal;
1229    import std.algorithm.sorting : sort;
1230
1231    int[] arr1 = [5, 2, 8];
1232    int[] arr2 = [3, 7, 9];
1233    int[] arr3 = [1, 4, 6];
1234
1235    // in-place sorting across all of the arrays
1236    auto s = arr1.chain(arr2, arr3).sort;
1237
1238    assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1239    assert(arr1.equal([1, 2, 3]));
1240    assert(arr2.equal([4, 5, 6]));
1241    assert(arr3.equal([7, 8, 9]));
1242}
1243
1244/**
1245Due to safe type promotion in D, chaining together different
1246character ranges results in a `uint` range.
1247
1248Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf),
1249and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges
1250to get the type you need.
1251 */
1252pure @safe nothrow unittest
1253{
1254    import std.utf : byChar, byCodeUnit;
1255
1256    auto s1 = "string one";
1257    auto s2 = "string two";
1258    // s1 and s2 front is dchar because of auto-decoding
1259    static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
1260
1261    auto r1 = s1.chain(s2);
1262    // chains of ranges of the same character type give that same type
1263    static assert(is(typeof(r1.front) == dchar));
1264
1265    auto s3 = "string three".byCodeUnit;
1266    static assert(is(typeof(s3.front) == immutable char));
1267    auto r2 = s1.chain(s3);
1268    // chaining ranges of mixed character types gives `dchar`
1269    static assert(is(typeof(r2.front) == dchar));
1270
1271    // use byChar on character ranges to correctly convert them to UTF-8
1272    auto r3 = s1.byChar.chain(s3);
1273    static assert(is(typeof(r3.front) == immutable char));
1274}
1275
1276pure @safe nothrow unittest
1277{
1278    import std.algorithm.comparison : equal;
1279    import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1280                                          propagatesRangeType;
1281
1282    {
1283        int[] arr1 = [ 1, 2, 3, 4 ];
1284        int[] arr2 = [ 5, 6 ];
1285        int[] arr3 = [ 7 ];
1286        int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1287        auto s1 = chain(arr1);
1288        static assert(isRandomAccessRange!(typeof(s1)));
1289        auto s2 = chain(arr1, arr2);
1290        static assert(isBidirectionalRange!(typeof(s2)));
1291        static assert(isRandomAccessRange!(typeof(s2)));
1292        s2.front = 1;
1293        auto s = chain(arr1, arr2, arr3);
1294        assert(s[5] == 6);
1295        assert(equal(s, witness));
1296        assert(s[5] == 6);
1297    }
1298    {
1299        int[] arr1 = [ 1, 2, 3, 4 ];
1300        int[] witness = [ 1, 2, 3, 4 ];
1301        assert(equal(chain(arr1), witness));
1302    }
1303    {
1304        uint[] foo = [1,2,3,4,5];
1305        uint[] bar = [1,2,3,4,5];
1306        auto c = chain(foo, bar);
1307        c[3] = 42;
1308        assert(c[3] == 42);
1309        assert(c.moveFront() == 1);
1310        assert(c.moveBack() == 5);
1311        assert(c.moveAt(4) == 5);
1312        assert(c.moveAt(5) == 1);
1313    }
1314
1315
1316    // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed.
1317    // elements are mutable.
1318    assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1319
1320    // Test the case where infinite ranges are present.
1321    auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1322    assert(inf[0] == 0);
1323    assert(inf[3] == 4);
1324    assert(inf[6] == 4);
1325    assert(inf[7] == 5);
1326    static assert(isInfinite!(typeof(inf)));
1327
1328    immutable int[] immi = [ 1, 2, 3 ];
1329    immutable float[] immf = [ 1, 2, 3 ];
1330    static assert(is(typeof(chain(immi, immf))));
1331
1332    // Check that chain at least instantiates and compiles with every possible
1333    // pair of DummyRange types, in either order.
1334
1335    foreach (DummyType1; AllDummyRanges)
1336    (){ // workaround slow optimizations for large functions
1337        // https://issues.dlang.org/show_bug.cgi?id=2396
1338        DummyType1 dummy1;
1339        foreach (DummyType2; AllDummyRanges)
1340        {
1341            DummyType2 dummy2;
1342            auto myChain = chain(dummy1, dummy2);
1343
1344            static assert(
1345                propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1346            );
1347
1348            assert(myChain.front == 1);
1349            foreach (i; 0 .. dummyLength)
1350            {
1351                myChain.popFront();
1352            }
1353            assert(myChain.front == 1);
1354
1355            static if (isBidirectionalRange!DummyType1 &&
1356                      isBidirectionalRange!DummyType2) {
1357                assert(myChain.back == 10);
1358            }
1359
1360            static if (isRandomAccessRange!DummyType1 &&
1361                      isRandomAccessRange!DummyType2) {
1362                assert(myChain[0] == 1);
1363            }
1364
1365            static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1366            {
1367                static assert(hasLvalueElements!(typeof(myChain)));
1368            }
1369            else
1370            {
1371                static assert(!hasLvalueElements!(typeof(myChain)));
1372            }
1373        }
1374    }();
1375}
1376
1377pure @safe nothrow @nogc unittest
1378{
1379    class Foo{}
1380    immutable(Foo)[] a;
1381    immutable(Foo)[] b;
1382    assert(chain(a, b).empty);
1383}
1384
1385// https://issues.dlang.org/show_bug.cgi?id=18657
1386pure @safe unittest
1387{
1388    import std.algorithm.comparison : equal;
1389    string s = "foo";
1390    auto r = refRange(&s).chain("bar");
1391    assert(equal(r.save, "foobar"));
1392    assert(equal(r, "foobar"));
1393}
1394
1395/**
1396Choose one of two ranges at runtime depending on a Boolean condition.
1397
1398The ranges may be different, but they must have compatible element types (i.e.
1399`CommonType` must exist for the two element types). The result is a range
1400that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D
1401R1) is a random-access range and `R2` is a forward range).
1402
1403Params:
1404    condition = which range to choose: `r1` if `true`, `r2` otherwise
1405    r1 = the "true" range
1406    r2 = the "false" range
1407
1408Returns:
1409    A range type dependent on `R1` and `R2`.
1410 */
1411auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
1412if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1413    !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1414{
1415    size_t choice = condition? 0: 1;
1416    return ChooseResult!(R1, R2)(choice, r1, r2);
1417}
1418
1419///
1420@safe nothrow pure @nogc unittest
1421{
1422    import std.algorithm.comparison : equal;
1423    import std.algorithm.iteration : filter, map;
1424
1425    auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
1426    auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
1427
1428    // choose() is primarily useful when you need to select one of two ranges
1429    // with different types at runtime.
1430    static assert(!is(typeof(data1) == typeof(data2)));
1431
1432    auto chooseRange(bool pickFirst)
1433    {
1434        // The returned range is a common wrapper type that can be used for
1435        // returning or storing either range without running into a type error.
1436        return choose(pickFirst, data1, data2);
1437
1438        // Simply returning the chosen range without using choose() does not
1439        // work, because map() and filter() return different types.
1440        //return pickFirst ? data1 : data2; // does not compile
1441    }
1442
1443    auto result = chooseRange(true);
1444    assert(result.equal(only(1, 2, 4)));
1445
1446    result = chooseRange(false);
1447    assert(result.equal(only(6, 7, 8, 9)));
1448}
1449
1450
1451private struct ChooseResult(Ranges...)
1452{
1453    import std.meta : aliasSeqOf, ApplyLeft;
1454    import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor,
1455        lvalueOf;
1456
1457    private union
1458    {
1459        Ranges rs;
1460    }
1461    private size_t chosenI;
1462
1463    private static auto ref actOnChosen(alias foo, ExtraArgs ...)
1464        (ref ChooseResult r, auto ref ExtraArgs extraArgs)
1465    {
1466        ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1467
1468        switch (r.chosenI)
1469        {
1470            static foreach (candI; 0 .. rs.length)
1471            {
1472                case candI: return foo(getI!candI(r), extraArgs);
1473            }
1474
1475            default: assert(false);
1476        }
1477    }
1478
1479    // @trusted because of assignment of r which overlap each other
1480    this(size_t chosen, return scope Ranges rs) @trusted
1481    {
1482        import core.lifetime : emplace;
1483
1484        // This should be the only place chosenI is ever assigned
1485        // independently
1486        this.chosenI = chosen;
1487
1488        // Otherwise the compiler will complain about skipping these fields
1489        static foreach (i; 0 .. rs.length)
1490        {
1491            this.rs[i] = Ranges[i].init;
1492        }
1493
1494        // The relevant field needs to be initialized last so it will overwrite
1495        // the other initializations and not the other way around.
1496        sw: switch (chosenI)
1497        {
1498            static foreach (i; 0 .. rs.length)
1499            {
1500                case i:
1501                emplace(&this.rs[i], rs[i]);
1502                break sw;
1503            }
1504
1505            default: assert(false);
1506        }
1507    }
1508
1509    // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/)
1510    // without this overload the regular constructor would invert the meaning of
1511    // the boolean
1512    static if (rs.length == 2)
1513    pragma(inline, true)
1514    deprecated("Call with size_t (0 = first), or use the choose function")
1515    this(bool firstChosen, Ranges rs)
1516    {
1517        import core.lifetime : move;
1518        this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move);
1519    }
1520
1521    void opAssign(ChooseResult r)
1522    {
1523        ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1524
1525        static if (anySatisfy!(hasElaborateDestructor, Ranges))
1526            if (chosenI != r.chosenI)
1527        {
1528            // destroy the current item
1529            actOnChosen!((ref r) => destroy(r))(this);
1530        }
1531        chosenI = r.chosenI;
1532
1533        sw: switch (chosenI)
1534        {
1535            static foreach (candI; 0 .. rs.length)
1536            {
1537                case candI: getI!candI(this) = getI!candI(r);
1538                break sw;
1539            }
1540
1541            default: assert(false);
1542        }
1543    }
1544
1545    // Carefully defined postblit to postblit the appropriate range
1546    static if (anySatisfy!(hasElaborateCopyConstructor, Ranges))
1547    this(this)
1548    {
1549        actOnChosen!((ref r) {
1550                static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit();
1551            })(this);
1552    }
1553
1554    static if (anySatisfy!(hasElaborateDestructor, Ranges))
1555    ~this()
1556    {
1557        actOnChosen!((ref r) => destroy(r))(this);
1558    }
1559
1560    // Propagate infiniteness.
1561    static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false;
1562    else @property bool empty()
1563    {
1564        return actOnChosen!(r => r.empty)(this);
1565    }
1566
1567    @property auto ref front()
1568    {
1569        static auto ref getFront(R)(ref R r) { return r.front; }
1570        return actOnChosen!getFront(this);
1571    }
1572
1573    void popFront()
1574    {
1575        return actOnChosen!((ref r) { r.popFront; })(this);
1576    }
1577
1578    static if (allSatisfy!(isForwardRange, Ranges))
1579    @property auto save() // return scope inferred
1580    {
1581        auto saveOrInit(size_t i)()
1582        {
1583            ref getI() @trusted { return rs[i]; }
1584            if (i == chosenI) return getI().save;
1585            else return Ranges[i].init;
1586        }
1587
1588        return typeof(this)(chosenI, staticMap!(saveOrInit,
1589            aliasSeqOf!(rs.length.iota)));
1590    }
1591
1592    template front(T)
1593    {
1594        private enum overloadValidFor(alias r) = is(typeof(r.front = T.init));
1595
1596        static if (allSatisfy!(overloadValidFor, rs))
1597        void front(T v)
1598        {
1599            actOnChosen!((ref r, T v) { r.front = v; })(this, v);
1600        }
1601    }
1602
1603    static if (allSatisfy!(hasMobileElements, Ranges))
1604    auto moveFront()
1605    {
1606        return actOnChosen!((ref r) => r.moveFront)(this);
1607    }
1608
1609    static if (allSatisfy!(isBidirectionalRange, Ranges))
1610    {
1611        @property auto ref back()
1612        {
1613            static auto ref getBack(R)(ref R r) { return r.back; }
1614            return actOnChosen!getBack(this);
1615        }
1616
1617        void popBack()
1618        {
1619            actOnChosen!((ref r) { r.popBack; })(this);
1620        }
1621
1622        static if (allSatisfy!(hasMobileElements, Ranges))
1623        auto moveBack()
1624        {
1625            return actOnChosen!((ref r) => r.moveBack)(this);
1626        }
1627
1628        template back(T)
1629        {
1630            private enum overloadValidFor(alias r) = is(typeof(r.back = T.init));
1631
1632            static if (allSatisfy!(overloadValidFor, rs))
1633            void back(T v)
1634            {
1635                actOnChosen!((ref r, T v) { r.back = v; })(this, v);
1636            }
1637        }
1638    }
1639
1640    static if (allSatisfy!(hasLength, Ranges))
1641    {
1642        @property size_t length()
1643        {
1644            return actOnChosen!(r => r.length)(this);
1645        }
1646        alias opDollar = length;
1647    }
1648
1649    static if (allSatisfy!(isRandomAccessRange, Ranges))
1650    {
1651        auto ref opIndex(size_t index)
1652        {
1653            static auto ref get(R)(ref R r, size_t index) { return r[index]; }
1654            return actOnChosen!get(this, index);
1655        }
1656
1657        static if (allSatisfy!(hasMobileElements, Ranges))
1658            auto moveAt(size_t index)
1659            {
1660                return actOnChosen!((ref r, size_t index) => r.moveAt(index))
1661                    (this, index);
1662            }
1663
1664        private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init));
1665
1666        template opIndexAssign(T)
1667        if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges))
1668        {
1669            void opIndexAssign(T v, size_t index)
1670            {
1671                return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
1672                    (this, index, v);
1673            }
1674        }
1675    }
1676
1677    static if (allSatisfy!(hasSlicing, Ranges))
1678    auto opSlice(size_t begin, size_t end)
1679    {
1680        alias Slice(R) = typeof(R.init[0 .. 1]);
1681        alias Slices = staticMap!(Slice, Ranges);
1682
1683        auto sliceOrInit(size_t i)()
1684        {
1685            ref getI() @trusted { return rs[i]; }
1686            return i == chosenI? getI()[begin .. end]: Slices[i].init;
1687        }
1688
1689        return chooseAmong(chosenI, staticMap!(sliceOrInit,
1690            aliasSeqOf!(rs.length.iota)));
1691    }
1692}
1693
1694// https://issues.dlang.org/show_bug.cgi?id=18657
1695pure @safe unittest
1696{
1697    import std.algorithm.comparison : equal;
1698    string s = "foo";
1699    auto r = choose(true, refRange(&s), "bar");
1700    assert(equal(r.save, "foo"));
1701    assert(equal(r, "foo"));
1702}
1703
1704@safe unittest
1705{
1706    static void* p;
1707    static struct R
1708    {
1709        void* q;
1710        int front;
1711        bool empty;
1712        void popFront() {}
1713        // `p = q;` is only there to prevent inference of `scope return`.
1714        @property @safe R save() { p = q; return this; }
1715
1716    }
1717    R r;
1718    choose(true, r, r).save;
1719}
1720
1721// Make sure ChooseResult.save doesn't trust @system user code.
1722@system unittest // copy is @system
1723{
1724    static struct R
1725    {
1726        int front;
1727        bool empty;
1728        void popFront() {}
1729        this(this) @system {}
1730        @property R save() { return R(front, empty); }
1731    }
1732    choose(true, R(), R()).save;
1733    choose(true, [0], R()).save;
1734    choose(true, R(), [0]).save;
1735}
1736
1737@safe unittest // copy is @system
1738{
1739    static struct R
1740    {
1741        int front;
1742        bool empty;
1743        void popFront() {}
1744        this(this) @system {}
1745        @property R save() { return R(front, empty); }
1746    }
1747    static assert(!__traits(compiles, choose(true, R(), R()).save));
1748    static assert(!__traits(compiles, choose(true, [0], R()).save));
1749    static assert(!__traits(compiles, choose(true, R(), [0]).save));
1750}
1751
1752@system unittest // .save is @system
1753{
1754    static struct R
1755    {
1756        int front;
1757        bool empty;
1758        void popFront() {}
1759        @property R save() @system { return this; }
1760    }
1761    choose(true, R(), R()).save;
1762    choose(true, [0], R()).save;
1763    choose(true, R(), [0]).save;
1764}
1765
1766@safe unittest // .save is @system
1767{
1768    static struct R
1769    {
1770        int front;
1771        bool empty;
1772        void popFront() {}
1773        @property R save() @system { return this; }
1774    }
1775    static assert(!__traits(compiles, choose(true, R(), R()).save));
1776    static assert(!__traits(compiles, choose(true, [0], R()).save));
1777    static assert(!__traits(compiles, choose(true, R(), [0]).save));
1778}
1779
1780//https://issues.dlang.org/show_bug.cgi?id=19738
1781@safe nothrow pure @nogc unittest
1782{
1783    static struct EvilRange
1784    {
1785        enum empty = true;
1786        int front;
1787        void popFront() @safe {}
1788        auto opAssign(const ref EvilRange other)
1789        {
1790            *(cast(uint*) 0xcafebabe) = 0xdeadbeef;
1791            return this;
1792        }
1793    }
1794
1795    static assert(!__traits(compiles, () @safe
1796    {
1797        auto c1 = choose(true, EvilRange(), EvilRange());
1798        auto c2 = c1;
1799        c1 = c2;
1800    }));
1801}
1802
1803
1804// https://issues.dlang.org/show_bug.cgi?id=20495
1805@safe unittest
1806{
1807    static struct KillableRange
1808    {
1809        int *item;
1810        ref int front() { return *item; }
1811        bool empty() { return *item > 10; }
1812        void popFront() { ++(*item); }
1813        this(this)
1814        {
1815            assert(item is null || cast(size_t) item > 1000);
1816            item = new int(*item);
1817        }
1818        KillableRange save() { return this; }
1819    }
1820
1821    auto kr = KillableRange(new int(1));
1822    int[] x = [1,2,3,4,5]; // length is first
1823
1824    auto chosen = choose(true, x, kr);
1825    auto chosen2 = chosen.save;
1826}
1827
1828/**
1829Choose one of multiple ranges at runtime.
1830
1831The ranges may be different, but they must have compatible element types. The
1832result is a range that offers the weakest capabilities of all `Ranges`.
1833
1834Params:
1835    index = which range to choose, must be less than the number of ranges
1836    rs = two or more ranges
1837
1838Returns:
1839    The indexed range. If rs consists of only one range, the return type is an
1840    alias of that range's type.
1841 */
1842auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
1843if (Ranges.length >= 2
1844        && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
1845        && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
1846{
1847        return ChooseResult!Ranges(index, rs);
1848}
1849
1850///
1851@safe nothrow pure @nogc unittest
1852{
1853    auto test()
1854    {
1855        import std.algorithm.comparison : equal;
1856
1857        int[4] sarr1 = [1, 2, 3, 4];
1858        int[2] sarr2 = [5, 6];
1859        int[1] sarr3 = [7];
1860        auto arr1 = sarr1[];
1861        auto arr2 = sarr2[];
1862        auto arr3 = sarr3[];
1863
1864        {
1865            auto s = chooseAmong(0, arr1, arr2, arr3);
1866            auto t = s.save;
1867            assert(s.length == 4);
1868            assert(s[2] == 3);
1869            s.popFront();
1870            assert(equal(t, only(1, 2, 3, 4)));
1871        }
1872        {
1873            auto s = chooseAmong(1, arr1, arr2, arr3);
1874            assert(s.length == 2);
1875            s.front = 8;
1876            assert(equal(s, only(8, 6)));
1877        }
1878        {
1879            auto s = chooseAmong(1, arr1, arr2, arr3);
1880            assert(s.length == 2);
1881            s[1] = 9;
1882            assert(equal(s, only(8, 9)));
1883        }
1884        {
1885            auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
1886            assert(s.length == 2);
1887            assert(equal(s, only(2, 3)));
1888        }
1889        {
1890            auto s = chooseAmong(0, arr1, arr2, arr3);
1891            assert(s.length == 4);
1892            assert(s.back == 4);
1893            s.popBack();
1894            s.back = 5;
1895            assert(equal(s, only(1, 2, 5)));
1896            s.back = 3;
1897            assert(equal(s, only(1, 2, 3)));
1898        }
1899        {
1900            uint[5] foo = [1, 2, 3, 4, 5];
1901            uint[5] bar = [6, 7, 8, 9, 10];
1902            auto c = chooseAmong(1, foo[], bar[]);
1903            assert(c[3] == 9);
1904            c[3] = 42;
1905            assert(c[3] == 42);
1906            assert(c.moveFront() == 6);
1907            assert(c.moveBack() == 10);
1908            assert(c.moveAt(4) == 10);
1909        }
1910        {
1911            import std.range : cycle;
1912            auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
1913            assert(isInfinite!(typeof(s)));
1914            assert(!s.empty);
1915            assert(s[100] == 8);
1916            assert(s[101] == 9);
1917            assert(s[0 .. 3].equal(only(8, 9, 8)));
1918        }
1919        return 0;
1920    }
1921    // works at runtime
1922    auto a = test();
1923    // and at compile time
1924    static b = test();
1925}
1926
1927@safe nothrow pure @nogc unittest
1928{
1929    int[3] a = [1, 2, 3];
1930    long[3] b = [4, 5, 6];
1931    auto c = chooseAmong(0, a[], b[]);
1932    c[0] = 42;
1933    assert(c[0] == 42);
1934}
1935
1936@safe nothrow pure @nogc unittest
1937{
1938    static struct RefAccessRange
1939    {
1940        int[] r;
1941        ref front() @property { return r[0]; }
1942        ref back() @property { return r[$ - 1]; }
1943        void popFront() { r = r[1 .. $]; }
1944        void popBack() { r = r[0 .. $ - 1]; }
1945        auto empty() @property { return r.empty; }
1946        ref opIndex(size_t i) { return r[i]; }
1947        auto length() @property { return r.length; }
1948        alias opDollar = length;
1949        auto save() { return this; }
1950    }
1951    static assert(isRandomAccessRange!RefAccessRange);
1952    static assert(isRandomAccessRange!RefAccessRange);
1953    int[4] a = [4, 3, 2, 1];
1954    int[2] b = [6, 5];
1955    auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[]));
1956
1957    void refFunc(ref int a, int target) { assert(a == target); }
1958
1959    refFunc(c[2], 2);
1960    refFunc(c.front, 4);
1961    refFunc(c.back, 1);
1962}
1963
1964
1965/**
1966$(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`,
1967then `r3.front`, after which it pops off one element from each and
1968continues again from `r1`. For example, if two ranges are involved,
1969it alternately yields elements off the two ranges. `roundRobin`
1970stops after it has consumed all ranges (skipping over the ones that
1971finish early).
1972 */
1973auto roundRobin(Rs...)(Rs rs)
1974if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
1975{
1976    struct Result
1977    {
1978        import std.conv : to;
1979
1980        public Rs source;
1981        private size_t _current = size_t.max;
1982
1983        @property bool empty()
1984        {
1985            foreach (i, Unused; Rs)
1986            {
1987                if (!source[i].empty) return false;
1988            }
1989            return true;
1990        }
1991
1992        @property auto ref front()
1993        {
1994            final switch (_current)
1995            {
1996                foreach (i, R; Rs)
1997                {
1998                    case i:
1999                        assert(
2000                            !source[i].empty,
2001                            "Attempting to fetch the front of an empty roundRobin"
2002                        );
2003                        return source[i].front;
2004                }
2005            }
2006            assert(0);
2007        }
2008
2009        void popFront()
2010        {
2011            final switch (_current)
2012            {
2013                foreach (i, R; Rs)
2014                {
2015                    case i:
2016                        source[i].popFront();
2017                        break;
2018                }
2019            }
2020
2021            auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
2022            final switch (next)
2023            {
2024                foreach (i, R; Rs)
2025                {
2026                    case i:
2027                        if (!source[i].empty)
2028                        {
2029                            _current = i;
2030                            return;
2031                        }
2032                        if (i == _current)
2033                        {
2034                            _current = _current.max;
2035                            return;
2036                        }
2037                        goto case (i + 1) % Rs.length;
2038                }
2039            }
2040        }
2041
2042        static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
2043            @property auto save()
2044            {
2045                auto saveSource(size_t len)()
2046                {
2047                    import std.typecons : tuple;
2048                    static assert(len > 0);
2049                    static if (len == 1)
2050                    {
2051                        return tuple(source[0].save);
2052                    }
2053                    else
2054                    {
2055                        return saveSource!(len - 1)() ~
2056                            tuple(source[len - 1].save);
2057                    }
2058                }
2059                return Result(saveSource!(Rs.length).expand, _current);
2060            }
2061
2062        static if (allSatisfy!(hasLength, Rs))
2063        {
2064            @property size_t length()
2065            {
2066                size_t result;
2067                foreach (i, R; Rs)
2068                {
2069                    result += source[i].length;
2070                }
2071                return result;
2072            }
2073
2074            alias opDollar = length;
2075        }
2076    }
2077
2078    return Result(rs, 0);
2079}
2080
2081///
2082@safe unittest
2083{
2084    import std.algorithm.comparison : equal;
2085
2086    int[] a = [ 1, 2, 3 ];
2087    int[] b = [ 10, 20, 30, 40 ];
2088    auto r = roundRobin(a, b);
2089    assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
2090}
2091
2092/**
2093 * roundRobin can be used to create "interleave" functionality which inserts
2094 * an element between each element in a range.
2095 */
2096@safe unittest
2097{
2098    import std.algorithm.comparison : equal;
2099
2100    auto interleave(R, E)(R range, E element)
2101    if ((isInputRange!R && hasLength!R) || isForwardRange!R)
2102    {
2103        static if (hasLength!R)
2104            immutable len = range.length;
2105        else
2106            immutable len = range.save.walkLength;
2107
2108        return roundRobin(
2109            range,
2110            element.repeat(len - 1)
2111        );
2112    }
2113
2114    assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
2115}
2116
2117pure @safe unittest
2118{
2119    import std.algorithm.comparison : equal;
2120    string f = "foo", b = "bar";
2121    auto r = roundRobin(refRange(&f), refRange(&b));
2122    assert(equal(r.save, "fboaor"));
2123    assert(equal(r.save, "fboaor"));
2124}
2125
2126/**
2127Iterates a random-access range starting from a given point and
2128progressively extending left and right from that point. If no initial
2129point is given, iteration starts from the middle of the
2130range. Iteration spans the entire range.
2131
2132When `startingIndex` is 0 the range will be fully iterated in order
2133and in reverse order when `r.length` is given.
2134
2135Params:
2136    r = a random access range with length and slicing
2137    startingIndex = the index to begin iteration from
2138
2139Returns:
2140    A forward range with length
2141 */
2142auto radial(Range, I)(Range r, I startingIndex)
2143if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
2144{
2145    if (startingIndex != r.length) ++startingIndex;
2146    return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
2147}
2148
2149/// Ditto
2150auto radial(R)(R r)
2151if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
2152{
2153    return .radial(r, (r.length - !r.empty) / 2);
2154}
2155
2156///
2157@safe unittest
2158{
2159    import std.algorithm.comparison : equal;
2160    int[] a = [ 1, 2, 3, 4, 5 ];
2161    assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
2162    a = [ 1, 2, 3, 4 ];
2163    assert(equal(radial(a), [ 2, 3, 1, 4 ]));
2164
2165    // If the left end is reached first, the remaining elements on the right
2166    // are concatenated in order:
2167    a = [ 0, 1, 2, 3, 4, 5 ];
2168    assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
2169
2170    // If the right end is reached first, the remaining elements on the left
2171    // are concatenated in reverse order:
2172    assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
2173}
2174
2175@safe unittest
2176{
2177    import std.algorithm.comparison : equal;
2178    import std.conv : text;
2179    import std.exception : enforce;
2180    import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2181
2182    void test(int[] input, int[] witness)
2183    {
2184        enforce(equal(radial(input), witness),
2185                text(radial(input), " vs. ", witness));
2186    }
2187    test([], []);
2188    test([ 1 ], [ 1 ]);
2189    test([ 1, 2 ], [ 1, 2 ]);
2190    test([ 1, 2, 3 ], [ 2, 3, 1 ]);
2191    test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
2192    test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
2193    test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
2194
2195    int[] a = [ 1, 2, 3, 4, 5 ];
2196    assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
2197    assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
2198    assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
2199    static assert(isForwardRange!(typeof(radial(a, 1))));
2200
2201    auto r = radial([1,2,3,4,5]);
2202    for (auto rr = r.save; !rr.empty; rr.popFront())
2203    {
2204        assert(rr.front == moveFront(rr));
2205    }
2206    r.front = 5;
2207    assert(r.front == 5);
2208
2209    // Test instantiation without lvalue elements.
2210    DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
2211    assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
2212
2213    // immutable int[] immi = [ 1, 2 ];
2214    // static assert(is(typeof(radial(immi))));
2215}
2216
2217@safe unittest
2218{
2219    import std.algorithm.comparison : equal;
2220
2221    auto LL = iota(1L, 6L);
2222    auto r = radial(LL);
2223    assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
2224}
2225
2226/**
2227Lazily takes only up to `n` elements of a range. This is
2228particularly useful when using with infinite ranges.
2229
2230Unlike $(LREF takeExactly), `take` does not require that there
2231are `n` or more elements in `input`. As a consequence, length
2232information is not applied to the result unless `input` also has
2233length information.
2234
2235Params:
2236    input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2237    to iterate over up to `n` times
2238    n = the number of elements to take
2239
2240Returns:
2241    At minimum, an input range. If the range offers random access
2242    and `length`, `take` offers them as well.
2243 */
2244Take!R take(R)(R input, size_t n)
2245if (isInputRange!(Unqual!R))
2246{
2247    alias U = Unqual!R;
2248    static if (is(R T == Take!T))
2249    {
2250        import std.algorithm.comparison : min;
2251        return R(input.source, min(n, input._maxAvailable));
2252    }
2253    else static if (!isInfinite!U && hasSlicing!U)
2254    {
2255        import std.algorithm.comparison : min;
2256        return input[0 .. min(n, input.length)];
2257    }
2258    else
2259    {
2260        return Take!R(input, n);
2261    }
2262}
2263
2264/// ditto
2265struct Take(Range)
2266if (isInputRange!(Unqual!Range) &&
2267    //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
2268    //take for slicing infinite ranges.
2269    !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
2270{
2271    private alias R = Unqual!Range;
2272
2273    /// User accessible in read and write
2274    public R source;
2275
2276    private size_t _maxAvailable;
2277
2278    alias Source = R;
2279
2280    /// Range primitives
2281    @property bool empty()
2282    {
2283        return _maxAvailable == 0 || source.empty;
2284    }
2285
2286    /// ditto
2287    @property auto ref front()
2288    {
2289        assert(!empty,
2290            "Attempting to fetch the front of an empty "
2291            ~ Take.stringof);
2292        return source.front;
2293    }
2294
2295    /// ditto
2296    void popFront()
2297    {
2298        assert(!empty,
2299            "Attempting to popFront() past the end of a "
2300            ~ Take.stringof);
2301        source.popFront();
2302        --_maxAvailable;
2303    }
2304
2305    static if (isForwardRange!R)
2306        /// ditto
2307        @property Take save()
2308        {
2309            return Take(source.save, _maxAvailable);
2310        }
2311
2312    static if (hasAssignableElements!R)
2313        /// ditto
2314        @property void front(ElementType!R v)
2315        {
2316            assert(!empty,
2317                "Attempting to assign to the front of an empty "
2318                ~ Take.stringof);
2319            // This has to return auto instead of void because of
2320            // https://issues.dlang.org/show_bug.cgi?id=4706
2321            source.front = v;
2322        }
2323
2324    static if (hasMobileElements!R)
2325    {
2326        /// ditto
2327        auto moveFront()
2328        {
2329            assert(!empty,
2330                "Attempting to move the front of an empty "
2331                ~ Take.stringof);
2332            return source.moveFront();
2333        }
2334    }
2335
2336    static if (isInfinite!R)
2337    {
2338        /// ditto
2339        @property size_t length() const
2340        {
2341            return _maxAvailable;
2342        }
2343
2344        /// ditto
2345        alias opDollar = length;
2346
2347        //Note: Due to Take/hasSlicing circular dependency,
2348        //This needs to be a restrained template.
2349        /// ditto
2350        auto opSlice()(size_t i, size_t j)
2351        if (hasSlicing!R)
2352        {
2353            assert(i <= j, "Invalid slice bounds");
2354            assert(j <= length, "Attempting to slice past the end of a "
2355                ~ Take.stringof);
2356            return source[i .. j];
2357        }
2358    }
2359    else static if (hasLength!R)
2360    {
2361        /// ditto
2362        @property size_t length()
2363        {
2364            import std.algorithm.comparison : min;
2365            return min(_maxAvailable, source.length);
2366        }
2367
2368        alias opDollar = length;
2369    }
2370
2371    static if (isRandomAccessRange!R)
2372    {
2373        /// ditto
2374        void popBack()
2375        {
2376            assert(!empty,
2377                "Attempting to popBack() past the beginning of a "
2378                ~ Take.stringof);
2379            --_maxAvailable;
2380        }
2381
2382        /// ditto
2383        @property auto ref back()
2384        {
2385            assert(!empty,
2386                "Attempting to fetch the back of an empty "
2387                ~ Take.stringof);
2388            return source[this.length - 1];
2389        }
2390
2391        /// ditto
2392        auto ref opIndex(size_t index)
2393        {
2394            assert(index < length,
2395                "Attempting to index out of the bounds of a "
2396                ~ Take.stringof);
2397            return source[index];
2398        }
2399
2400        static if (hasAssignableElements!R)
2401        {
2402            /// ditto
2403            @property void back(ElementType!R v)
2404            {
2405                // This has to return auto instead of void because of
2406                // https://issues.dlang.org/show_bug.cgi?id=4706
2407                assert(!empty,
2408                    "Attempting to assign to the back of an empty "
2409                    ~ Take.stringof);
2410                source[this.length - 1] = v;
2411            }
2412
2413            /// ditto
2414            void opIndexAssign(ElementType!R v, size_t index)
2415            {
2416                assert(index < length,
2417                    "Attempting to index out of the bounds of a "
2418                    ~ Take.stringof);
2419                source[index] = v;
2420            }
2421        }
2422
2423        static if (hasMobileElements!R)
2424        {
2425            /// ditto
2426            auto moveBack()
2427            {
2428                assert(!empty,
2429                    "Attempting to move the back of an empty "
2430                    ~ Take.stringof);
2431                return source.moveAt(this.length - 1);
2432            }
2433
2434            /// ditto
2435            auto moveAt(size_t index)
2436            {
2437                assert(index < length,
2438                    "Attempting to index out of the bounds of a "
2439                    ~ Take.stringof);
2440                return source.moveAt(index);
2441            }
2442        }
2443    }
2444
2445    /**
2446    Access to maximal length of the range.
2447    Note: the actual length of the range depends on the underlying range.
2448    If it has fewer elements, it will stop before maxLength is reached.
2449    */
2450    @property size_t maxLength() const
2451    {
2452        return _maxAvailable;
2453    }
2454}
2455
2456/// ditto
2457template Take(R)
2458if (isInputRange!(Unqual!R) &&
2459    ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2460{
2461    alias Take = R;
2462}
2463
2464///
2465pure @safe nothrow unittest
2466{
2467    import std.algorithm.comparison : equal;
2468
2469    int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2470    auto s = take(arr1, 5);
2471    assert(s.length == 5);
2472    assert(s[4] == 5);
2473    assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2474}
2475
2476/**
2477 * If the range runs out before `n` elements, `take` simply returns the entire
2478 * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2479 * the range ends prematurely):
2480 */
2481pure @safe nothrow unittest
2482{
2483    import std.algorithm.comparison : equal;
2484
2485    int[] arr2 = [ 1, 2, 3 ];
2486    auto t = take(arr2, 5);
2487    assert(t.length == 3);
2488    assert(equal(t, [ 1, 2, 3 ]));
2489}
2490
2491pure @safe nothrow unittest
2492{
2493    import std.algorithm.comparison : equal;
2494    import std.internal.test.dummyrange : AllDummyRanges;
2495
2496    int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2497    auto s = take(arr1, 5);
2498    assert(s.length == 5);
2499    assert(s[4] == 5);
2500    assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2501    assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2502
2503    // Test fix for bug 4464.
2504    static assert(is(typeof(s) == Take!(int[])));
2505    static assert(is(typeof(s) == int[]));
2506
2507    // Test using narrow strings.
2508    import std.exception : assumeWontThrow;
2509
2510    auto myStr = "This is a string.";
2511    auto takeMyStr = take(myStr, 7);
2512    assert(assumeWontThrow(equal(takeMyStr, "This is")));
2513    // Test fix for bug 5052.
2514    auto takeMyStrAgain = take(takeMyStr, 4);
2515    assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2516    static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
2517    takeMyStrAgain = take(takeMyStr, 10);
2518    assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
2519
2520    foreach (DummyType; AllDummyRanges)
2521    {
2522        DummyType dummy;
2523        auto t = take(dummy, 5);
2524        alias T = typeof(t);
2525
2526        static if (isRandomAccessRange!DummyType)
2527        {
2528            static assert(isRandomAccessRange!T);
2529            assert(t[4] == 5);
2530
2531            assert(moveAt(t, 1) == t[1]);
2532            assert(t.back == moveBack(t));
2533        }
2534        else static if (isForwardRange!DummyType)
2535        {
2536            static assert(isForwardRange!T);
2537        }
2538
2539        for (auto tt = t; !tt.empty; tt.popFront())
2540        {
2541            assert(tt.front == moveFront(tt));
2542        }
2543
2544        // Bidirectional ranges can't be propagated properly if they don't
2545        // also have random access.
2546
2547        assert(equal(t, [1,2,3,4,5]));
2548
2549        //Test that take doesn't wrap the result of take.
2550        assert(take(t, 4) == take(dummy, 4));
2551    }
2552
2553    immutable myRepeat = repeat(1);
2554    static assert(is(Take!(typeof(myRepeat))));
2555}
2556
2557pure @safe nothrow @nogc unittest
2558{
2559    //check for correct slicing of Take on an infinite range
2560    import std.algorithm.comparison : equal;
2561    foreach (start; 0 .. 4)
2562        foreach (stop; start .. 4)
2563            assert(iota(4).cycle.take(4)[start .. stop]
2564                .equal(iota(start, stop)));
2565}
2566
2567pure @safe nothrow @nogc unittest
2568{
2569    // Check that one can declare variables of all Take types,
2570    // and that they match the return type of the corresponding
2571    // take().
2572    // See https://issues.dlang.org/show_bug.cgi?id=4464
2573    int[] r1;
2574    Take!(int[]) t1;
2575    t1 = take(r1, 1);
2576    assert(t1.empty);
2577
2578    string r2;
2579    Take!string t2;
2580    t2 = take(r2, 1);
2581    assert(t2.empty);
2582
2583    Take!(Take!string) t3;
2584    t3 = take(t2, 1);
2585    assert(t3.empty);
2586}
2587
2588pure @safe nothrow @nogc unittest
2589{
2590    alias R1 = typeof(repeat(1));
2591    alias R2 = typeof(cycle([1]));
2592    alias TR1 = Take!R1;
2593    alias TR2 = Take!R2;
2594    static assert(isBidirectionalRange!TR1);
2595    static assert(isBidirectionalRange!TR2);
2596}
2597
2598// https://issues.dlang.org/show_bug.cgi?id=12731
2599pure @safe nothrow @nogc unittest
2600{
2601    auto a = repeat(1);
2602    auto s = a[1 .. 5];
2603    s = s[1 .. 3];
2604    assert(s.length == 2);
2605    assert(s[0] == 1);
2606    assert(s[1] == 1);
2607}
2608
2609// https://issues.dlang.org/show_bug.cgi?id=13151
2610pure @safe nothrow @nogc unittest
2611{
2612    import std.algorithm.comparison : equal;
2613
2614    auto r = take(repeat(1, 4), 3);
2615    assert(r.take(2).equal(repeat(1, 2)));
2616}
2617
2618
2619/**
2620Similar to $(LREF take), but assumes that `range` has at least $(D
2621n) elements. Consequently, the result of $(D takeExactly(range, n))
2622always defines the `length` property (and initializes it to `n`)
2623even when `range` itself does not define `length`.
2624
2625The result of `takeExactly` is identical to that of $(LREF take) in
2626cases where the original range defines `length` or is infinite.
2627
2628Unlike $(LREF take), however, it is illegal to pass a range with less than
2629`n` elements to `takeExactly`; this will cause an assertion failure.
2630 */
2631auto takeExactly(R)(R range, size_t n)
2632if (isInputRange!R)
2633{
2634    static if (is(typeof(takeExactly(range._input, n)) == R))
2635    {
2636        assert(n <= range._n,
2637               "Attempted to take more than the length of the range with takeExactly.");
2638        // takeExactly(takeExactly(r, n1), n2) has the same type as
2639        // takeExactly(r, n1) and simply returns takeExactly(r, n2)
2640        range._n = n;
2641        return range;
2642    }
2643    //Also covers hasSlicing!R for finite ranges.
2644    else static if (hasLength!R)
2645    {
2646        assert(n <= range.length,
2647               "Attempted to take more than the length of the range with takeExactly.");
2648        return take(range, n);
2649    }
2650    else static if (isInfinite!R)
2651        return Take!R(range, n);
2652    else
2653    {
2654        static struct Result
2655        {
2656            R _input;
2657            private size_t _n;
2658
2659            @property bool empty() const { return !_n; }
2660            @property auto ref front()
2661            {
2662                assert(_n > 0, "front() on an empty " ~ Result.stringof);
2663                return _input.front;
2664            }
2665            void popFront() { _input.popFront(); --_n; }
2666            @property size_t length() const { return _n; }
2667            alias opDollar = length;
2668
2669            @property auto _takeExactly_Result_asTake()
2670            {
2671                return take(_input, _n);
2672            }
2673
2674            alias _takeExactly_Result_asTake this;
2675
2676            static if (isForwardRange!R)
2677                @property auto save()
2678                {
2679                    return Result(_input.save, _n);
2680                }
2681
2682            static if (hasMobileElements!R)
2683            {
2684                auto moveFront()
2685                {
2686                    assert(!empty,
2687                        "Attempting to move the front of an empty "
2688                        ~ typeof(this).stringof);
2689                    return _input.moveFront();
2690                }
2691            }
2692
2693            static if (hasAssignableElements!R)
2694            {
2695                @property auto ref front(ElementType!R v)
2696                {
2697                    assert(!empty,
2698                        "Attempting to assign to the front of an empty "
2699                        ~ typeof(this).stringof);
2700                    return _input.front = v;
2701                }
2702            }
2703        }
2704
2705        return Result(range, n);
2706    }
2707}
2708
2709///
2710pure @safe nothrow unittest
2711{
2712    import std.algorithm.comparison : equal;
2713
2714    auto a = [ 1, 2, 3, 4, 5 ];
2715
2716    auto b = takeExactly(a, 3);
2717    assert(equal(b, [1, 2, 3]));
2718    static assert(is(typeof(b.length) == size_t));
2719    assert(b.length == 3);
2720    assert(b.front == 1);
2721    assert(b.back == 3);
2722}
2723
2724pure @safe nothrow unittest
2725{
2726    import std.algorithm.comparison : equal;
2727    import std.algorithm.iteration : filter;
2728
2729    auto a = [ 1, 2, 3, 4, 5 ];
2730    auto b = takeExactly(a, 3);
2731    assert(equal(b, [1, 2, 3]));
2732    auto c = takeExactly(b, 2);
2733    assert(equal(c, [1, 2]));
2734
2735
2736
2737    auto d = filter!"a > 2"(a);
2738    auto e = takeExactly(d, 3);
2739    assert(equal(e, [3, 4, 5]));
2740    static assert(is(typeof(e.length) == size_t));
2741    assert(e.length == 3);
2742    assert(e.front == 3);
2743
2744    assert(equal(takeExactly(e, 3), [3, 4, 5]));
2745}
2746
2747pure @safe nothrow unittest
2748{
2749    import std.algorithm.comparison : equal;
2750    import std.internal.test.dummyrange : AllDummyRanges;
2751
2752    auto a = [ 1, 2, 3, 4, 5 ];
2753    //Test that take and takeExactly are the same for ranges which define length
2754    //but aren't sliceable.
2755    struct L
2756    {
2757        @property auto front() { return _arr[0]; }
2758        @property bool empty() { return _arr.empty; }
2759        void popFront() { _arr.popFront(); }
2760        @property size_t length() { return _arr.length; }
2761        int[] _arr;
2762    }
2763    static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
2764    assert(take(L(a), 3) == takeExactly(L(a), 3));
2765
2766    //Test that take and takeExactly are the same for ranges which are sliceable.
2767    static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
2768    assert(take(a, 3) == takeExactly(a, 3));
2769
2770    //Test that take and takeExactly are the same for infinite ranges.
2771    auto inf = repeat(1);
2772    static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
2773    assert(take(inf, 5) == takeExactly(inf, 5));
2774
2775    //Test that take and takeExactly are _not_ the same for ranges which don't
2776    //define length.
2777    static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
2778
2779    foreach (DummyType; AllDummyRanges)
2780    {
2781        {
2782            DummyType dummy;
2783            auto t = takeExactly(dummy, 5);
2784
2785            //Test that takeExactly doesn't wrap the result of takeExactly.
2786            assert(takeExactly(t, 4) == takeExactly(dummy, 4));
2787        }
2788
2789        static if (hasMobileElements!DummyType)
2790        {
2791            {
2792                auto t = takeExactly(DummyType.init, 4);
2793                assert(t.moveFront() == 1);
2794                assert(equal(t, [1, 2, 3, 4]));
2795            }
2796        }
2797
2798        static if (hasAssignableElements!DummyType)
2799        {
2800            {
2801                auto t = takeExactly(DummyType.init, 4);
2802                t.front = 9;
2803                assert(equal(t, [9, 2, 3, 4]));
2804            }
2805        }
2806    }
2807}
2808
2809pure @safe nothrow unittest
2810{
2811    import std.algorithm.comparison : equal;
2812    import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2813
2814    alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
2815    auto te = takeExactly(DummyType(), 5);
2816    Take!DummyType t = te;
2817    assert(equal(t, [1, 2, 3, 4, 5]));
2818    assert(equal(t, te));
2819}
2820
2821// https://issues.dlang.org/show_bug.cgi?id=18092
2822// can't combine take and takeExactly
2823@safe unittest
2824{
2825    import std.algorithm.comparison : equal;
2826    import std.internal.test.dummyrange : AllDummyRanges;
2827
2828    static foreach (Range; AllDummyRanges)
2829    {{
2830        Range r;
2831        assert(r.take(6).takeExactly(2).equal([1, 2]));
2832        assert(r.takeExactly(6).takeExactly(2).equal([1, 2]));
2833        assert(r.takeExactly(6).take(2).equal([1, 2]));
2834    }}
2835}
2836
2837/**
2838Returns a range with at most one element; for example, $(D
2839takeOne([42, 43, 44])) returns a range consisting of the integer $(D
284042). Calling `popFront()` off that range renders it empty.
2841
2842In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in
2843certain interfaces it is important to know statically that the range may only
2844have at most one element.
2845
2846The type returned by `takeOne` is a random-access range with length
2847regardless of `R`'s capabilities, as long as it is a forward range.
2848(another feature that distinguishes `takeOne` from `take`). If
2849(D R) is an input range but not a forward range, return type is an input
2850range with all random-access capabilities except save.
2851 */
2852auto takeOne(R)(R source)
2853if (isInputRange!R)
2854{
2855    static if (hasSlicing!R)
2856    {
2857        return source[0 .. !source.empty];
2858    }
2859    else
2860    {
2861        static struct Result
2862        {
2863            private R _source;
2864            private bool _empty = true;
2865            @property bool empty() const { return _empty; }
2866            @property auto ref front()
2867            {
2868                assert(!empty, "Attempting to fetch the front of an empty takeOne");
2869                return _source.front;
2870            }
2871            void popFront()
2872            {
2873                assert(!empty, "Attempting to popFront an empty takeOne");
2874                _source.popFront();
2875                _empty = true;
2876            }
2877            void popBack()
2878            {
2879                assert(!empty, "Attempting to popBack an empty takeOne");
2880                _source.popFront();
2881                _empty = true;
2882            }
2883            static if (isForwardRange!(Unqual!R))
2884            {
2885                @property auto save() { return Result(_source.save, empty); }
2886            }
2887            @property auto ref back()
2888            {
2889                assert(!empty, "Attempting to fetch the back of an empty takeOne");
2890                return _source.front;
2891            }
2892            @property size_t length() const { return !empty; }
2893            alias opDollar = length;
2894            auto ref opIndex(size_t n)
2895            {
2896                assert(n < length, "Attempting to index a takeOne out of bounds");
2897                return _source.front;
2898            }
2899            auto opSlice(size_t m, size_t n)
2900            {
2901                assert(
2902                    m <= n,
2903                    "Attempting to slice a takeOne range with a larger first argument than the second."
2904                );
2905                assert(
2906                    n <= length,
2907                    "Attempting to slice using an out of bounds index on a takeOne range."
2908                    );
2909                return n > m ? this : Result(_source, true);
2910            }
2911            // Non-standard property
2912            @property R source() { return _source; }
2913        }
2914
2915        return Result(source, source.empty);
2916    }
2917}
2918
2919///
2920pure @safe nothrow unittest
2921{
2922    auto s = takeOne([42, 43, 44]);
2923    static assert(isRandomAccessRange!(typeof(s)));
2924    assert(s.length == 1);
2925    assert(!s.empty);
2926    assert(s.front == 42);
2927    s.front = 43;
2928    assert(s.front == 43);
2929    assert(s.back == 43);
2930    assert(s[0] == 43);
2931    s.popFront();
2932    assert(s.length == 0);
2933    assert(s.empty);
2934}
2935
2936pure @safe nothrow @nogc unittest
2937{
2938    struct NonForwardRange
2939    {
2940        enum empty = false;
2941        int front() { return 42; }
2942        void popFront() {}
2943    }
2944
2945    static assert(!isForwardRange!NonForwardRange);
2946
2947    auto s = takeOne(NonForwardRange());
2948    assert(s.length == 1);
2949    assert(!s.empty);
2950    assert(s.front == 42);
2951    assert(s.back == 42);
2952    assert(s[0] == 42);
2953
2954    auto t = s[0 .. 0];
2955    assert(t.empty);
2956    assert(t.length == 0);
2957
2958    auto u = s[1 .. 1];
2959    assert(u.empty);
2960    assert(u.length == 0);
2961
2962    auto v = s[0 .. 1];
2963    s.popFront();
2964    assert(s.length == 0);
2965    assert(s.empty);
2966    assert(!v.empty);
2967    assert(v.front == 42);
2968    v.popBack();
2969    assert(v.empty);
2970    assert(v.length == 0);
2971}
2972
2973pure @safe nothrow @nogc unittest
2974{
2975    struct NonSlicingForwardRange
2976    {
2977        enum empty = false;
2978        int front() { return 42; }
2979        void popFront() {}
2980        @property auto save() { return this; }
2981    }
2982
2983    static assert(isForwardRange!NonSlicingForwardRange);
2984    static assert(!hasSlicing!NonSlicingForwardRange);
2985
2986    auto s = takeOne(NonSlicingForwardRange());
2987    assert(s.length == 1);
2988    assert(!s.empty);
2989    assert(s.front == 42);
2990    assert(s.back == 42);
2991    assert(s[0] == 42);
2992    auto t = s.save;
2993    s.popFront();
2994    assert(s.length == 0);
2995    assert(s.empty);
2996    assert(!t.empty);
2997    assert(t.front == 42);
2998    t.popBack();
2999    assert(t.empty);
3000    assert(t.length == 0);
3001}
3002
3003// Test that asserts trigger correctly
3004@system unittest
3005{
3006    import std.exception : assertThrown;
3007    import core.exception : AssertError;
3008
3009    struct NonForwardRange
3010    {
3011        enum empty = false;
3012        int front() { return 42; }
3013        void popFront() {}
3014    }
3015
3016    auto s = takeOne(NonForwardRange());
3017
3018    assertThrown!AssertError(s[1]);
3019    assertThrown!AssertError(s[0 .. 2]);
3020
3021    size_t one = 1;     // Avoid style warnings triggered by literals
3022    size_t zero = 0;
3023    assertThrown!AssertError(s[one .. zero]);
3024
3025    s.popFront;
3026    assert(s.empty);
3027    assertThrown!AssertError(s.front);
3028    assertThrown!AssertError(s.back);
3029    assertThrown!AssertError(s.popFront);
3030    assertThrown!AssertError(s.popBack);
3031}
3032
3033// https://issues.dlang.org/show_bug.cgi?id=16999
3034pure @safe unittest
3035{
3036    auto myIota = new class
3037    {
3038        int front = 0;
3039        @safe void popFront(){front++;}
3040        enum empty = false;
3041    };
3042    auto iotaPart = myIota.takeOne;
3043    int sum;
3044    foreach (var; chain(iotaPart, iotaPart, iotaPart))
3045    {
3046        sum += var;
3047    }
3048    assert(sum == 3);
3049    assert(iotaPart.front == 3);
3050}
3051
3052/++
3053    Returns an empty range which is statically known to be empty and is
3054    guaranteed to have `length` and be random access regardless of `R`'s
3055    capabilities.
3056  +/
3057auto takeNone(R)()
3058if (isInputRange!R)
3059{
3060    return typeof(takeOne(R.init)).init;
3061}
3062
3063///
3064pure @safe nothrow @nogc unittest
3065{
3066    auto range = takeNone!(int[])();
3067    assert(range.length == 0);
3068    assert(range.empty);
3069}
3070
3071pure @safe nothrow @nogc unittest
3072{
3073    enum ctfe = takeNone!(int[])();
3074    static assert(ctfe.length == 0);
3075    static assert(ctfe.empty);
3076}
3077
3078
3079/++
3080    Creates an empty range from the given range in $(BIGOH 1). If it can, it
3081    will return the same range type. If not, it will return
3082    $(D takeExactly(range, 0)).
3083  +/
3084auto takeNone(R)(R range)
3085if (isInputRange!R)
3086{
3087    import std.traits : isDynamicArray;
3088    //Makes it so that calls to takeNone which don't use UFCS still work with a
3089    //member version if it's defined.
3090    static if (is(typeof(R.takeNone)))
3091        auto retval = range.takeNone();
3092    // https://issues.dlang.org/show_bug.cgi?id=8339
3093    else static if (isDynamicArray!R)/+ ||
3094                   (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
3095    {
3096        auto retval = R.init;
3097    }
3098    //An infinite range sliced at [0 .. 0] would likely still not be empty...
3099    else static if (hasSlicing!R && !isInfinite!R)
3100        auto retval = range[0 .. 0];
3101    else
3102        auto retval = takeExactly(range, 0);
3103
3104    // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being
3105    // done in an out block.
3106    assert(retval.empty);
3107    return retval;
3108}
3109
3110///
3111pure @safe nothrow unittest
3112{
3113    import std.algorithm.iteration : filter;
3114    assert(takeNone([42, 27, 19]).empty);
3115    assert(takeNone("dlang.org").empty);
3116    assert(takeNone(filter!"true"([42, 27, 19])).empty);
3117}
3118
3119@safe unittest
3120{
3121    import std.algorithm.iteration : filter;
3122    import std.meta : AliasSeq;
3123
3124    struct Dummy
3125    {
3126        mixin template genInput()
3127        {
3128        @safe:
3129            @property bool empty() { return _arr.empty; }
3130            @property auto front() { return _arr.front; }
3131            void popFront() { _arr.popFront(); }
3132            static assert(isInputRange!(typeof(this)));
3133        }
3134    }
3135    alias genInput = Dummy.genInput;
3136
3137    static struct NormalStruct
3138    {
3139        //Disabled to make sure that the takeExactly version is used.
3140        @disable this();
3141        this(int[] arr) { _arr = arr; }
3142        mixin genInput;
3143        int[] _arr;
3144    }
3145
3146    static struct SliceStruct
3147    {
3148        @disable this();
3149        this(int[] arr) { _arr = arr; }
3150        mixin genInput;
3151        @property auto save() { return this; }
3152        auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
3153        @property size_t length() { return _arr.length; }
3154        int[] _arr;
3155    }
3156
3157    static struct InitStruct
3158    {
3159        mixin genInput;
3160        int[] _arr;
3161    }
3162
3163    static struct TakeNoneStruct
3164    {
3165        this(int[] arr) { _arr = arr; }
3166        @disable this();
3167        mixin genInput;
3168        auto takeNone() { return typeof(this)(null); }
3169        int[] _arr;
3170    }
3171
3172    static class NormalClass
3173    {
3174        this(int[] arr) {_arr = arr;}
3175        mixin genInput;
3176        int[] _arr;
3177    }
3178
3179    static class SliceClass
3180    {
3181    @safe:
3182        this(int[] arr) { _arr = arr; }
3183        mixin genInput;
3184        @property auto save() { return new typeof(this)(_arr); }
3185        auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
3186        @property size_t length() { return _arr.length; }
3187        int[] _arr;
3188    }
3189
3190    static class TakeNoneClass
3191    {
3192    @safe:
3193        this(int[] arr) { _arr = arr; }
3194        mixin genInput;
3195        auto takeNone() { return new typeof(this)(null); }
3196        int[] _arr;
3197    }
3198
3199    import std.format : format;
3200
3201    static foreach (range; AliasSeq!([1, 2, 3, 4, 5],
3202                             "hello world",
3203                             "hello world"w,
3204                             "hello world"d,
3205                             SliceStruct([1, 2, 3]),
3206                             // https://issues.dlang.org/show_bug.cgi?id=8339
3207                             // forces this to be takeExactly `InitStruct([1, 2, 3]),
3208                             TakeNoneStruct([1, 2, 3])))
3209    {
3210        static assert(takeNone(range).empty, typeof(range).stringof);
3211        assert(takeNone(range).empty);
3212        static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
3213    }
3214
3215    static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
3216                             InitStruct([1, 2, 3])))
3217    {
3218        static assert(takeNone(range).empty, typeof(range).stringof);
3219        assert(takeNone(range).empty);
3220        static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
3221    }
3222
3223    //Don't work in CTFE.
3224    auto normal = new NormalClass([1, 2, 3]);
3225    assert(takeNone(normal).empty);
3226    static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
3227
3228    auto slice = new SliceClass([1, 2, 3]);
3229    assert(takeNone(slice).empty);
3230    static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
3231
3232    auto taken = new TakeNoneClass([1, 2, 3]);
3233    assert(takeNone(taken).empty);
3234    static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
3235
3236    auto filtered = filter!"true"([1, 2, 3, 4, 5]);
3237    assert(takeNone(filtered).empty);
3238    // https://issues.dlang.org/show_bug.cgi?id=8339 and
3239    // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly
3240    //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
3241}
3242
3243/++
3244 + Return a range advanced to within `_n` elements of the end of
3245 + `range`.
3246 +
3247 + Intended as the range equivalent of the Unix
3248 + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
3249 + of `range` is less than or equal to `_n`, `range` is returned
3250 + as-is.
3251 +
3252 + Completes in $(BIGOH 1) steps for ranges that support slicing and have
3253 + length. Completes in $(BIGOH range.length) time for all other ranges.
3254 +
3255 + Params:
3256 +    range = range to get _tail of
3257 +    n = maximum number of elements to include in _tail
3258 +
3259 + Returns:
3260 +    Returns the _tail of `range` augmented with length information
3261 +/
3262auto tail(Range)(Range range, size_t n)
3263if (isInputRange!Range && !isInfinite!Range &&
3264    (hasLength!Range || isForwardRange!Range))
3265{
3266    static if (hasLength!Range)
3267    {
3268        immutable length = range.length;
3269        if (n >= length)
3270            return range.takeExactly(length);
3271        else
3272            return range.drop(length - n).takeExactly(n);
3273    }
3274    else
3275    {
3276        Range scout = range.save;
3277        foreach (immutable i; 0 .. n)
3278        {
3279            if (scout.empty)
3280                return range.takeExactly(i);
3281            scout.popFront();
3282        }
3283
3284        auto tail = range.save;
3285        while (!scout.empty)
3286        {
3287            assert(!tail.empty);
3288            scout.popFront();
3289            tail.popFront();
3290        }
3291
3292        return tail.takeExactly(n);
3293    }
3294}
3295
3296///
3297pure @safe nothrow unittest
3298{
3299    // tail -c n
3300    assert([1, 2, 3].tail(1) == [3]);
3301    assert([1, 2, 3].tail(2) == [2, 3]);
3302    assert([1, 2, 3].tail(3) == [1, 2, 3]);
3303    assert([1, 2, 3].tail(4) == [1, 2, 3]);
3304    assert([1, 2, 3].tail(0).length == 0);
3305
3306    // tail --lines=n
3307    import std.algorithm.comparison : equal;
3308    import std.algorithm.iteration : joiner;
3309    import std.exception : assumeWontThrow;
3310    import std.string : lineSplitter;
3311    assert("one\ntwo\nthree"
3312        .lineSplitter
3313        .tail(2)
3314        .joiner("\n")
3315        .equal("two\nthree")
3316        .assumeWontThrow);
3317}
3318
3319// @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408
3320pure nothrow @safe /+@nogc+/ unittest
3321{
3322    import std.algorithm.comparison : equal;
3323    import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
3324        RangeType, ReturnBy;
3325
3326    static immutable cheatsheet = [6, 7, 8, 9, 10];
3327
3328    foreach (R; AllDummyRanges)
3329    {
3330        static if (isInputRange!R && !isInfinite!R &&
3331                   (hasLength!R || isForwardRange!R))
3332        {
3333            assert(R.init.tail(5).equal(cheatsheet));
3334            static assert(R.init.tail(5).equal(cheatsheet));
3335
3336            assert(R.init.tail(0).length == 0);
3337            assert(R.init.tail(10).equal(R.init));
3338            assert(R.init.tail(11).equal(R.init));
3339        }
3340    }
3341
3342    // Infinite ranges are not supported
3343    static assert(!__traits(compiles, repeat(0).tail(0)));
3344
3345    // Neither are non-forward ranges without length
3346    static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
3347        RangeType.Input).init.tail(5)));
3348}
3349
3350pure @safe nothrow @nogc unittest
3351{
3352    static immutable input = [1, 2, 3];
3353    static immutable expectedOutput = [2, 3];
3354    assert(input.tail(2) == expectedOutput);
3355}
3356
3357/++
3358    Convenience function which calls
3359    $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`.
3360    `drop` makes it easier to pop elements from a range
3361    and then pass it to another function within a single expression,
3362    whereas `popFrontN` would require multiple statements.
3363
3364    `dropBack` provides the same functionality but instead calls
3365    $(REF popBackN, std, range, primitives)`(range, n)`
3366
3367    Note: `drop` and `dropBack` will only pop $(I up to)
3368    `n` elements but will stop if the range is empty first.
3369    In other languages this is sometimes called `skip`.
3370
3371    Params:
3372        range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3373        n = the number of elements to drop
3374
3375    Returns:
3376        `range` with up to `n` elements dropped
3377
3378    See_Also:
3379        $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives)
3380  +/
3381R drop(R)(R range, size_t n)
3382if (isInputRange!R)
3383{
3384    range.popFrontN(n);
3385    return range;
3386}
3387
3388///
3389@safe unittest
3390{
3391    import std.algorithm.comparison : equal;
3392
3393    assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
3394    assert("hello world".drop(6) == "world");
3395    assert("hello world".drop(50).empty);
3396    assert("hello world".take(6).drop(3).equal("lo "));
3397}
3398
3399/// ditto
3400R dropBack(R)(R range, size_t n)
3401if (isBidirectionalRange!R)
3402{
3403    range.popBackN(n);
3404    return range;
3405}
3406
3407///
3408@safe unittest
3409{
3410    import std.algorithm.comparison : equal;
3411
3412    assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
3413    assert("hello world".dropBack(6) == "hello");
3414    assert("hello world".dropBack(50).empty);
3415    assert("hello world".drop(4).dropBack(4).equal("o w"));
3416}
3417
3418@safe unittest
3419{
3420    import std.algorithm.comparison : equal;
3421    import std.container.dlist : DList;
3422
3423    //Remove all but the first two elements
3424    auto a = DList!int(0, 1, 9, 9, 9, 9);
3425    a.remove(a[].drop(2));
3426    assert(a[].equal(a[].take(2)));
3427}
3428
3429@safe unittest
3430{
3431    import std.algorithm.comparison : equal;
3432    import std.algorithm.iteration : filter;
3433
3434    assert(drop("", 5).empty);
3435    assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3436}
3437
3438@safe unittest
3439{
3440    import std.algorithm.comparison : equal;
3441    import std.container.dlist : DList;
3442
3443    //insert before the last two elements
3444    auto a = DList!int(0, 1, 2, 5, 6);
3445    a.insertAfter(a[].dropBack(2), [3, 4]);
3446    assert(a[].equal(iota(0, 7)));
3447}
3448
3449/++
3450    Similar to $(LREF drop) and `dropBack` but they call
3451    $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)`
3452    instead.
3453
3454    Note: Unlike `drop`, `dropExactly` will assume that the
3455    range holds at least `n` elements. This makes `dropExactly`
3456    faster than `drop`, but it also means that if `range` does
3457    not contain at least `n` elements, it will attempt to call `popFront`
3458    on an empty range, which is undefined behavior. So, only use
3459    `popFrontExactly` when it is guaranteed that `range` holds at least
3460    `n` elements.
3461
3462    Params:
3463        range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3464        n = the number of elements to drop
3465
3466    Returns:
3467        `range` with `n` elements dropped
3468
3469    See_Also:
3470        $(REF popFrontExcatly, std, range, primitives),
3471        $(REF popBackExcatly, std, range, primitives)
3472+/
3473R dropExactly(R)(R range, size_t n)
3474if (isInputRange!R)
3475{
3476    popFrontExactly(range, n);
3477    return range;
3478}
3479/// ditto
3480R dropBackExactly(R)(R range, size_t n)
3481if (isBidirectionalRange!R)
3482{
3483    popBackExactly(range, n);
3484    return range;
3485}
3486
3487///
3488@safe unittest
3489{
3490    import std.algorithm.comparison : equal;
3491    import std.algorithm.iteration : filterBidirectional;
3492
3493    auto a = [1, 2, 3];
3494    assert(a.dropExactly(2) == [3]);
3495    assert(a.dropBackExactly(2) == [1]);
3496
3497    string s = "���������";
3498    assert(s.dropExactly(2) == "���");
3499    assert(s.dropBackExactly(2) == "���");
3500
3501    auto bd = filterBidirectional!"true"([1, 2, 3]);
3502    assert(bd.dropExactly(2).equal([3]));
3503    assert(bd.dropBackExactly(2).equal([1]));
3504}
3505
3506/++
3507    Convenience function which calls
3508    `range.popFront()` and returns `range`. `dropOne`
3509    makes it easier to pop an element from a range
3510    and then pass it to another function within a single expression,
3511    whereas `popFront` would require multiple statements.
3512
3513    `dropBackOne` provides the same functionality but instead calls
3514    `range.popBack()`.
3515+/
3516R dropOne(R)(R range)
3517if (isInputRange!R)
3518{
3519    range.popFront();
3520    return range;
3521}
3522/// ditto
3523R dropBackOne(R)(R range)
3524if (isBidirectionalRange!R)
3525{
3526    range.popBack();
3527    return range;
3528}
3529
3530///
3531pure @safe nothrow unittest
3532{
3533    import std.algorithm.comparison : equal;
3534    import std.algorithm.iteration : filterBidirectional;
3535    import std.container.dlist : DList;
3536
3537    auto dl = DList!int(9, 1, 2, 3, 9);
3538    assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
3539
3540    auto a = [1, 2, 3];
3541    assert(a.dropOne() == [2, 3]);
3542    assert(a.dropBackOne() == [1, 2]);
3543
3544    string s = "���������";
3545    import std.exception : assumeWontThrow;
3546    assert(assumeWontThrow(s.dropOne() == "������"));
3547    assert(assumeWontThrow(s.dropBackOne() == "������"));
3548
3549    auto bd = filterBidirectional!"true"([1, 2, 3]);
3550    assert(bd.dropOne().equal([2, 3]));
3551    assert(bd.dropBackOne().equal([1, 2]));
3552}
3553
3554/**
3555Create a range which repeats one value.
3556
3557Params:
3558    value = the _value to repeat
3559    n = the number of times to repeat `value`
3560
3561Returns:
3562    If `n` is not defined, an infinite random access range
3563    with slicing.
3564
3565    If `n` is defined, a random access range with slicing.
3566*/
3567struct Repeat(T)
3568{
3569private:
3570    //Store a non-qualified T when possible: This is to make Repeat assignable
3571    static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable)))
3572    {
3573        import std.typecons : Rebindable;
3574        alias UT = Rebindable!T;
3575    }
3576    else static if (is(T : Unqual!T) && is(Unqual!T : T))
3577        alias UT = Unqual!T;
3578    else
3579        alias UT = T;
3580    UT _value;
3581
3582public:
3583    /// Range primitives
3584    @property inout(T) front() inout { return _value; }
3585
3586    /// ditto
3587    @property inout(T) back() inout { return _value; }
3588
3589    /// ditto
3590    enum bool empty = false;
3591
3592    /// ditto
3593    void popFront() {}
3594
3595    /// ditto
3596    void popBack() {}
3597
3598    /// ditto
3599    @property auto save() inout { return this; }
3600
3601    /// ditto
3602    inout(T) opIndex(size_t) inout { return _value; }
3603
3604    /// ditto
3605    auto opSlice(size_t i, size_t j)
3606    in
3607    {
3608        assert(
3609            i <= j,
3610            "Attempting to slice a Repeat with a larger first argument than the second."
3611        );
3612    }
3613    do
3614    {
3615        return this.takeExactly(j - i);
3616    }
3617    private static struct DollarToken {}
3618
3619    /// ditto
3620    enum opDollar = DollarToken.init;
3621
3622    /// ditto
3623    auto opSlice(size_t, DollarToken) inout { return this; }
3624}
3625
3626/// Ditto
3627Repeat!T repeat(T)(T value) { return Repeat!T(value); }
3628
3629///
3630pure @safe nothrow unittest
3631{
3632    import std.algorithm.comparison : equal;
3633
3634    assert(5.repeat().take(4).equal([5, 5, 5, 5]));
3635}
3636
3637pure @safe nothrow unittest
3638{
3639    import std.algorithm.comparison : equal;
3640
3641    auto  r = repeat(5);
3642    alias R = typeof(r);
3643    static assert(isBidirectionalRange!R);
3644    static assert(isForwardRange!R);
3645    static assert(isInfinite!R);
3646    static assert(hasSlicing!R);
3647
3648    assert(r.back == 5);
3649    assert(r.front == 5);
3650    assert(r.take(4).equal([ 5, 5, 5, 5 ]));
3651    assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
3652
3653    R r2 = r[5 .. $];
3654    assert(r2.back == 5);
3655    assert(r2.front == 5);
3656}
3657
3658/// ditto
3659Take!(Repeat!T) repeat(T)(T value, size_t n)
3660{
3661    return take(repeat(value), n);
3662}
3663
3664///
3665pure @safe nothrow unittest
3666{
3667    import std.algorithm.comparison : equal;
3668
3669    assert(5.repeat(4).equal([5, 5, 5, 5]));
3670}
3671
3672// https://issues.dlang.org/show_bug.cgi?id=12007
3673pure @safe nothrow unittest
3674{
3675    static class C{}
3676    Repeat!(immutable int) ri;
3677    ri = ri.save;
3678    Repeat!(immutable C) rc;
3679    rc = rc.save;
3680
3681    import std.algorithm.setops : cartesianProduct;
3682    import std.algorithm.comparison : equal;
3683    import std.typecons : tuple;
3684    immutable int[] A = [1,2,3];
3685    immutable int[] B = [4,5,6];
3686
3687    assert(equal(cartesianProduct(A,B),
3688        [
3689            tuple(1, 4), tuple(1, 5), tuple(1, 6),
3690            tuple(2, 4), tuple(2, 5), tuple(2, 6),
3691            tuple(3, 4), tuple(3, 5), tuple(3, 6),
3692        ]));
3693}
3694
3695/**
3696Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
3697whose front is defined by successive calls to `fun()`.
3698This is especially useful to call function with global side effects (random
3699functions), or to create ranges expressed as a single delegate, rather than
3700an entire `front`/`popFront`/`empty` structure.
3701`fun` maybe be passed either a template alias parameter (existing
3702function, delegate, struct type defining `static opCall`) or
3703a run-time value argument (delegate, function object).
3704The result range models an InputRange
3705($(REF isInputRange, std,range,primitives)).
3706The resulting range will call `fun()` on construction, and every call to
3707`popFront`, and the cached value will be returned when `front` is called.
3708
3709Returns: an `inputRange` where each element represents another call to fun.
3710*/
3711auto generate(Fun)(Fun fun)
3712if (isCallable!fun)
3713{
3714    auto gen = Generator!(Fun)(fun);
3715    gen.popFront(); // prime the first element
3716    return gen;
3717}
3718
3719/// ditto
3720auto generate(alias fun)()
3721if (isCallable!fun)
3722{
3723    auto gen = Generator!(fun)();
3724    gen.popFront(); // prime the first element
3725    return gen;
3726}
3727
3728///
3729@safe pure nothrow unittest
3730{
3731    import std.algorithm.comparison : equal;
3732    import std.algorithm.iteration : map;
3733
3734    int i = 1;
3735    auto powersOfTwo = generate!(() => i *= 2)().take(10);
3736    assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
3737}
3738
3739///
3740@safe pure nothrow unittest
3741{
3742    import std.algorithm.comparison : equal;
3743
3744    //Returns a run-time delegate
3745    auto infiniteIota(T)(T low, T high)
3746    {
3747        T i = high;
3748        return (){if (i == high) i = low; return i++;};
3749    }
3750    //adapted as a range.
3751    assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
3752}
3753
3754///
3755@safe unittest
3756{
3757    import std.format : format;
3758    import std.random : uniform;
3759
3760    auto r = generate!(() => uniform(0, 6)).take(10);
3761    format("%(%s %)", r);
3762}
3763
3764private struct Generator(Fun...)
3765{
3766    static assert(Fun.length == 1);
3767    static assert(isInputRange!Generator);
3768    import std.traits : FunctionAttribute, functionAttributes, ReturnType;
3769
3770private:
3771    static if (is(Fun[0]))
3772        Fun[0] fun;
3773    else
3774        alias fun = Fun[0];
3775
3776    enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
3777    static if (returnByRef_)
3778        ReturnType!fun *elem_;
3779    else
3780        ReturnType!fun elem_;
3781public:
3782    /// Range primitives
3783    enum empty = false;
3784
3785    static if (returnByRef_)
3786    {
3787        /// ditto
3788        ref front() @property
3789        {
3790            return *elem_;
3791        }
3792        /// ditto
3793        void popFront()
3794        {
3795            elem_ = &fun();
3796        }
3797    }
3798    else
3799    {
3800        /// ditto
3801        auto front() @property
3802        {
3803            return elem_;
3804        }
3805        /// ditto
3806        void popFront()
3807        {
3808            elem_ = fun();
3809        }
3810    }
3811}
3812
3813@safe nothrow unittest
3814{
3815    import std.algorithm.comparison : equal;
3816
3817    struct StaticOpCall
3818    {
3819        static ubyte opCall() { return 5 ; }
3820    }
3821
3822    assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
3823}
3824
3825@safe pure unittest
3826{
3827    import std.algorithm.comparison : equal;
3828
3829    struct OpCall
3830    {
3831        ubyte opCall() @safe pure { return 5 ; }
3832    }
3833
3834    OpCall op;
3835    assert(equal(generate(op).take(10), repeat(5).take(10)));
3836}
3837
3838// verify ref mechanism works
3839@system nothrow unittest
3840{
3841    int[10] arr;
3842    int idx;
3843
3844    ref int fun() {
3845        auto x = idx++;
3846        idx %= arr.length;
3847        return arr[x];
3848    }
3849    int y = 1;
3850    foreach (ref x; generate!(fun).take(20))
3851    {
3852        x += y++;
3853    }
3854    import std.algorithm.comparison : equal;
3855    assert(equal(arr[], iota(12, 32, 2)));
3856}
3857
3858// assure front isn't the mechanism to make generate go to the next element.
3859@safe unittest
3860{
3861    int i;
3862    auto g = generate!(() => ++i);
3863    auto f = g.front;
3864    assert(f == g.front);
3865    g = g.drop(5); // reassign because generate caches
3866    assert(g.front == f + 5);
3867}
3868
3869/**
3870Repeats the given forward range ad infinitum. If the original range is
3871infinite (fact that would make `Cycle` the identity application),
3872`Cycle` detects that and aliases itself to the range type
3873itself. That works for non-forward ranges too.
3874If the original range has random access, `Cycle` offers
3875random access and also offers a constructor taking an initial position
3876`index`. `Cycle` works with static arrays in addition to ranges,
3877mostly for performance reasons.
3878
3879Note: The input range must not be empty.
3880
3881Tip: This is a great way to implement simple circular buffers.
3882*/
3883struct Cycle(R)
3884if (isForwardRange!R && !isInfinite!R)
3885{
3886    static if (isRandomAccessRange!R && hasLength!R)
3887    {
3888        private R _original;
3889        private size_t _index;
3890
3891        /// Range primitives
3892        this(R input, size_t index = 0)
3893        {
3894            _original = input;
3895            _index = index % _original.length;
3896        }
3897
3898        /// ditto
3899        @property auto ref front()
3900        {
3901            return _original[_index];
3902        }
3903
3904        static if (is(typeof((cast(const R)_original)[_index])))
3905        {
3906            /// ditto
3907            @property auto ref front() const
3908            {
3909                return _original[_index];
3910            }
3911        }
3912
3913        static if (hasAssignableElements!R)
3914        {
3915            /// ditto
3916            @property void front(ElementType!R val)
3917            {
3918                _original[_index] = val;
3919            }
3920        }
3921
3922        /// ditto
3923        enum bool empty = false;
3924
3925        /// ditto
3926        void popFront()
3927        {
3928            ++_index;
3929            if (_index >= _original.length)
3930                _index = 0;
3931        }
3932
3933        /// ditto
3934        auto ref opIndex(size_t n)
3935        {
3936            return _original[(n + _index) % _original.length];
3937        }
3938
3939        static if (is(typeof((cast(const R)_original)[_index])) &&
3940                   is(typeof((cast(const R)_original).length)))
3941        {
3942            /// ditto
3943            auto ref opIndex(size_t n) const
3944            {
3945                return _original[(n + _index) % _original.length];
3946            }
3947        }
3948
3949        static if (hasAssignableElements!R)
3950        {
3951            /// ditto
3952            void opIndexAssign(ElementType!R val, size_t n)
3953            {
3954                _original[(n + _index) % _original.length] = val;
3955            }
3956        }
3957
3958        /// ditto
3959        @property Cycle save()
3960        {
3961            //No need to call _original.save, because Cycle never actually modifies _original
3962            return Cycle(_original, _index);
3963        }
3964
3965        private static struct DollarToken {}
3966
3967        /// ditto
3968        enum opDollar = DollarToken.init;
3969
3970        static if (hasSlicing!R)
3971        {
3972            /// ditto
3973            auto opSlice(size_t i, size_t j)
3974            in
3975            {
3976                assert(i <= j);
3977            }
3978            do
3979            {
3980                return this[i .. $].takeExactly(j - i);
3981            }
3982
3983            /// ditto
3984            auto opSlice(size_t i, DollarToken)
3985            {
3986                return typeof(this)(_original, _index + i);
3987            }
3988        }
3989    }
3990    else
3991    {
3992        private R _original;
3993        private R _current;
3994
3995        /// ditto
3996        this(R input)
3997        {
3998            _original = input;
3999            _current = input.save;
4000        }
4001
4002        private this(R original, R current)
4003        {
4004            _original = original;
4005            _current = current;
4006        }
4007
4008        /// ditto
4009        @property auto ref front()
4010        {
4011            return _current.front;
4012        }
4013
4014        static if (is(typeof((cast(const R)_current).front)))
4015        {
4016            /// ditto
4017            @property auto ref front() const
4018            {
4019                return _current.front;
4020            }
4021        }
4022
4023        static if (hasAssignableElements!R)
4024        {
4025            /// ditto
4026            @property auto front(ElementType!R val)
4027            {
4028                return _current.front = val;
4029            }
4030        }
4031
4032        /// ditto
4033        enum bool empty = false;
4034
4035        /// ditto
4036        void popFront()
4037        {
4038            _current.popFront();
4039            if (_current.empty)
4040                _current = _original.save;
4041        }
4042
4043        /// ditto
4044        @property Cycle save()
4045        {
4046            //No need to call _original.save, because Cycle never actually modifies _original
4047            return Cycle(_original, _current.save);
4048        }
4049    }
4050}
4051
4052/// ditto
4053template Cycle(R)
4054if (isInfinite!R)
4055{
4056    alias Cycle = R;
4057}
4058
4059/// ditto
4060struct Cycle(R)
4061if (isStaticArray!R)
4062{
4063    private alias ElementType = typeof(R.init[0]);
4064    private ElementType* _ptr;
4065    private size_t _index;
4066
4067nothrow:
4068
4069    /// Range primitives
4070    this(ref R input, size_t index = 0) @system
4071    {
4072        _ptr = input.ptr;
4073        _index = index % R.length;
4074    }
4075
4076    /// ditto
4077    @property ref inout(ElementType) front() inout @safe
4078    {
4079        static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4080        {
4081            return p[idx];
4082        }
4083        return trustedPtrIdx(_ptr, _index);
4084    }
4085
4086    /// ditto
4087    enum bool empty = false;
4088
4089    /// ditto
4090    void popFront() @safe
4091    {
4092        ++_index;
4093        if (_index >= R.length)
4094            _index = 0;
4095    }
4096
4097    /// ditto
4098    ref inout(ElementType) opIndex(size_t n) inout @safe
4099    {
4100        static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4101        {
4102            return p[idx % R.length];
4103        }
4104        return trustedPtrIdx(_ptr, n + _index);
4105    }
4106
4107    /// ditto
4108    @property inout(Cycle) save() inout @safe
4109    {
4110        return this;
4111    }
4112
4113    private static struct DollarToken {}
4114    /// ditto
4115    enum opDollar = DollarToken.init;
4116
4117    /// ditto
4118    auto opSlice(size_t i, size_t j) @safe
4119    in
4120    {
4121        assert(
4122            i <= j,
4123            "Attempting to slice a Repeat with a larger first argument than the second."
4124        );
4125    }
4126    do
4127    {
4128        return this[i .. $].takeExactly(j - i);
4129    }
4130
4131    /// ditto
4132    inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
4133    {
4134        static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
4135        {
4136            return cast(inout) Cycle(*cast(R*)(p), idx);
4137        }
4138        return trustedCtor(_ptr, _index + i);
4139    }
4140}
4141
4142/// Ditto
4143auto cycle(R)(R input)
4144if (isInputRange!R)
4145{
4146    static assert(isForwardRange!R || isInfinite!R,
4147        "Cycle requires a forward range argument unless it's statically known"
4148         ~ " to be infinite");
4149    assert(!input.empty, "Attempting to pass an empty input to cycle");
4150    static if (isInfinite!R) return input;
4151    else return Cycle!R(input);
4152}
4153
4154///
4155@safe unittest
4156{
4157    import std.algorithm.comparison : equal;
4158    import std.range : cycle, take;
4159
4160    // Here we create an infinitive cyclic sequence from [1, 2]
4161    // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
4162    // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
4163    // and compare them with the expected values for equality.
4164    assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
4165}
4166
4167/// Ditto
4168Cycle!R cycle(R)(R input, size_t index = 0)
4169if (isRandomAccessRange!R && !isInfinite!R)
4170{
4171    assert(!input.empty, "Attempting to pass an empty input to cycle");
4172    return Cycle!R(input, index);
4173}
4174
4175/// Ditto
4176Cycle!R cycle(R)(ref R input, size_t index = 0) @system
4177if (isStaticArray!R)
4178{
4179    return Cycle!R(input, index);
4180}
4181
4182@safe nothrow unittest
4183{
4184    import std.algorithm.comparison : equal;
4185    import std.internal.test.dummyrange : AllDummyRanges;
4186
4187    static assert(isForwardRange!(Cycle!(uint[])));
4188
4189    // Make sure ref is getting propagated properly.
4190    int[] nums = [1,2,3];
4191    auto c2 = cycle(nums);
4192    c2[3]++;
4193    assert(nums[0] == 2);
4194
4195    immutable int[] immarr = [1, 2, 3];
4196
4197    foreach (DummyType; AllDummyRanges)
4198    {
4199        static if (isForwardRange!DummyType)
4200        {
4201            DummyType dummy;
4202            auto cy = cycle(dummy);
4203            static assert(isForwardRange!(typeof(cy)));
4204            auto t = take(cy, 20);
4205            assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
4206
4207            const cRange = cy;
4208            assert(cRange.front == 1);
4209
4210            static if (hasAssignableElements!DummyType)
4211            {
4212                {
4213                    cy.front = 66;
4214                    scope(exit) cy.front = 1;
4215                    assert(dummy.front == 66);
4216                }
4217
4218                static if (isRandomAccessRange!DummyType)
4219                {
4220                    {
4221                        cy[10] = 66;
4222                        scope(exit) cy[10] = 1;
4223                        assert(dummy.front == 66);
4224                    }
4225
4226                    assert(cRange[10] == 1);
4227                }
4228            }
4229
4230            static if (hasSlicing!DummyType)
4231            {
4232                auto slice = cy[5 .. 15];
4233                assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
4234                static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
4235
4236                auto infSlice = cy[7 .. $];
4237                assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
4238                static assert(isInfinite!(typeof(infSlice)));
4239            }
4240        }
4241    }
4242}
4243
4244@system nothrow unittest // For static arrays.
4245{
4246    import std.algorithm.comparison : equal;
4247
4248    int[3] a = [ 1, 2, 3 ];
4249    static assert(isStaticArray!(typeof(a)));
4250    auto c = cycle(a);
4251    assert(a.ptr == c._ptr);
4252    assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
4253    static assert(isForwardRange!(typeof(c)));
4254
4255    // Test qualifiers on slicing.
4256    alias C = typeof(c);
4257    static assert(is(typeof(c[1 .. $]) == C));
4258    const cConst = c;
4259    static assert(is(typeof(cConst[1 .. $]) == const(C)));
4260}
4261
4262@safe nothrow unittest // For infinite ranges
4263{
4264    struct InfRange
4265    {
4266        void popFront() { }
4267        @property int front() { return 0; }
4268        enum empty = false;
4269        auto save() { return this; }
4270    }
4271    struct NonForwardInfRange
4272    {
4273        void popFront() { }
4274        @property int front() { return 0; }
4275        enum empty = false;
4276    }
4277
4278    InfRange i;
4279    NonForwardInfRange j;
4280    auto c = cycle(i);
4281    assert(c == i);
4282    //make sure it can alias out even non-forward infinite ranges
4283    static assert(is(typeof(j.cycle) == typeof(j)));
4284}
4285
4286@safe unittest
4287{
4288    import std.algorithm.comparison : equal;
4289
4290    int[5] arr = [0, 1, 2, 3, 4];
4291    auto cleD = cycle(arr[]); //Dynamic
4292    assert(equal(cleD[5 .. 10], arr[]));
4293
4294    //n is a multiple of 5 worth about 3/4 of size_t.max
4295    auto n = size_t.max/4 + size_t.max/2;
4296    n -= n % 5;
4297
4298    //Test index overflow
4299    foreach (_ ; 0 .. 10)
4300    {
4301        cleD = cleD[n .. $];
4302        assert(equal(cleD[5 .. 10], arr[]));
4303    }
4304}
4305
4306@system @nogc nothrow unittest
4307{
4308    import std.algorithm.comparison : equal;
4309
4310    int[5] arr = [0, 1, 2, 3, 4];
4311    auto cleS = cycle(arr);   //Static
4312    assert(equal(cleS[5 .. 10], arr[]));
4313
4314    //n is a multiple of 5 worth about 3/4 of size_t.max
4315    auto n = size_t.max/4 + size_t.max/2;
4316    n -= n % 5;
4317
4318    //Test index overflow
4319    foreach (_ ; 0 .. 10)
4320    {
4321        cleS = cleS[n .. $];
4322        assert(equal(cleS[5 .. 10], arr[]));
4323    }
4324}
4325
4326@system unittest
4327{
4328    import std.algorithm.comparison : equal;
4329
4330    int[1] arr = [0];
4331    auto cleS = cycle(arr);
4332    cleS = cleS[10 .. $];
4333    assert(equal(cleS[5 .. 10], 0.repeat(5)));
4334    assert(cleS.front == 0);
4335}
4336
4337// https://issues.dlang.org/show_bug.cgi?id=10845
4338@system unittest
4339{
4340    import std.algorithm.comparison : equal;
4341    import std.algorithm.iteration : filter;
4342
4343    auto a = inputRangeObject(iota(3).filter!"true");
4344    assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
4345}
4346
4347// https://issues.dlang.org/show_bug.cgi?id=12177
4348@safe unittest
4349{
4350    static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
4351}
4352
4353// https://issues.dlang.org/show_bug.cgi?id=13390
4354@system unittest
4355{
4356    import core.exception : AssertError;
4357    import std.exception : assertThrown;
4358    assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
4359}
4360
4361// https://issues.dlang.org/show_bug.cgi?id=18657
4362pure @safe unittest
4363{
4364    import std.algorithm.comparison : equal;
4365    string s = "foo";
4366    auto r = refRange(&s).cycle.take(4);
4367    assert(equal(r.save, "foof"));
4368    assert(equal(r.save, "foof"));
4369}
4370
4371private alias lengthType(R) = typeof(R.init.length.init);
4372
4373/**
4374   Iterate several ranges in lockstep. The element type is a proxy tuple
4375   that allows accessing the current element in the `n`th range by
4376   using `e[n]`.
4377
4378   `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
4379   bundle its elements and uses the `opApply` protocol.
4380   `lockstep` allows reference access to the elements in
4381   `foreach` iterations.
4382
4383    Params:
4384        sp = controls what `zip` will do if the ranges are different lengths
4385        ranges = the ranges to zip together
4386    Returns:
4387        At minimum, an input range. `Zip` offers the lowest range facilities
4388        of all components, e.g. it offers random access iff all ranges offer
4389        random access, and also offers mutation and swapping if all ranges offer
4390        it. Due to this, `Zip` is extremely powerful because it allows manipulating
4391        several ranges in lockstep.
4392    Throws:
4393        An `Exception` if all of the ranges are not the same length and
4394        `sp` is set to `StoppingPolicy.requireSameLength`.
4395
4396    Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for
4397    the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This
4398    limitation is not shared by the anonymous range returned by the `zip`
4399    function when not given an explicit `StoppingPolicy` as an argument.
4400*/
4401struct Zip(Ranges...)
4402if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4403{
4404    import std.format : format; //for generic mixins
4405    import std.typecons : Tuple;
4406
4407    alias R = Ranges;
4408    private R ranges;
4409    alias ElementType = Tuple!(staticMap!(.ElementType, R));
4410    private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
4411
4412/**
4413   Builds an object. Usually this is invoked indirectly by using the
4414   $(LREF zip) function.
4415 */
4416    this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
4417    {
4418        ranges[] = rs[];
4419        stoppingPolicy = s;
4420    }
4421
4422/**
4423   Returns `true` if the range is at end. The test depends on the
4424   stopping policy.
4425*/
4426    static if (allSatisfy!(isInfinite, R))
4427    {
4428        // BUG:  Doesn't propagate infiniteness if only some ranges are infinite
4429        //       and s == StoppingPolicy.longest.  This isn't fixable in the
4430        //       current design since StoppingPolicy is known only at runtime.
4431        enum bool empty = false;
4432    }
4433    else
4434    {
4435        ///
4436        @property bool empty()
4437        {
4438            import std.exception : enforce;
4439            import std.meta : anySatisfy;
4440
4441            final switch (stoppingPolicy)
4442            {
4443            case StoppingPolicy.shortest:
4444                foreach (i, Unused; R)
4445                {
4446                    if (ranges[i].empty) return true;
4447                }
4448                return false;
4449            case StoppingPolicy.longest:
4450                static if (anySatisfy!(isInfinite, R))
4451                {
4452                    return false;
4453                }
4454                else
4455                {
4456                    foreach (i, Unused; R)
4457                    {
4458                        if (!ranges[i].empty) return false;
4459                    }
4460                    return true;
4461                }
4462            case StoppingPolicy.requireSameLength:
4463                foreach (i, Unused; R[1 .. $])
4464                {
4465                    enforce(ranges[0].empty ==
4466                            ranges[i + 1].empty,
4467                            "Inequal-length ranges passed to Zip");
4468                }
4469                return ranges[0].empty;
4470            }
4471            assert(false);
4472        }
4473    }
4474
4475    static if (allSatisfy!(isForwardRange, R))
4476    {
4477        ///
4478        @property Zip save()
4479        {
4480            //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
4481            return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4482        }
4483    }
4484
4485    private .ElementType!(R[i]) tryGetInit(size_t i)()
4486    {
4487        alias E = .ElementType!(R[i]);
4488        static if (!is(typeof({static E i;})))
4489            throw new Exception("Range with non-default constructable elements exhausted.");
4490        else
4491            return E.init;
4492    }
4493
4494/**
4495   Returns the current iterated element.
4496*/
4497    @property ElementType front()
4498    {
4499        @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
4500        //ElementType(tryGetFront!0, tryGetFront!1, ...)
4501        return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
4502    }
4503
4504/**
4505   Sets the front of all iterated ranges.
4506*/
4507    static if (allSatisfy!(hasAssignableElements, R))
4508    {
4509        @property void front(ElementType v)
4510        {
4511            foreach (i, Unused; R)
4512            {
4513                if (!ranges[i].empty)
4514                {
4515                    ranges[i].front = v[i];
4516                }
4517            }
4518        }
4519    }
4520
4521/**
4522   Moves out the front.
4523*/
4524    static if (allSatisfy!(hasMobileElements, R))
4525    {
4526        ElementType moveFront()
4527        {
4528            @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4529            //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
4530            return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
4531        }
4532    }
4533
4534/**
4535   Returns the rightmost element.
4536*/
4537    static if (allSatisfy!(isBidirectionalRange, R))
4538    {
4539        @property ElementType back()
4540        {
4541            //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4542
4543            @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
4544            //ElementType(tryGetBack!0, tryGetBack!1, ...)
4545            return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
4546        }
4547
4548/**
4549   Moves out the back.
4550*/
4551        static if (allSatisfy!(hasMobileElements, R))
4552        {
4553            ElementType moveBack()
4554            {
4555                //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4556
4557                @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();}
4558                //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
4559                return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
4560            }
4561        }
4562
4563/**
4564   Returns the current iterated element.
4565*/
4566        static if (allSatisfy!(hasAssignableElements, R))
4567        {
4568            @property void back(ElementType v)
4569            {
4570                //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
4571                //Not sure the call is even legal for StoppingPolicy.longest
4572
4573                foreach (i, Unused; R)
4574                {
4575                    if (!ranges[i].empty)
4576                    {
4577                        ranges[i].back = v[i];
4578                    }
4579                }
4580            }
4581        }
4582    }
4583
4584/**
4585   Advances to the next element in all controlled ranges.
4586*/
4587    void popFront()
4588    {
4589        import std.exception : enforce;
4590
4591        final switch (stoppingPolicy)
4592        {
4593        case StoppingPolicy.shortest:
4594            foreach (i, Unused; R)
4595            {
4596                assert(!ranges[i].empty);
4597                ranges[i].popFront();
4598            }
4599            break;
4600        case StoppingPolicy.longest:
4601            foreach (i, Unused; R)
4602            {
4603                if (!ranges[i].empty) ranges[i].popFront();
4604            }
4605            break;
4606        case StoppingPolicy.requireSameLength:
4607            foreach (i, Unused; R)
4608            {
4609                enforce(!ranges[i].empty, "Invalid Zip object");
4610                ranges[i].popFront();
4611            }
4612            break;
4613        }
4614    }
4615
4616/**
4617   Calls `popBack` for all controlled ranges.
4618*/
4619    static if (allSatisfy!(isBidirectionalRange, R))
4620    {
4621        void popBack()
4622        {
4623            //TODO: Fixme! In case of jaggedness, this is wrong.
4624            import std.exception : enforce;
4625
4626            final switch (stoppingPolicy)
4627            {
4628            case StoppingPolicy.shortest:
4629                foreach (i, Unused; R)
4630                {
4631                    assert(!ranges[i].empty);
4632                    ranges[i].popBack();
4633                }
4634                break;
4635            case StoppingPolicy.longest:
4636                foreach (i, Unused; R)
4637                {
4638                    if (!ranges[i].empty) ranges[i].popBack();
4639                }
4640                break;
4641            case StoppingPolicy.requireSameLength:
4642                foreach (i, Unused; R)
4643                {
4644                    enforce(!ranges[i].empty, "Invalid Zip object");
4645                    ranges[i].popBack();
4646                }
4647                break;
4648            }
4649        }
4650    }
4651
4652/**
4653   Returns the length of this range. Defined only if all ranges define
4654   `length`.
4655*/
4656    static if (allSatisfy!(hasLength, R))
4657    {
4658        @property auto length()
4659        {
4660            static if (Ranges.length == 1)
4661                return ranges[0].length;
4662            else
4663            {
4664                if (stoppingPolicy == StoppingPolicy.requireSameLength)
4665                    return ranges[0].length;
4666
4667                //[min|max](ranges[0].length, ranges[1].length, ...)
4668                import std.algorithm.comparison : min, max;
4669                if (stoppingPolicy == StoppingPolicy.shortest)
4670                    return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4671                else
4672                    return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4673            }
4674        }
4675
4676        alias opDollar = length;
4677    }
4678
4679/**
4680   Returns a slice of the range. Defined only if all range define
4681   slicing.
4682*/
4683    static if (allSatisfy!(hasSlicing, R))
4684    {
4685        auto opSlice(size_t from, size_t to)
4686        {
4687            //Slicing an infinite range yields the type Take!R
4688            //For finite ranges, the type Take!R aliases to R
4689            alias ZipResult = Zip!(staticMap!(Take, R));
4690
4691            //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
4692            return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4693        }
4694    }
4695
4696/**
4697   Returns the `n`th element in the composite range. Defined if all
4698   ranges offer random access.
4699*/
4700    static if (allSatisfy!(isRandomAccessRange, R))
4701    {
4702        ElementType opIndex(size_t n)
4703        {
4704            //TODO: Fixme! This may create an out of bounds access
4705            //for StoppingPolicy.longest
4706
4707            //ElementType(ranges[0][n], ranges[1][n], ...)
4708            return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
4709        }
4710
4711/**
4712   Assigns to the `n`th element in the composite range. Defined if
4713   all ranges offer random access.
4714*/
4715        static if (allSatisfy!(hasAssignableElements, R))
4716        {
4717            void opIndexAssign(ElementType v, size_t n)
4718            {
4719                //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
4720                foreach (i, Range; R)
4721                {
4722                    ranges[i][n] = v[i];
4723                }
4724            }
4725        }
4726
4727/**
4728   Destructively reads the `n`th element in the composite
4729   range. Defined if all ranges offer random access.
4730*/
4731        static if (allSatisfy!(hasMobileElements, R))
4732        {
4733            ElementType moveAt(size_t n)
4734            {
4735                //TODO: Fixme! This may create an out of bounds access
4736                //for StoppingPolicy.longest
4737
4738                //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
4739                return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
4740            }
4741        }
4742    }
4743}
4744
4745/// Ditto
4746auto zip(Ranges...)(Ranges ranges)
4747if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4748{
4749    import std.meta : anySatisfy, templateOr;
4750    static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1)
4751    {
4752        return ZipShortest!(Ranges)(ranges);
4753    }
4754    else static if (allSatisfy!(isBidirectionalRange, Ranges))
4755    {
4756        static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)
4757            && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges)
4758            && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges)))
4759        {
4760            // If all the ranges are bidirectional, if possible slice them to
4761            // the same length to simplify the implementation.
4762            static assert(anySatisfy!(hasLength, Ranges));
4763            static foreach (i, Range; Ranges)
4764                static if (hasLength!Range)
4765                {
4766                    static if (!is(typeof(minLen) == size_t))
4767                        size_t minLen = ranges[i].length;
4768                    else
4769                    {{
4770                        const x = ranges[i].length;
4771                        if (x < minLen) minLen = x;
4772                    }}
4773                }
4774            import std.format : format;
4775            static if (!anySatisfy!(isInfinite, Ranges))
4776                return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
4777                    `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length)));
4778            else
4779                return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
4780                    `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length)));
4781        }
4782        else static if (allSatisfy!(isRandomAccessRange, Ranges))
4783        {
4784            // We can't slice but we can still use random access to ensure
4785            // "back" is retrieving the same index for each range.
4786            return ZipShortest!(Ranges)(ranges);
4787        }
4788        else
4789        {
4790            // If bidirectional range operations would not be supported by
4791            // ZipShortest that might have actually been a bug since Zip
4792            // supported `back` without verifying that each range had the
4793            // same length, but for the sake of backwards compatibility
4794            // use the old Zip to continue supporting them.
4795            return Zip!Ranges(ranges);
4796        }
4797    }
4798    else
4799    {
4800        return ZipShortest!(Ranges)(ranges);
4801    }
4802}
4803
4804///
4805@nogc nothrow pure @safe unittest
4806{
4807    import std.algorithm.comparison : equal;
4808    import std.algorithm.iteration : map;
4809
4810    // pairwise sum
4811    auto arr = only(0, 1, 2);
4812    auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
4813    assert(part1.equal(only(1, 3)));
4814}
4815
4816///
4817nothrow pure @safe unittest
4818{
4819    import std.conv : to;
4820
4821    int[] a = [ 1, 2, 3 ];
4822    string[] b = [ "a", "b", "c" ];
4823    string[] result;
4824
4825    foreach (tup; zip(a, b))
4826    {
4827        result ~= tup[0].to!string ~ tup[1];
4828    }
4829
4830    assert(result == [ "1a", "2b", "3c" ]);
4831
4832    size_t idx = 0;
4833    // unpacking tuple elements with foreach
4834    foreach (e1, e2; zip(a, b))
4835    {
4836        assert(e1 == a[idx]);
4837        assert(e2 == b[idx]);
4838        ++idx;
4839    }
4840}
4841
4842/// `zip` is powerful - the following code sorts two arrays in parallel:
4843nothrow pure @safe unittest
4844{
4845    import std.algorithm.sorting : sort;
4846
4847    int[] a = [ 1, 2, 3 ];
4848    string[] b = [ "a", "c", "b" ];
4849    zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
4850
4851    assert(a == [ 3, 2, 1 ]);
4852    // b is sorted according to a's sorting
4853    assert(b == [ "b", "c", "a" ]);
4854}
4855
4856/// Ditto
4857auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
4858if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4859{
4860    return Zip!Ranges(ranges, sp);
4861}
4862
4863/**
4864   Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop.
4865   By default stop at the end of the shortest of all ranges.
4866*/
4867enum StoppingPolicy
4868{
4869    /// Stop when the shortest range is exhausted
4870    shortest,
4871    /// Stop when the longest range is exhausted
4872    longest,
4873    /// Require that all ranges are equal
4874    requireSameLength,
4875}
4876
4877///
4878pure @safe unittest
4879{
4880    import std.algorithm.comparison : equal;
4881    import std.exception : assertThrown;
4882    import std.range.primitives;
4883    import std.typecons : tuple;
4884
4885    auto a = [1, 2, 3];
4886    auto b = [4, 5, 6, 7];
4887
4888    auto shortest = zip(StoppingPolicy.shortest, a, b);
4889    assert(shortest.equal([
4890        tuple(1, 4),
4891        tuple(2, 5),
4892        tuple(3, 6)
4893    ]));
4894
4895    auto longest = zip(StoppingPolicy.longest, a, b);
4896    assert(longest.equal([
4897        tuple(1, 4),
4898        tuple(2, 5),
4899        tuple(3, 6),
4900        tuple(0, 7)
4901    ]));
4902
4903    auto same = zip(StoppingPolicy.requireSameLength, a, b);
4904    same.popFrontN(3);
4905    assertThrown!Exception(same.popFront);
4906}
4907
4908/+
4909Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest`
4910except it properly implements `back` and `popBack` in the
4911case of uneven ranges or disables those operations when
4912it is not possible to guarantee they are correct.
4913+/
4914package template ZipShortest(Ranges...)
4915if (Ranges.length && __traits(compiles,
4916    {
4917        static assert(allSatisfy!(isInputRange, Ranges));
4918    }))
4919{
4920    alias ZipShortest = .ZipShortest!(
4921        Ranges.length == 1 || allSatisfy!(isInfinite, Ranges)
4922            ? Yes.allKnownSameLength
4923            : No.allKnownSameLength,
4924        Ranges);
4925}
4926/+ non-public, ditto +/
4927package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...)
4928if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4929{
4930    import std.format : format; //for generic mixins
4931    import std.meta : anySatisfy, templateOr;
4932    import std.typecons : Tuple;
4933
4934    deprecated("Use of an undocumented alias R.")
4935    alias R = Ranges; // Unused here but defined in case library users rely on it.
4936    private Ranges ranges;
4937    alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
4938
4939    /+
4940       Builds an object. Usually this is invoked indirectly by using the
4941       $(LREF zip) function.
4942    +/
4943    this(Ranges rs)
4944    {
4945        ranges[] = rs[];
4946    }
4947
4948    /+
4949       Returns `true` if the range is at end.
4950    +/
4951    static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges)
4952        : allSatisfy!(isInfinite, Ranges))
4953    {
4954        enum bool empty = false;
4955    }
4956    else
4957    {
4958        @property bool empty()
4959        {
4960            static if (allKnownSameLength)
4961            {
4962                return ranges[0].empty;
4963            }
4964            else
4965            {
4966                static foreach (i; 0 .. Ranges.length)
4967                {
4968                    if (ranges[i].empty)
4969                        return true;
4970                }
4971                return false;
4972            }
4973        }
4974    }
4975
4976    /+
4977       Forward range primitive. Only present if each constituent range is a
4978       forward range.
4979    +/
4980    static if (allSatisfy!(isForwardRange, Ranges))
4981    @property typeof(this) save()
4982    {
4983        return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length)));
4984    }
4985
4986    /+
4987       Returns the current iterated element.
4988    +/
4989    @property ElementType front()
4990    {
4991        return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length)));
4992    }
4993
4994    /+
4995       Sets the front of all iterated ranges. Only present if each constituent
4996       range has assignable elements.
4997    +/
4998    static if (allSatisfy!(hasAssignableElements, Ranges))
4999    @property void front()(ElementType v)
5000    {
5001        static foreach (i; 0 .. Ranges.length)
5002            ranges[i].front = v[i];
5003    }
5004
5005    /+
5006       Moves out the front. Present if each constituent range has mobile elements.
5007    +/
5008    static if (allSatisfy!(hasMobileElements, Ranges))
5009    ElementType moveFront()()
5010    {
5011        return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length)));
5012    }
5013
5014    private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges)
5015        && (allKnownSameLength
5016            || allSatisfy!(isRandomAccessRange, Ranges)
5017            // Could also add the case where there is one non-infinite bidirectional
5018            // range that defines `length` and all others are infinite random access
5019            // ranges. Adding this would require appropriate branches in
5020            // back/moveBack/popBack.
5021            );
5022
5023    /+
5024       Returns the rightmost element. Present if all constituent ranges are
5025       bidirectional and either there is a compile-time guarantee that all
5026       ranges have the same length (in `allKnownSameLength`) or all ranges
5027       provide random access to elements.
5028    +/
5029    static if (isBackWellDefined)
5030    @property ElementType back()
5031    {
5032        static if (allKnownSameLength)
5033        {
5034            return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length)));
5035        }
5036        else
5037        {
5038            const backIndex = length - 1;
5039            return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length)));
5040        }
5041    }
5042
5043    /+
5044       Moves out the back. Present if `back` is defined and
5045       each constituent range has mobile elements.
5046    +/
5047    static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges))
5048    ElementType moveBack()()
5049    {
5050        static if (allKnownSameLength)
5051        {
5052            return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length)));
5053        }
5054        else
5055        {
5056            const backIndex = length - 1;
5057            return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length)));
5058        }
5059    }
5060
5061    /+
5062       Sets the rightmost element. Only present if `back` is defined and
5063       each constituent range has assignable elements.
5064    +/
5065    static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges))
5066    @property void back()(ElementType v)
5067    {
5068        static if (allKnownSameLength)
5069        {
5070            static foreach (i; 0 .. Ranges.length)
5071                ranges[i].back = v[i];
5072        }
5073        else
5074        {
5075            const backIndex = length - 1;
5076            static foreach (i; 0 .. Ranges.length)
5077                ranges[i][backIndex] = v[i];
5078        }
5079    }
5080
5081    /+
5082       Calls `popFront` on each constituent range.
5083    +/
5084    void popFront()
5085    {
5086        static foreach (i; 0 .. Ranges.length)
5087            ranges[i].popFront();
5088    }
5089
5090    /+
5091       Pops the rightmost element. Present if `back` is defined.
5092    +/
5093    static if (isBackWellDefined)
5094    void popBack()
5095    {
5096        static if (allKnownSameLength)
5097        {
5098            static foreach (i; 0 .. Ranges.length)
5099                ranges[i].popBack;
5100        }
5101        else
5102        {
5103            const len = length;
5104            static foreach (i; 0 .. Ranges.length)
5105                static if (!isInfinite!(Ranges[i]))
5106                    if (ranges[i].length == len)
5107                        ranges[i].popBack();
5108        }
5109    }
5110
5111    /+
5112       Returns the length of this range. Defined if at least one
5113       constituent range defines `length` and the other ranges all also
5114       define `length` or are infinite, or if at least one constituent
5115       range defines `length` and there is a compile-time guarantee that
5116       all ranges have the same length (in `allKnownSameLength`).
5117    +/
5118    static if (allKnownSameLength
5119        ? anySatisfy!(hasLength, Ranges)
5120        : (anySatisfy!(hasLength, Ranges)
5121            && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
5122    {
5123        @property size_t length()
5124        {
5125           static foreach (i, Range; Ranges)
5126           {
5127                static if (hasLength!Range)
5128                {
5129                    static if (!is(typeof(minLen) == size_t))
5130                        size_t minLen = ranges[i].length;
5131                    else static if (!allKnownSameLength)
5132                    {{
5133                        const x = ranges[i].length;
5134                        if (x < minLen) minLen = x;
5135                    }}
5136                }
5137            }
5138            return minLen;
5139        }
5140
5141        alias opDollar = length;
5142    }
5143
5144    /+
5145       Returns a slice of the range. Defined if all constituent ranges
5146       support slicing.
5147    +/
5148    static if (allSatisfy!(hasSlicing, Ranges))
5149    {
5150        // Note: we will know that all elements of the resultant range
5151        // will have the same length but we cannot change `allKnownSameLength`
5152        // because the `hasSlicing` predicate tests that the result returned
5153        // by `opSlice` has the same type as the receiver.
5154        auto opSlice()(size_t from, size_t to)
5155        {
5156            //(ranges[0][from .. to], ranges[1][from .. to], ...)
5157            enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length));
5158            static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs)))
5159                return mixin(`typeof(this)`~sliceArgs);
5160            else
5161                // The type is different anyway so we might as well
5162                // explicitly set allKnownSameLength.
5163                return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`
5164                    ~sliceArgs);
5165        }
5166    }
5167
5168    /+
5169       Returns the `n`th element in the composite range. Defined if all
5170       constituent ranges offer random access.
5171    +/
5172    static if (allSatisfy!(isRandomAccessRange, Ranges))
5173    ElementType opIndex()(size_t n)
5174    {
5175        return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length)));
5176    }
5177
5178    /+
5179       Sets the `n`th element in the composite range. Defined if all
5180       constituent ranges offer random access and have assignable elements.
5181    +/
5182    static if (allSatisfy!(isRandomAccessRange, Ranges)
5183        && allSatisfy!(hasAssignableElements, Ranges))
5184    void opIndexAssign()(ElementType v, size_t n)
5185    {
5186        static foreach (i; 0 .. Ranges.length)
5187            ranges[i][n] = v[i];
5188    }
5189
5190    /+
5191       Destructively reads the `n`th element in the composite
5192       range. Defined if all constituent ranges offer random
5193       access and have mobile elements.
5194    +/
5195    static if (allSatisfy!(isRandomAccessRange, Ranges)
5196        && allSatisfy!(hasMobileElements, Ranges))
5197    ElementType moveAt()(size_t n)
5198    {
5199        return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length)));
5200    }
5201}
5202
5203pure @system unittest
5204{
5205    import std.algorithm.comparison : equal;
5206    import std.algorithm.iteration : filter, map;
5207    import std.algorithm.mutation : swap;
5208    import std.algorithm.sorting : sort;
5209
5210    import std.exception : assertThrown, assertNotThrown;
5211    import std.typecons : tuple;
5212
5213    int[] a = [ 1, 2, 3 ];
5214    float[] b = [ 1.0, 2.0, 3.0 ];
5215    foreach (e; zip(a, b))
5216    {
5217        assert(e[0] == e[1]);
5218    }
5219
5220    swap(a[0], a[1]);
5221    {
5222        auto z = zip(a, b);
5223    }
5224    //swap(z.front(), z.back());
5225    sort!("a[0] < b[0]")(zip(a, b));
5226    assert(a == [1, 2, 3]);
5227    assert(b == [2.0, 1.0, 3.0]);
5228
5229    auto z = zip(StoppingPolicy.requireSameLength, a, b);
5230    assertNotThrown(z.popBack());
5231    assertNotThrown(z.popBack());
5232    assertNotThrown(z.popBack());
5233    assert(z.empty);
5234    assertThrown(z.popBack());
5235
5236    a = [ 1, 2, 3 ];
5237    b = [ 1.0, 2.0, 3.0 ];
5238    sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
5239    assert(a == [3, 2, 1]);
5240    assert(b == [3.0, 2.0, 1.0]);
5241
5242    a = [];
5243    b = [];
5244    assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
5245
5246    // Test infiniteness propagation.
5247    static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
5248
5249    // Test stopping policies with both value and reference.
5250    auto a1 = [1, 2];
5251    auto a2 = [1, 2, 3];
5252    auto stuff = tuple(tuple(a1, a2),
5253            tuple(filter!"a"(a1), filter!"a"(a2)));
5254
5255    alias FOO = Zip!(immutable(int)[], immutable(float)[]);
5256
5257    foreach (t; stuff.expand)
5258    {
5259        auto arr1 = t[0];
5260        auto arr2 = t[1];
5261        auto zShortest = zip(arr1, arr2);
5262        assert(equal(map!"a[0]"(zShortest), [1, 2]));
5263        assert(equal(map!"a[1]"(zShortest), [1, 2]));
5264
5265        try {
5266            auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
5267            foreach (elem; zSame) {}
5268            assert(0);
5269        } catch (Throwable) { /* It's supposed to throw.*/ }
5270
5271        auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
5272        assert(!zLongest.ranges[0].empty);
5273        assert(!zLongest.ranges[1].empty);
5274
5275        zLongest.popFront();
5276        zLongest.popFront();
5277        assert(!zLongest.empty);
5278        assert(zLongest.ranges[0].empty);
5279        assert(!zLongest.ranges[1].empty);
5280
5281        zLongest.popFront();
5282        assert(zLongest.empty);
5283    }
5284
5285    // https://issues.dlang.org/show_bug.cgi?id=8900
5286    assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
5287    assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
5288
5289    // https://issues.dlang.org/show_bug.cgi?id=18524
5290    // moveBack instead performs moveFront
5291    {
5292        auto r = zip([1,2,3]);
5293        assert(r.moveBack()[0] == 3);
5294        assert(r.moveFront()[0] == 1);
5295    }
5296
5297    // Doesn't work yet.  Issues w/ emplace.
5298    // static assert(is(Zip!(immutable int[], immutable float[])));
5299
5300
5301    // These unittests pass, but make the compiler consume an absurd amount
5302    // of RAM and time.  Therefore, they should only be run if explicitly
5303    // uncommented when making changes to Zip.  Also, running them using
5304    // make -fwin32.mak unittest makes the compiler completely run out of RAM.
5305    // You need to test just this module.
5306    /+
5307     foreach (DummyType1; AllDummyRanges)
5308     {
5309         DummyType1 d1;
5310         foreach (DummyType2; AllDummyRanges)
5311         {
5312             DummyType2 d2;
5313             auto r = zip(d1, d2);
5314             assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
5315             assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
5316
5317             static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
5318             {
5319                 static assert(isForwardRange!(typeof(r)));
5320             }
5321
5322             static if (isBidirectionalRange!DummyType1 &&
5323                     isBidirectionalRange!DummyType2) {
5324                 static assert(isBidirectionalRange!(typeof(r)));
5325             }
5326             static if (isRandomAccessRange!DummyType1 &&
5327                     isRandomAccessRange!DummyType2) {
5328                 static assert(isRandomAccessRange!(typeof(r)));
5329             }
5330         }
5331     }
5332    +/
5333}
5334
5335nothrow pure @safe unittest
5336{
5337    import std.algorithm.sorting : sort;
5338
5339    auto a = [5,4,3,2,1];
5340    auto b = [3,1,2,5,6];
5341    auto z = zip(a, b);
5342
5343    sort!"a[0] < b[0]"(z);
5344
5345    assert(a == [1, 2, 3, 4, 5]);
5346    assert(b == [6, 5, 2, 1, 3]);
5347}
5348
5349nothrow pure @safe unittest
5350{
5351    import std.algorithm.comparison : equal;
5352    import std.typecons : tuple;
5353
5354    auto LL = iota(1L, 1000L);
5355    auto z = zip(LL, [4]);
5356
5357    assert(equal(z, [tuple(1L,4)]));
5358
5359    auto LL2 = iota(0L, 500L);
5360    auto z2 = zip([7], LL2);
5361    assert(equal(z2, [tuple(7, 0L)]));
5362}
5363
5364// Test for https://issues.dlang.org/show_bug.cgi?id=11196
5365@safe pure unittest
5366{
5367    import std.exception : assertThrown;
5368
5369    static struct S { @disable this(); }
5370    assert(zip((S[5]).init[]).length == 5);
5371    assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
5372    assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
5373}
5374
5375// https://issues.dlang.org/show_bug.cgi?id=12007
5376@nogc nothrow @safe pure unittest
5377{
5378    static struct R
5379    {
5380        enum empty = false;
5381        void popFront(){}
5382        int front(){return 1;} @property
5383        R save(){return this;} @property
5384        void opAssign(R) @disable;
5385    }
5386    R r;
5387    auto z = zip(r, r);
5388    assert(z.save == z);
5389}
5390
5391nothrow pure @system unittest
5392{
5393    import std.typecons : tuple;
5394
5395    auto r1 = [0,1,2];
5396    auto r2 = [1,2,3];
5397    auto z1 = zip(refRange(&r1), refRange(&r2));
5398    auto z2 = z1.save;
5399    z1.popFront();
5400    assert(z1.front == tuple(1,2));
5401    assert(z2.front == tuple(0,1));
5402}
5403
5404@nogc nothrow pure @safe unittest
5405{
5406    // Test zip's `back` and `length` with non-equal ranges.
5407    static struct NonSliceableRandomAccess
5408    {
5409        private int[] a;
5410        @property ref front()
5411        {
5412            return a.front;
5413        }
5414        @property ref back()
5415        {
5416            return a.back;
5417        }
5418        ref opIndex(size_t i)
5419        {
5420            return a[i];
5421        }
5422        void popFront()
5423        {
5424            a.popFront();
5425        }
5426        void popBack()
5427        {
5428            a.popBack();
5429        }
5430        auto moveFront()
5431        {
5432            return a.moveFront();
5433        }
5434        auto moveBack()
5435        {
5436            return a.moveBack();
5437        }
5438        auto moveAt(size_t i)
5439        {
5440            return a.moveAt(i);
5441        }
5442        bool empty() const
5443        {
5444            return a.empty;
5445        }
5446        size_t length() const
5447        {
5448            return a.length;
5449        }
5450        typeof(this) save()
5451        {
5452            return this;
5453        }
5454    }
5455    static assert(isRandomAccessRange!NonSliceableRandomAccess);
5456    static assert(!hasSlicing!NonSliceableRandomAccess);
5457    static foreach (iteration; 0 .. 2)
5458    {{
5459        int[5] data = [101, 102, 103, 201, 202];
5460        static if (iteration == 0)
5461        {
5462            auto r1 = NonSliceableRandomAccess(data[0 .. 3]);
5463            auto r2 = NonSliceableRandomAccess(data[3 .. 5]);
5464        }
5465        else
5466        {
5467            auto r1 = data[0 .. 3];
5468            auto r2 = data[3 .. 5];
5469        }
5470        auto z = zip(r1, r2);
5471        static assert(isRandomAccessRange!(typeof(z)));
5472        assert(z.length == 2);
5473        assert(z.back[0] == 102 && z.back[1] == 202);
5474        z.back = typeof(z.back)(-102, -202);// Assign to back.
5475        assert(z.back[0] == -102 && z.back[1] == -202);
5476        z.popBack();
5477        assert(z.length == 1);
5478        assert(z.back[0] == 101 && z.back[1] == 201);
5479        z.front = typeof(z.front)(-101, -201);
5480        assert(z.moveBack() == typeof(z.back)(-101, -201));
5481        z.popBack();
5482        assert(z.empty);
5483    }}
5484}
5485
5486@nogc nothrow pure @safe unittest
5487{
5488    // Test opSlice on infinite `zip`.
5489    auto z = zip(repeat(1), repeat(2));
5490    assert(hasSlicing!(typeof(z)));
5491    auto slice = z[10 .. 20];
5492    assert(slice.length == 10);
5493    static assert(!is(typeof(z) == typeof(slice)));
5494}
5495
5496/*
5497    Generate lockstep's opApply function as a mixin string.
5498    If withIndex is true prepend a size_t index to the delegate.
5499*/
5500private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
5501{
5502    import std.format : format;
5503
5504    string[] params;
5505    string[] emptyChecks;
5506    string[] dgArgs;
5507    string[] popFronts;
5508    string indexDef;
5509    string indexInc;
5510
5511    if (withIndex)
5512    {
5513        params ~= "size_t";
5514        dgArgs ~= "index";
5515        if (reverse)
5516        {
5517            indexDef = q{
5518                size_t index = ranges[0].length-1;
5519                enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
5520                        "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
5521
5522                foreach (range; ranges[1..$])
5523                    enforce(range.length == ranges[0].length);
5524                };
5525            indexInc = "--index;";
5526        }
5527        else
5528        {
5529            indexDef = "size_t index = 0;";
5530            indexInc = "++index;";
5531        }
5532    }
5533
5534    foreach (idx, Range; Ranges)
5535    {
5536        params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
5537        emptyChecks ~= format("!ranges[%s].empty", idx);
5538        if (reverse)
5539        {
5540            dgArgs ~= format("ranges[%s].back", idx);
5541            popFronts ~= format("ranges[%s].popBack();", idx);
5542        }
5543        else
5544        {
5545            dgArgs ~= format("ranges[%s].front", idx);
5546            popFronts ~= format("ranges[%s].popFront();", idx);
5547        }
5548    }
5549
5550    string name = reverse ? "opApplyReverse" : "opApply";
5551
5552    return format(
5553    q{
5554        int %s(scope int delegate(%s) dg)
5555        {
5556            import std.exception : enforce;
5557
5558            auto ranges = _ranges;
5559            int res;
5560            %s
5561
5562            while (%s)
5563            {
5564                res = dg(%s);
5565                if (res) break;
5566                %s
5567                %s
5568            }
5569
5570            if (_stoppingPolicy == StoppingPolicy.requireSameLength)
5571            {
5572                foreach (range; ranges)
5573                    enforce(range.empty);
5574            }
5575            return res;
5576        }
5577    }, name, params.join(", "), indexDef,
5578       emptyChecks.join(" && "), dgArgs.join(", "),
5579       popFronts.join("\n                "),
5580       indexInc);
5581}
5582
5583/**
5584   Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
5585   $(LREF zip) it allows reference access to its elements. If only a single
5586   range is passed in, the `Lockstep` aliases itself away.  If the
5587   ranges are of different lengths and `s` == `StoppingPolicy.shortest`
5588   stop after the shortest range is empty.  If the ranges are of different
5589   lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
5590   exception.  `s` may not be `StoppingPolicy.longest`, and passing this
5591   will throw an exception.
5592
5593   Iterating over `Lockstep` in reverse and with an index is only possible
5594   when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
5595   indexes. If an attempt is made at iterating in reverse when `s` ==
5596   `StoppingPolicy.shortest`, an exception will be thrown.
5597
5598   By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
5599
5600   Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be
5601   inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to
5602   a different implementation.
5603
5604   See_Also: $(LREF zip)
5605
5606       `lockstep` is similar to $(LREF zip), but `zip` bundles its
5607       elements and returns a range.
5608       `lockstep` also supports reference access.
5609       Use `zip` if you want to pass the result to a range function.
5610*/
5611struct Lockstep(Ranges...)
5612if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
5613{
5614    ///
5615    this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
5616    {
5617        import std.exception : enforce;
5618
5619        _ranges = ranges;
5620        enforce(sp != StoppingPolicy.longest,
5621                "Can't use StoppingPolicy.Longest on Lockstep.");
5622        _stoppingPolicy = sp;
5623    }
5624
5625    mixin(lockstepMixin!Ranges(false, false));
5626    mixin(lockstepMixin!Ranges(true, false));
5627    static if (allSatisfy!(isBidirectionalRange, Ranges))
5628    {
5629        mixin(lockstepMixin!Ranges(false, true));
5630        static if (allSatisfy!(hasLength, Ranges))
5631        {
5632            mixin(lockstepMixin!Ranges(true, true));
5633        }
5634        else
5635        {
5636            mixin(lockstepReverseFailMixin!Ranges(true));
5637        }
5638    }
5639    else
5640    {
5641        mixin(lockstepReverseFailMixin!Ranges(false));
5642        mixin(lockstepReverseFailMixin!Ranges(true));
5643    }
5644
5645private:
5646    alias R = Ranges;
5647    R _ranges;
5648    StoppingPolicy _stoppingPolicy;
5649}
5650
5651/// Ditto
5652Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
5653if (allSatisfy!(isInputRange, Ranges))
5654{
5655    return Lockstep!(Ranges)(ranges);
5656}
5657/// Ditto
5658Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
5659if (allSatisfy!(isInputRange, Ranges))
5660{
5661    static if (Ranges.length > 1)
5662        return Lockstep!Ranges(ranges, s);
5663    else
5664        return ranges[0];
5665}
5666
5667///
5668@system unittest
5669{
5670   auto arr1 = [1,2,3,4,5,100];
5671   auto arr2 = [6,7,8,9,10];
5672
5673   foreach (ref a, b; lockstep(arr1, arr2))
5674   {
5675       a += b;
5676   }
5677
5678   assert(arr1 == [7,9,11,13,15,100]);
5679
5680   /// Lockstep also supports iterating with an index variable:
5681   foreach (index, a, b; lockstep(arr1, arr2))
5682   {
5683       assert(arr1[index] == a);
5684       assert(arr2[index] == b);
5685   }
5686}
5687
5688// https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
5689@system unittest
5690{
5691    auto arr1 = [0, 1, 2, 3];
5692    auto arr2 = [4, 5, 6, 7];
5693
5694    size_t n = arr1.length -1;
5695    foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
5696    {
5697        assert(n == index);
5698        assert(index == a);
5699        assert(arr1[index] == a);
5700        assert(arr2[index] == b);
5701        n--;
5702    }
5703
5704    auto arr3 = [4, 5];
5705    n = 1;
5706    foreach_reverse (a, b; lockstep(arr1, arr3))
5707    {
5708        assert(a == arr1[$-n] && b == arr3[$-n]);
5709        n++;
5710    }
5711}
5712
5713@system unittest
5714{
5715    import std.algorithm.iteration : filter;
5716    import std.conv : to;
5717
5718    // The filters are to make these the lowest common forward denominator ranges,
5719    // i.e. w/o ref return, random access, length, etc.
5720    auto foo = filter!"a"([1,2,3,4,5]);
5721    immutable bar = [6f,7f,8f,9f,10f].idup;
5722    auto l = lockstep(foo, bar);
5723
5724    // Should work twice.  These are forward ranges with implicit save.
5725    foreach (i; 0 .. 2)
5726    {
5727        uint[] res1;
5728        float[] res2;
5729
5730        foreach (a, ref b; l)
5731        {
5732            res1 ~= a;
5733            res2 ~= b;
5734        }
5735
5736        assert(res1 == [1,2,3,4,5]);
5737        assert(res2 == [6,7,8,9,10]);
5738        assert(bar == [6f,7f,8f,9f,10f]);
5739    }
5740
5741    // Doc example.
5742    auto arr1 = [1,2,3,4,5];
5743    auto arr2 = [6,7,8,9,10];
5744
5745    foreach (ref a, ref b; lockstep(arr1, arr2))
5746    {
5747        a += b;
5748    }
5749
5750    assert(arr1 == [7,9,11,13,15]);
5751
5752    // Make sure StoppingPolicy.requireSameLength doesn't throw.
5753    auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
5754
5755    int k = 1;
5756    foreach (a, b; ls)
5757    {
5758        assert(a - b == k);
5759        ++k;
5760    }
5761
5762    // Make sure StoppingPolicy.requireSameLength throws.
5763    arr2.popBack();
5764    ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
5765
5766    try {
5767        foreach (a, b; ls) {}
5768        assert(0);
5769    } catch (Exception) {}
5770
5771    // Just make sure 1-range case instantiates. This hangs the compiler
5772    // when no explicit stopping policy is specified due to
5773    // https://issues.dlang.org/show_bug.cgi?id=4652
5774    auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
5775    foreach (i, a; stuff)
5776    {
5777        assert(stuff[i] == a);
5778    }
5779
5780    // Test with indexing.
5781    uint[] res1;
5782    float[] res2;
5783    size_t[] indices;
5784    foreach (i, a, b; lockstep(foo, bar))
5785    {
5786        indices ~= i;
5787        res1 ~= a;
5788        res2 ~= b;
5789    }
5790
5791    assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
5792    assert(res1 == [1,2,3,4,5]);
5793    assert(res2 == [6f,7f,8f,9f,10f]);
5794
5795    // Make sure we've worked around the relevant compiler bugs and this at least
5796    // compiles w/ >2 ranges.
5797    lockstep(foo, foo, foo);
5798
5799    // Make sure it works with const.
5800    const(int[])[] foo2 = [[1, 2, 3]];
5801    const(int[])[] bar2 = [[4, 5, 6]];
5802    auto c = chain(foo2, bar2);
5803
5804    foreach (f, b; lockstep(c, c)) {}
5805
5806    // Regression 10468
5807    foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
5808}
5809
5810@system unittest
5811{
5812    struct RvalueRange
5813    {
5814        int[] impl;
5815        @property bool empty() { return impl.empty; }
5816        @property int front() { return impl[0]; } // N.B. non-ref
5817        void popFront() { impl.popFront(); }
5818    }
5819    auto data1 = [ 1, 2, 3, 4 ];
5820    auto data2 = [ 5, 6, 7, 8 ];
5821    auto r1 = RvalueRange(data1);
5822    auto r2 = data2;
5823    foreach (a, ref b; lockstep(r1, r2))
5824    {
5825        a++;
5826        b++;
5827    }
5828    assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
5829    assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
5830
5831    // Since r1 is by-value only, the compiler should reject attempts to
5832    // foreach over it with ref.
5833    static assert(!__traits(compiles, {
5834        foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
5835    }));
5836}
5837
5838private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
5839{
5840    import std.format : format;
5841    string[] params;
5842    string message;
5843
5844    if (withIndex)
5845    {
5846        message = "Indexed reverse iteration with lockstep is only supported"
5847        ~"if all ranges are bidirectional and have a length.\n";
5848    }
5849    else
5850    {
5851        message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
5852    }
5853
5854    if (withIndex)
5855    {
5856        params ~= "size_t";
5857    }
5858
5859    foreach (idx, Range; Ranges)
5860    {
5861        params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
5862    }
5863
5864    return format(
5865    q{
5866        int opApplyReverse()(scope int delegate(%s) dg)
5867        {
5868            static assert(false, "%s");
5869        }
5870    }, params.join(", "), message);
5871}
5872
5873// For generic programming, make sure Lockstep!(Range) is well defined for a
5874// single range.
5875template Lockstep(Range)
5876{
5877    alias Lockstep = Range;
5878}
5879
5880/**
5881Creates a mathematical sequence given the initial values and a
5882recurrence function that computes the next value from the existing
5883values. The sequence comes in the form of an infinite forward
5884range. The type `Recurrence` itself is seldom used directly; most
5885often, recurrences are obtained by calling the function $(D
5886recurrence).
5887
5888When calling `recurrence`, the function that computes the next
5889value is specified as a template argument, and the initial values in
5890the recurrence are passed as regular arguments. For example, in a
5891Fibonacci sequence, there are two initial values (and therefore a
5892state size of 2) because computing the next Fibonacci value needs the
5893past two values.
5894
5895The signature of this function should be:
5896----
5897auto fun(R)(R state, size_t n)
5898----
5899where `n` will be the index of the current value, and `state` will be an
5900opaque state vector that can be indexed with array-indexing notation
5901`state[i]`, where valid values of `i` range from $(D (n - 1)) to
5902$(D (n - State.length)).
5903
5904If the function is passed in string form, the state has name `"a"`
5905and the zero-based index in the recurrence has name `"n"`. The
5906given string must return the desired value for `a[n]` given
5907`a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
5908state size is dictated by the number of arguments passed to the call
5909to `recurrence`. The `Recurrence` struct itself takes care of
5910managing the recurrence's state and shifting it appropriately.
5911 */
5912struct Recurrence(alias fun, StateType, size_t stateSize)
5913{
5914    import std.functional : binaryFun;
5915
5916    StateType[stateSize] _state;
5917    size_t _n;
5918
5919    this(StateType[stateSize] initial) { _state = initial; }
5920
5921    void popFront()
5922    {
5923        static auto trustedCycle(ref typeof(_state) s) @trusted
5924        {
5925            return cycle(s);
5926        }
5927        // The cast here is reasonable because fun may cause integer
5928        // promotion, but needs to return a StateType to make its operation
5929        // closed.  Therefore, we have no other choice.
5930        _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
5931            trustedCycle(_state), _n + stateSize);
5932        ++_n;
5933    }
5934
5935    @property StateType front()
5936    {
5937        return _state[_n % stateSize];
5938    }
5939
5940    @property typeof(this) save()
5941    {
5942        return this;
5943    }
5944
5945    enum bool empty = false;
5946}
5947
5948///
5949pure @safe nothrow unittest
5950{
5951    import std.algorithm.comparison : equal;
5952
5953    // The Fibonacci numbers, using function in string form:
5954    // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
5955    auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5956    assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
5957
5958    // The factorials, using function in lambda form:
5959    auto fac = recurrence!((a,n) => a[n-1] * n)(1);
5960    assert(take(fac, 10).equal([
5961        1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
5962    ]));
5963
5964    // The triangular numbers, using function in explicit form:
5965    static size_t genTriangular(R)(R state, size_t n)
5966    {
5967        return state[n-1] + n;
5968    }
5969    auto tri = recurrence!genTriangular(0);
5970    assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
5971}
5972
5973/// Ditto
5974Recurrence!(fun, CommonType!(State), State.length)
5975recurrence(alias fun, State...)(State initial)
5976{
5977    CommonType!(State)[State.length] state;
5978    foreach (i, Unused; State)
5979    {
5980        state[i] = initial[i];
5981    }
5982    return typeof(return)(state);
5983}
5984
5985pure @safe nothrow unittest
5986{
5987    import std.algorithm.comparison : equal;
5988
5989    auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5990    static assert(isForwardRange!(typeof(fib)));
5991
5992    int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
5993    assert(equal(take(fib, 10), witness));
5994    foreach (e; take(fib, 10)) {}
5995    auto fact = recurrence!("n * a[n-1]")(1);
5996    assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
5997                            2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
5998    auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
5999    foreach (e; take(piapprox, 20)) {}
6000    // Thanks to yebblies for this test and the associated fix
6001    auto r = recurrence!"a[n-2]"(1, 2);
6002    witness = [1, 2, 1, 2, 1];
6003    assert(equal(take(r, 5), witness));
6004}
6005
6006/**
6007   `Sequence` is similar to `Recurrence` except that iteration is
6008   presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
6009   closed form). This means that the `n`th element in the series is
6010   computable directly from the initial values and `n` itself. This
6011   implies that the interface offered by `Sequence` is a random-access
6012   range, as opposed to the regular `Recurrence`, which only offers
6013   forward iteration.
6014
6015   The state of the sequence is stored as a `Tuple` so it can be
6016   heterogeneous.
6017*/
6018struct Sequence(alias fun, State)
6019{
6020private:
6021    import std.functional : binaryFun;
6022
6023    alias compute = binaryFun!(fun, "a", "n");
6024    alias ElementType = typeof(compute(State.init, cast(size_t) 1));
6025    State _state;
6026    size_t _n;
6027
6028    static struct DollarToken{}
6029
6030public:
6031    this(State initial, size_t n = 0)
6032    {
6033        _state = initial;
6034        _n = n;
6035    }
6036
6037    @property ElementType front()
6038    {
6039        return compute(_state, _n);
6040    }
6041
6042    void popFront()
6043    {
6044        ++_n;
6045    }
6046
6047    enum opDollar = DollarToken();
6048
6049    auto opSlice(size_t lower, size_t upper)
6050    in
6051    {
6052        assert(
6053            upper >= lower,
6054            "Attempting to slice a Sequence with a larger first argument than the second."
6055        );
6056    }
6057    do
6058    {
6059        return typeof(this)(_state, _n + lower).take(upper - lower);
6060    }
6061
6062    auto opSlice(size_t lower, DollarToken)
6063    {
6064        return typeof(this)(_state, _n + lower);
6065    }
6066
6067    ElementType opIndex(size_t n)
6068    {
6069        return compute(_state, n + _n);
6070    }
6071
6072    enum bool empty = false;
6073
6074    @property Sequence save() { return this; }
6075}
6076
6077/// Ditto
6078auto sequence(alias fun, State...)(State args)
6079{
6080    import std.typecons : Tuple, tuple;
6081    alias Return = Sequence!(fun, Tuple!State);
6082    return Return(tuple(args));
6083}
6084
6085/// Odd numbers, using function in string form:
6086pure @safe nothrow @nogc unittest
6087{
6088    auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6089    assert(odds.front == 1);
6090    odds.popFront();
6091    assert(odds.front == 3);
6092    odds.popFront();
6093    assert(odds.front == 5);
6094}
6095
6096/// Triangular numbers, using function in lambda form:
6097pure @safe nothrow @nogc unittest
6098{
6099    auto tri = sequence!((a,n) => n*(n+1)/2)();
6100
6101    // Note random access
6102    assert(tri[0] == 0);
6103    assert(tri[3] == 6);
6104    assert(tri[1] == 1);
6105    assert(tri[4] == 10);
6106    assert(tri[2] == 3);
6107}
6108
6109/// Fibonacci numbers, using function in explicit form:
6110@safe nothrow @nogc unittest
6111{
6112    import std.math.exponential : pow;
6113    import std.math.rounding : round;
6114    import std.math.algebraic : sqrt;
6115    static ulong computeFib(S)(S state, size_t n)
6116    {
6117        // Binet's formula
6118        return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6119                                 state[2]));
6120    }
6121    auto fib = sequence!computeFib(
6122        (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
6123        (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
6124        sqrt(5.0));
6125
6126    // Note random access with [] operator
6127    assert(fib[1] == 1);
6128    assert(fib[4] == 5);
6129    assert(fib[3] == 3);
6130    assert(fib[2] == 2);
6131    assert(fib[9] == 55);
6132}
6133
6134pure @safe nothrow @nogc unittest
6135{
6136    import std.typecons : Tuple, tuple;
6137    auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6138    static assert(isForwardRange!(typeof(y)));
6139
6140    //@@BUG
6141    //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6142    //foreach (e; take(y, 15))
6143    {}                                 //writeln(e);
6144
6145    auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6146        tuple(1, 2));
6147    for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6148    {
6149        assert(odds.front == odds[0]);
6150        assert(odds[0] == currentOdd);
6151        odds.popFront();
6152    }
6153}
6154
6155pure @safe nothrow @nogc unittest
6156{
6157    import std.algorithm.comparison : equal;
6158
6159    auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6160    static assert(hasSlicing!(typeof(odds)));
6161
6162    //Note: don't use drop or take as the target of an equal,
6163    //since they'll both just forward to opSlice, making the tests irrelevant
6164
6165    // static slicing tests
6166    assert(equal(odds[0 .. 5], only(1,  3,  5,  7,  9)));
6167    assert(equal(odds[3 .. 7], only(7,  9, 11, 13)));
6168
6169    // relative slicing test, testing slicing is NOT agnostic of state
6170    auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6171    assert(equal(odds_less5[0 ..  3], only(11, 13, 15)));
6172    assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6173
6174    //Infinite slicing tests
6175    odds = odds[10 .. $];
6176    assert(equal(odds.take(3), only(21, 23, 25)));
6177}
6178
6179// https://issues.dlang.org/show_bug.cgi?id=5036
6180pure @safe nothrow unittest
6181{
6182    auto s = sequence!((a, n) => new int)(0);
6183    assert(s.front != s.front);  // no caching
6184}
6185
6186// iota
6187/**
6188   Creates a range of values that span the given starting and stopping
6189   values.
6190
6191   Params:
6192   begin = The starting value.
6193   end = The value that serves as the stopping criterion. This value is not
6194        included in the range.
6195   step = The value to add to the current value at each iteration.
6196
6197   Returns:
6198   A range that goes through the numbers `begin`, $(D begin + step),
6199   $(D begin + 2 * step), `...`, up to and excluding `end`.
6200
6201   The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6202   0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6203   is returned. If $(D step == 0) then $(D begin == end) is an error.
6204
6205   For built-in types, the range returned is a random access range. For
6206   user-defined types that support `++`, the range is an input
6207   range.
6208
6209   An integral iota also supports `in` operator from the right. It takes
6210   the stepping into account, the integral won't be considered
6211   contained if it falls between two consecutive values of the range.
6212   `contains` does the same as in, but from lefthand side.
6213
6214    Example:
6215    ---
6216    void main()
6217    {
6218        import std.stdio;
6219
6220        // The following groups all produce the same output of:
6221        // 0 1 2 3 4
6222
6223        foreach (i; 0 .. 5)
6224            writef("%s ", i);
6225        writeln();
6226
6227        import std.range : iota;
6228        foreach (i; iota(0, 5))
6229            writef("%s ", i);
6230        writeln();
6231
6232        writefln("%(%s %|%)", iota(0, 5));
6233
6234        import std.algorithm.iteration : map;
6235        import std.algorithm.mutation : copy;
6236        import std.format;
6237        iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6238        writeln();
6239    }
6240    ---
6241*/
6242auto iota(B, E, S)(B begin, E end, S step)
6243if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6244        && isIntegral!S)
6245{
6246    import std.conv : unsigned;
6247
6248    alias Value = CommonType!(Unqual!B, Unqual!E);
6249    alias StepType = Unqual!S;
6250
6251    assert(step != 0 || begin == end);
6252
6253    static struct Result
6254    {
6255        private Value current, last;
6256        private StepType step; // by convention, 0 if range is empty
6257
6258        this(Value current, Value pastLast, StepType step)
6259        {
6260            if (current < pastLast && step > 0)
6261            {
6262                // Iterating upward
6263                assert(unsigned((pastLast - current) / step) <= size_t.max);
6264                // Cast below can't fail because current < pastLast
6265                this.last = cast(Value) (pastLast - 1);
6266                this.last -= unsigned(this.last - current) % step;
6267            }
6268            else if (current > pastLast && step < 0)
6269            {
6270                // Iterating downward
6271                assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6272                // Cast below can't fail because current > pastLast
6273                this.last = cast(Value) (pastLast + 1);
6274                this.last += unsigned(current - this.last) % (0 - step);
6275            }
6276            else
6277            {
6278                // Initialize an empty range
6279                this.step = 0;
6280                return;
6281            }
6282            this.step = step;
6283            this.current = current;
6284        }
6285
6286        @property bool empty() const { return step == 0; }
6287        @property inout(Value) front() inout { assert(!empty); return current; }
6288        void popFront()
6289        {
6290            assert(!empty);
6291            if (current == last) step = 0;
6292            else current += step;
6293        }
6294
6295        @property inout(Value) back() inout
6296        {
6297            assert(!empty);
6298            return last;
6299        }
6300        void popBack()
6301        {
6302            assert(!empty);
6303            if (current == last) step = 0;
6304            else last -= step;
6305        }
6306
6307        @property auto save() { return this; }
6308
6309        inout(Value) opIndex(ulong n) inout
6310        {
6311            assert(n < this.length);
6312
6313            // Just cast to Value here because doing so gives overflow behavior
6314            // consistent with calling popFront() n times.
6315            return cast(inout Value) (current + step * n);
6316        }
6317        auto opBinaryRight(string op)(Value val) const
6318        if (op == "in")
6319        {
6320            if (empty) return false;
6321            //cast to avoid becoming unsigned
6322            auto supposedIndex = cast(StepType)(val - current) / step;
6323            return supposedIndex < length && supposedIndex * step + current == val;
6324        }
6325        auto contains(Value x){return x in this;}
6326        inout(Result) opSlice() inout { return this; }
6327        inout(Result) opSlice(ulong lower, ulong upper) inout
6328        {
6329            assert(upper >= lower && upper <= this.length);
6330
6331            return cast(inout Result) Result(
6332                cast(Value)(current + lower * step),
6333                cast(Value)(current + upper * step),
6334                step);
6335        }
6336        @property size_t length() const
6337        {
6338            if (step > 0)
6339                return 1 + cast(size_t) (unsigned(last - current) / step);
6340            if (step < 0)
6341                return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6342            return 0;
6343        }
6344
6345        alias opDollar = length;
6346    }
6347
6348    return Result(begin, end, step);
6349}
6350
6351/// Ditto
6352auto iota(B, E)(B begin, E end)
6353if (isFloatingPoint!(CommonType!(B, E)))
6354{
6355    return iota(begin, end, CommonType!(B, E)(1));
6356}
6357
6358/// Ditto
6359auto iota(B, E)(B begin, E end)
6360if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6361{
6362    import std.conv : unsigned;
6363
6364    alias Value = CommonType!(Unqual!B, Unqual!E);
6365
6366    static struct Result
6367    {
6368        private Value current, pastLast;
6369
6370        this(Value current, Value pastLast)
6371        {
6372            if (current < pastLast)
6373            {
6374                assert(unsigned(pastLast - current) <= size_t.max,
6375                    "`iota` range is too long");
6376
6377                this.current = current;
6378                this.pastLast = pastLast;
6379            }
6380            else
6381            {
6382                // Initialize an empty range
6383                this.current = this.pastLast = current;
6384            }
6385        }
6386
6387        @property bool empty() const { return current == pastLast; }
6388        @property inout(Value) front() inout
6389        {
6390            assert(!empty, "Attempt to access `front` of empty `iota` range");
6391            return current;
6392        }
6393        void popFront()
6394        {
6395            assert(!empty, "Attempt to `popFront` of empty `iota` range");
6396            ++current;
6397        }
6398
6399        @property inout(Value) back() inout
6400        {
6401            assert(!empty, "Attempt to access `back` of empty `iota` range");
6402            return cast(inout(Value))(pastLast - 1);
6403        }
6404        void popBack()
6405        {
6406            assert(!empty, "Attempt to `popBack` of empty `iota` range");
6407            --pastLast;
6408        }
6409
6410        @property auto save() { return this; }
6411
6412        inout(Value) opIndex(size_t n) inout
6413        {
6414            assert(n < this.length,
6415                "Attempt to read out-of-bounds index of `iota` range");
6416
6417            // Just cast to Value here because doing so gives overflow behavior
6418            // consistent with calling popFront() n times.
6419            return cast(inout Value) (current + n);
6420        }
6421        auto opBinaryRight(string op)(Value val) const
6422        if (op == "in")
6423        {
6424            return current <= val && val < pastLast;
6425        }
6426        auto contains(Value x){return x in this;}
6427        inout(Result) opSlice() inout { return this; }
6428        inout(Result) opSlice(ulong lower, ulong upper) inout
6429        {
6430            assert(upper >= lower && upper <= this.length,
6431                "Attempt to get out-of-bounds slice of `iota` range");
6432
6433            return cast(inout Result) Result(cast(Value)(current + lower),
6434                                            cast(Value)(pastLast - (length - upper)));
6435        }
6436        @property size_t length() const
6437        {
6438            return cast(size_t)(pastLast - current);
6439        }
6440
6441        alias opDollar = length;
6442    }
6443
6444    return Result(begin, end);
6445}
6446
6447/// Ditto
6448auto iota(E)(E end)
6449if (is(typeof(iota(E(0), end))))
6450{
6451    E begin = E(0);
6452    return iota(begin, end);
6453}
6454
6455/// Ditto
6456// Specialization for floating-point types
6457auto iota(B, E, S)(B begin, E end, S step)
6458if (isFloatingPoint!(CommonType!(B, E, S)))
6459in
6460{
6461    assert(step != 0, "iota: step must not be 0");
6462    assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
6463}
6464do
6465{
6466    alias Value = Unqual!(CommonType!(B, E, S));
6467    static struct Result
6468    {
6469        private Value start, step;
6470        private size_t index, count;
6471
6472        this(Value start, Value end, Value step)
6473        {
6474            import std.conv : to;
6475
6476            this.start = start;
6477            this.step = step;
6478            immutable fcount = (end - start) / step;
6479            count = to!size_t(fcount);
6480            auto pastEnd = start + count * step;
6481            if (step > 0)
6482            {
6483                if (pastEnd < end) ++count;
6484                assert(start + count * step >= end);
6485            }
6486            else
6487            {
6488                if (pastEnd > end) ++count;
6489                assert(start + count * step <= end);
6490            }
6491        }
6492
6493        @property bool empty() const { return index == count; }
6494        @property Value front() const { assert(!empty); return start + step * index; }
6495        void popFront()
6496        {
6497            assert(!empty);
6498            ++index;
6499        }
6500        @property Value back() const
6501        {
6502            assert(!empty);
6503            return start + step * (count - 1);
6504        }
6505        void popBack()
6506        {
6507            assert(!empty);
6508            --count;
6509        }
6510
6511        @property auto save() { return this; }
6512
6513        Value opIndex(size_t n) const
6514        {
6515            assert(n < count);
6516            return start + step * (n + index);
6517        }
6518        inout(Result) opSlice() inout
6519        {
6520            return this;
6521        }
6522        inout(Result) opSlice(size_t lower, size_t upper) inout
6523        {
6524            assert(upper >= lower && upper <= count);
6525
6526            Result ret = this;
6527            ret.index += lower;
6528            ret.count = upper - lower + ret.index;
6529            return cast(inout Result) ret;
6530        }
6531        @property size_t length() const
6532        {
6533            return count - index;
6534        }
6535
6536        alias opDollar = length;
6537    }
6538
6539    return Result(begin, end, step);
6540}
6541
6542///
6543pure @safe unittest
6544{
6545    import std.algorithm.comparison : equal;
6546    import std.math.operations : isClose;
6547
6548    auto r = iota(0, 10, 1);
6549    assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6550    assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6551    assert(3 in r);
6552    assert(r.contains(3)); //Same as above
6553    assert(!(10 in r));
6554    assert(!(-8 in r));
6555    r = iota(0, 11, 3);
6556    assert(equal(r, [0, 3, 6, 9]));
6557    assert(r[2] == 6);
6558    assert(!(2 in r));
6559    auto rf = iota(0.0, 0.5, 0.1);
6560    assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
6561}
6562
6563pure nothrow @nogc @safe unittest
6564{
6565    import std.traits : Signed;
6566   //float overloads use std.conv.to so can't be @nogc or nothrow
6567    alias ssize_t = Signed!size_t;
6568    assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
6569    assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
6570    assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
6571    assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
6572    assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
6573}
6574
6575debug @system unittest
6576{//check the contracts
6577    import core.exception : AssertError;
6578    import std.exception : assertThrown;
6579    assertThrown!AssertError(iota(1,2,0));
6580    assertThrown!AssertError(iota(0f,1f,0f));
6581    assertThrown!AssertError(iota(1f,0f,0.1f));
6582    assertThrown!AssertError(iota(0f,1f,-0.1f));
6583}
6584
6585pure @system nothrow unittest
6586{
6587    int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6588    auto r1 = iota(a.ptr, a.ptr + a.length, 1);
6589    assert(r1.front == a.ptr);
6590    assert(r1.back == a.ptr + a.length - 1);
6591    assert(&a[4] in r1);
6592}
6593
6594pure @safe nothrow @nogc unittest
6595{
6596    assert(iota(1UL, 0UL).length == 0);
6597    assert(iota(1UL, 0UL, 1).length == 0);
6598    assert(iota(0, 1, 1).length == 1);
6599    assert(iota(1, 0, -1).length == 1);
6600    assert(iota(0, 1, -1).length == 0);
6601    assert(iota(ulong.max, 0).length == 0);
6602}
6603
6604pure @safe unittest
6605{
6606    import std.algorithm.comparison : equal;
6607    import std.algorithm.searching : count;
6608    import std.math.operations : isClose, nextUp, nextDown;
6609    import std.meta : AliasSeq;
6610
6611    static assert(is(ElementType!(typeof(iota(0f))) == float));
6612
6613    static assert(hasLength!(typeof(iota(0, 2))));
6614    auto r = iota(0, 10, 1);
6615    assert(r[$ - 1] == 9);
6616    assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
6617
6618    auto rSlice = r[2 .. 8];
6619    assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
6620
6621    rSlice.popFront();
6622    assert(rSlice[0] == rSlice.front);
6623    assert(rSlice.front == 3);
6624
6625    rSlice.popBack();
6626    assert(rSlice[rSlice.length - 1] == rSlice.back);
6627    assert(rSlice.back == 6);
6628
6629    rSlice = r[0 .. 4];
6630    assert(equal(rSlice, [0, 1, 2, 3]));
6631    assert(3 in rSlice);
6632    assert(!(4 in rSlice));
6633
6634    auto rr = iota(10);
6635    assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
6636
6637    r = iota(0, -10, -1);
6638    assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
6639    rSlice = r[3 .. 9];
6640    assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
6641
6642    r = iota(0, -6, -3);
6643    assert(equal(r, [0, -3][]));
6644    rSlice = r[1 .. 2];
6645    assert(equal(rSlice, [-3]));
6646
6647    r = iota(0, -7, -3);
6648    assert(equal(r, [0, -3, -6][]));
6649    assert(0 in r);
6650    assert(-6 in r);
6651    rSlice = r[1 .. 3];
6652    assert(equal(rSlice, [-3, -6]));
6653    assert(!(0 in rSlice));
6654    assert(!(-2 in rSlice));
6655    assert(!(-5 in rSlice));
6656    assert(!(3 in rSlice));
6657    assert(!(-9 in rSlice));
6658
6659    r = iota(0, 11, 3);
6660    assert(equal(r, [0, 3, 6, 9][]));
6661    assert(r[2] == 6);
6662    rSlice = r[1 .. 3];
6663    assert(equal(rSlice, [3, 6]));
6664
6665    auto rf = iota(0.0, 0.5, 0.1);
6666    assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
6667    assert(rf.length == 5);
6668
6669    rf.popFront();
6670    assert(rf.length == 4);
6671
6672    auto rfSlice = rf[1 .. 4];
6673    assert(rfSlice.length == 3);
6674    assert(isClose(rfSlice, [0.2, 0.3, 0.4]));
6675
6676    rfSlice.popFront();
6677    assert(isClose(rfSlice[0], 0.3));
6678
6679    rf.popFront();
6680    assert(rf.length == 3);
6681
6682    rfSlice = rf[1 .. 3];
6683    assert(rfSlice.length == 2);
6684    assert(isClose(rfSlice, [0.3, 0.4]));
6685    assert(isClose(rfSlice[0], 0.3));
6686
6687    // With something just above 0.5
6688    rf = iota(0.0, nextUp(0.5), 0.1);
6689    assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
6690    rf.popBack();
6691    assert(rf[rf.length - 1] == rf.back);
6692    assert(isClose(rf.back, 0.4));
6693    assert(rf.length == 5);
6694
6695    // going down
6696    rf = iota(0.0, -0.5, -0.1);
6697    assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
6698    rfSlice = rf[2 .. 5];
6699    assert(isClose(rfSlice, [-0.2, -0.3, -0.4]));
6700
6701    rf = iota(0.0, nextDown(-0.5), -0.1);
6702    assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
6703
6704    // iota of longs
6705    auto rl = iota(5_000_000L);
6706    assert(rl.length == 5_000_000L);
6707    assert(0 in rl);
6708    assert(4_000_000L in rl);
6709    assert(!(-4_000_000L in rl));
6710    assert(!(5_000_000L in rl));
6711
6712    // iota of longs with steps
6713    auto iota_of_longs_with_steps = iota(50L, 101L, 10);
6714    assert(iota_of_longs_with_steps.length == 6);
6715    assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
6716
6717    // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
6718    // Actually trying to consume it is the only way to find something is wrong
6719    // because the public properties are all correct.
6720    auto iota_zero_unsigned = iota(0, 0u, 3);
6721    assert(count(iota_zero_unsigned) == 0);
6722
6723    // https://issues.dlang.org/show_bug.cgi?id=7982
6724    // unsigned reverse iota can be buggy if `.length` doesn't
6725    // take them into account
6726    assert(iota(10u, 0u, -1).length == 10);
6727    assert(iota(10u, 0u, -2).length == 5);
6728    assert(iota(uint.max, uint.max-10, -1).length == 10);
6729    assert(iota(uint.max, uint.max-10, -2).length == 5);
6730    assert(iota(uint.max, 0u, -1).length == uint.max);
6731
6732    assert(20 in iota(20u, 10u, -2));
6733    assert(16 in iota(20u, 10u, -2));
6734    assert(!(15 in iota(20u, 10u, -2)));
6735    assert(!(10 in iota(20u, 10u, -2)));
6736    assert(!(uint.max in iota(20u, 10u, -1)));
6737    assert(!(int.min in iota(20u, 10u, -1)));
6738    assert(!(int.max in iota(20u, 10u, -1)));
6739
6740
6741    // https://issues.dlang.org/show_bug.cgi?id=8920
6742    static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
6743        int, uint, long, ulong))
6744    {{
6745        Type val;
6746        foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
6747        assert(val == 10);
6748    }}
6749}
6750
6751pure @safe nothrow unittest
6752{
6753    import std.algorithm.mutation : copy;
6754    auto idx = new size_t[100];
6755    copy(iota(0, idx.length), idx);
6756}
6757
6758@safe unittest
6759{
6760    import std.meta : AliasSeq;
6761    static foreach (range; AliasSeq!(iota(2, 27, 4),
6762                             iota(3, 9),
6763                             iota(2.7, 12.3, .1),
6764                             iota(3.2, 9.7)))
6765    {{
6766        const cRange = range;
6767        const e = cRange.empty;
6768        const f = cRange.front;
6769        const b = cRange.back;
6770        const i = cRange[2];
6771        const s1 = cRange[];
6772        const s2 = cRange[0 .. 3];
6773        const l = cRange.length;
6774    }}
6775}
6776
6777@system unittest
6778{
6779    //The ptr stuff can't be done at compile time, so we unfortunately end
6780    //up with some code duplication here.
6781    auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
6782
6783    {
6784        const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
6785        const e = cRange.empty;
6786        const f = cRange.front;
6787        const b = cRange.back;
6788        const i = cRange[2];
6789        const s1 = cRange[];
6790        const s2 = cRange[0 .. 3];
6791        const l = cRange.length;
6792    }
6793
6794    {
6795        const cRange = iota(arr.ptr, arr.ptr + arr.length);
6796        const e = cRange.empty;
6797        const f = cRange.front;
6798        const b = cRange.back;
6799        const i = cRange[2];
6800        const s1 = cRange[];
6801        const s2 = cRange[0 .. 3];
6802        const l = cRange.length;
6803    }
6804}
6805
6806@nogc nothrow pure @safe unittest
6807{
6808    {
6809        ushort start = 0, end = 10, step = 2;
6810        foreach (i; iota(start, end, step))
6811            static assert(is(typeof(i) == ushort));
6812    }
6813    {
6814        ubyte start = 0, end = 255, step = 128;
6815        uint x;
6816        foreach (i; iota(start, end, step))
6817        {
6818            static assert(is(typeof(i) == ubyte));
6819            ++x;
6820        }
6821        assert(x == 2);
6822    }
6823}
6824
6825/* Generic overload that handles arbitrary types that support arithmetic
6826 * operations.
6827 *
6828 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
6829 * as they can be incremented with `++` and compared with `<` or `==`.
6830 */
6831/// ditto
6832auto iota(B, E)(B begin, E end)
6833if (!isIntegral!(CommonType!(B, E)) &&
6834    !isFloatingPoint!(CommonType!(B, E)) &&
6835    !isPointer!(CommonType!(B, E)) &&
6836    is(typeof((ref B b) { ++b; })) &&
6837    (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
6838{
6839    static struct Result
6840    {
6841        B current;
6842        E end;
6843
6844        @property bool empty()
6845        {
6846            static if (is(typeof(B.init < E.init)))
6847                return !(current < end);
6848            else static if (is(typeof(B.init != E.init)))
6849                return current == end;
6850            else
6851                static assert(0);
6852        }
6853        @property auto front() { return current; }
6854        void popFront()
6855        {
6856            assert(!empty);
6857            ++current;
6858        }
6859    }
6860    return Result(begin, end);
6861}
6862
6863@safe unittest
6864{
6865    import std.algorithm.comparison : equal;
6866
6867    // Test iota() for a type that only supports ++ and != but does not have
6868    // '<'-ordering.
6869    struct Cyclic(int wrapAround)
6870    {
6871        int current;
6872
6873        this(int start) { current = start % wrapAround; }
6874
6875        bool opEquals(Cyclic c) const { return current == c.current; }
6876        bool opEquals(int i) const { return current == i; }
6877        void opUnary(string op)() if (op == "++")
6878        {
6879            current = (current + 1) % wrapAround;
6880        }
6881    }
6882    alias Cycle5 = Cyclic!5;
6883
6884    // Easy case
6885    auto i1 = iota(Cycle5(1), Cycle5(4));
6886    assert(i1.equal([1, 2, 3]));
6887
6888    // Wraparound case
6889    auto i2 = iota(Cycle5(3), Cycle5(2));
6890    assert(i2.equal([3, 4, 0, 1 ]));
6891}
6892
6893/**
6894   Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
6895   (below).
6896*/
6897enum TransverseOptions
6898{
6899/**
6900   When transversed, the elements of a range of ranges are assumed to
6901   have different lengths (e.g. a jagged array).
6902*/
6903    assumeJagged,                      //default
6904    /**
6905       The transversal enforces that the elements of a range of ranges have
6906       all the same length (e.g. an array of arrays, all having the same
6907       length). Checking is done once upon construction of the transversal
6908       range.
6909    */
6910        enforceNotJagged,
6911    /**
6912       The transversal assumes, without verifying, that the elements of a
6913       range of ranges have all the same length. This option is useful if
6914       checking was already done from the outside of the range.
6915    */
6916        assumeNotJagged,
6917}
6918
6919///
6920@safe pure unittest
6921{
6922    import std.algorithm.comparison : equal;
6923    import std.exception : assertThrown;
6924
6925    auto arr = [[1, 2], [3, 4, 5]];
6926
6927    auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
6928    assert(r1.equal([1, 3]));
6929
6930    // throws on construction
6931    assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
6932
6933    auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
6934    assert(r2.equal([1, 3]));
6935
6936    // either assuming or checking for equal lengths makes
6937    // the result a random access range
6938    assert(r2[0] == 1);
6939    static assert(!__traits(compiles, r1[0]));
6940}
6941
6942/**
6943   Given a range of ranges, iterate transversally through the first
6944   elements of each of the enclosed ranges.
6945*/
6946struct FrontTransversal(Ror,
6947        TransverseOptions opt = TransverseOptions.assumeJagged)
6948{
6949    alias RangeOfRanges = Unqual!(Ror);
6950    alias RangeType     = .ElementType!RangeOfRanges;
6951    alias ElementType   = .ElementType!RangeType;
6952
6953    private void prime()
6954    {
6955        static if (opt == TransverseOptions.assumeJagged)
6956        {
6957            while (!_input.empty && _input.front.empty)
6958            {
6959                _input.popFront();
6960            }
6961            static if (isBidirectionalRange!RangeOfRanges)
6962            {
6963                while (!_input.empty && _input.back.empty)
6964                {
6965                    _input.popBack();
6966                }
6967            }
6968        }
6969    }
6970
6971/**
6972   Construction from an input.
6973*/
6974    this(RangeOfRanges input)
6975    {
6976        _input = input;
6977        prime();
6978        static if (opt == TransverseOptions.enforceNotJagged)
6979            // (isRandomAccessRange!RangeOfRanges
6980            //     && hasLength!RangeType)
6981        {
6982            import std.exception : enforce;
6983
6984            if (empty) return;
6985            immutable commonLength = _input.front.length;
6986            foreach (e; _input)
6987            {
6988                enforce(e.length == commonLength);
6989            }
6990        }
6991    }
6992
6993/**
6994   Forward range primitives.
6995*/
6996    static if (isInfinite!RangeOfRanges)
6997    {
6998        enum bool empty = false;
6999    }
7000    else
7001    {
7002        @property bool empty()
7003        {
7004            static if (opt != TransverseOptions.assumeJagged)
7005            {
7006                if (!_input.empty)
7007                    return _input.front.empty;
7008            }
7009
7010            return _input.empty;
7011        }
7012    }
7013
7014    /// Ditto
7015    @property auto ref front()
7016    {
7017        assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
7018        return _input.front.front;
7019    }
7020
7021    /// Ditto
7022    static if (hasMobileElements!RangeType)
7023    {
7024        ElementType moveFront()
7025        {
7026            return _input.front.moveFront();
7027        }
7028    }
7029
7030    static if (hasAssignableElements!RangeType)
7031    {
7032        @property void front(ElementType val)
7033        {
7034            _input.front.front = val;
7035        }
7036    }
7037
7038    /// Ditto
7039    void popFront()
7040    {
7041        assert(!empty, "Attempting to popFront an empty FrontTransversal");
7042        _input.popFront();
7043        prime();
7044    }
7045
7046/**
7047   Duplicates this `frontTransversal`. Note that only the encapsulating
7048   range of range will be duplicated. Underlying ranges will not be
7049   duplicated.
7050*/
7051    static if (isForwardRange!RangeOfRanges)
7052    {
7053        @property FrontTransversal save()
7054        {
7055            return FrontTransversal(_input.save);
7056        }
7057    }
7058
7059    static if (isBidirectionalRange!RangeOfRanges)
7060    {
7061/**
7062   Bidirectional primitives. They are offered if $(D
7063   isBidirectionalRange!RangeOfRanges).
7064*/
7065        @property auto ref back()
7066        {
7067            assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7068            return _input.back.front;
7069        }
7070        /// Ditto
7071        void popBack()
7072        {
7073            assert(!empty, "Attempting to popBack an empty FrontTransversal");
7074            _input.popBack();
7075            prime();
7076        }
7077
7078        /// Ditto
7079        static if (hasMobileElements!RangeType)
7080        {
7081            ElementType moveBack()
7082            {
7083                return _input.back.moveFront();
7084            }
7085        }
7086
7087        static if (hasAssignableElements!RangeType)
7088        {
7089            @property void back(ElementType val)
7090            {
7091                _input.back.front = val;
7092            }
7093        }
7094    }
7095
7096    static if (isRandomAccessRange!RangeOfRanges &&
7097            (opt == TransverseOptions.assumeNotJagged ||
7098                    opt == TransverseOptions.enforceNotJagged))
7099    {
7100/**
7101   Random-access primitive. It is offered if $(D
7102   isRandomAccessRange!RangeOfRanges && (opt ==
7103   TransverseOptions.assumeNotJagged || opt ==
7104   TransverseOptions.enforceNotJagged)).
7105*/
7106        auto ref opIndex(size_t n)
7107        {
7108            return _input[n].front;
7109        }
7110
7111        /// Ditto
7112        static if (hasMobileElements!RangeType)
7113        {
7114            ElementType moveAt(size_t n)
7115            {
7116                return _input[n].moveFront();
7117            }
7118        }
7119        /// Ditto
7120        static if (hasAssignableElements!RangeType)
7121        {
7122            void opIndexAssign(ElementType val, size_t n)
7123            {
7124                _input[n].front = val;
7125            }
7126        }
7127        mixin ImplementLength!_input;
7128
7129/**
7130   Slicing if offered if `RangeOfRanges` supports slicing and all the
7131   conditions for supporting indexing are met.
7132*/
7133        static if (hasSlicing!RangeOfRanges)
7134        {
7135            typeof(this) opSlice(size_t lower, size_t upper)
7136            {
7137                return typeof(this)(_input[lower .. upper]);
7138            }
7139        }
7140    }
7141
7142    auto opSlice() { return this; }
7143
7144private:
7145    RangeOfRanges _input;
7146}
7147
7148/// Ditto
7149FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7150    TransverseOptions opt = TransverseOptions.assumeJagged,
7151    RangeOfRanges)
7152(RangeOfRanges rr)
7153{
7154    return typeof(return)(rr);
7155}
7156
7157///
7158pure @safe nothrow unittest
7159{
7160    import std.algorithm.comparison : equal;
7161    int[][] x = new int[][2];
7162    x[0] = [1, 2];
7163    x[1] = [3, 4];
7164    auto ror = frontTransversal(x);
7165    assert(equal(ror, [ 1, 3 ][]));
7166}
7167
7168@safe unittest
7169{
7170    import std.algorithm.comparison : equal;
7171    import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7172
7173    static assert(is(FrontTransversal!(immutable int[][])));
7174
7175    foreach (DummyType; AllDummyRanges)
7176    {
7177        auto dummies =
7178            [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7179
7180        foreach (i, ref elem; dummies)
7181        {
7182            // Just violate the DummyRange abstraction to get what I want.
7183            elem.arr = elem.arr[i..$ - (3 - i)];
7184        }
7185
7186        auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7187        static if (isForwardRange!DummyType)
7188        {
7189            static assert(isForwardRange!(typeof(ft)));
7190        }
7191
7192        assert(equal(ft, [1, 2, 3, 4]));
7193
7194        // Test slicing.
7195        assert(equal(ft[0 .. 2], [1, 2]));
7196        assert(equal(ft[1 .. 3], [2, 3]));
7197
7198        assert(ft.front == ft.moveFront());
7199        assert(ft.back == ft.moveBack());
7200        assert(ft.moveAt(1) == ft[1]);
7201
7202
7203        // Test infiniteness propagation.
7204        static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7205
7206        static if (DummyType.r == ReturnBy.Reference)
7207        {
7208            {
7209                ft.front++;
7210                scope(exit) ft.front--;
7211                assert(dummies.front.front == 2);
7212            }
7213
7214            {
7215                ft.front = 5;
7216                scope(exit) ft.front = 1;
7217                assert(dummies[0].front == 5);
7218            }
7219
7220            {
7221                ft.back = 88;
7222                scope(exit) ft.back = 4;
7223                assert(dummies.back.front == 88);
7224            }
7225
7226            {
7227                ft[1] = 99;
7228                scope(exit) ft[1] = 2;
7229                assert(dummies[1].front == 99);
7230            }
7231        }
7232    }
7233}
7234
7235// https://issues.dlang.org/show_bug.cgi?id=16363
7236pure @safe nothrow unittest
7237{
7238    import std.algorithm.comparison : equal;
7239
7240    int[][] darr = [[0, 1], [4, 5]];
7241    auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7242
7243    assert(equal(ft, [0, 4]));
7244    static assert(isRandomAccessRange!(typeof(ft)));
7245}
7246
7247// https://issues.dlang.org/show_bug.cgi?id=16442
7248pure @safe nothrow unittest
7249{
7250    int[][] arr = [[], []];
7251
7252    auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7253    assert(ft.empty);
7254}
7255
7256// ditto
7257pure @safe unittest
7258{
7259    int[][] arr = [[], []];
7260
7261    auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7262    assert(ft.empty);
7263}
7264
7265/**
7266    Given a range of ranges, iterate transversally through the
7267    `n`th element of each of the enclosed ranges. This function
7268    is similar to `unzip` in other languages.
7269
7270    Params:
7271        opt = Controls the assumptions the function makes about the lengths
7272        of the ranges
7273        rr = An input range of random access ranges
7274    Returns:
7275        At minimum, an input range. Range primitives such as bidirectionality
7276        and random access are given if the element type of `rr` provides them.
7277*/
7278struct Transversal(Ror,
7279        TransverseOptions opt = TransverseOptions.assumeJagged)
7280{
7281    private alias RangeOfRanges = Unqual!Ror;
7282    private alias InnerRange = ElementType!RangeOfRanges;
7283    private alias E = ElementType!InnerRange;
7284
7285    private void prime()
7286    {
7287        static if (opt == TransverseOptions.assumeJagged)
7288        {
7289            while (!_input.empty && _input.front.length <= _n)
7290            {
7291                _input.popFront();
7292            }
7293            static if (isBidirectionalRange!RangeOfRanges)
7294            {
7295                while (!_input.empty && _input.back.length <= _n)
7296                {
7297                    _input.popBack();
7298                }
7299            }
7300        }
7301    }
7302
7303/**
7304   Construction from an input and an index.
7305*/
7306    this(RangeOfRanges input, size_t n)
7307    {
7308        _input = input;
7309        _n = n;
7310        prime();
7311        static if (opt == TransverseOptions.enforceNotJagged)
7312        {
7313            import std.exception : enforce;
7314
7315            if (empty) return;
7316            immutable commonLength = _input.front.length;
7317            foreach (e; _input)
7318            {
7319                enforce(e.length == commonLength);
7320            }
7321        }
7322    }
7323
7324/**
7325   Forward range primitives.
7326*/
7327    static if (isInfinite!(RangeOfRanges))
7328    {
7329        enum bool empty = false;
7330    }
7331    else
7332    {
7333        @property bool empty()
7334        {
7335            return _input.empty;
7336        }
7337    }
7338
7339    /// Ditto
7340    @property auto ref front()
7341    {
7342        assert(!empty, "Attempting to fetch the front of an empty Transversal");
7343        return _input.front[_n];
7344    }
7345
7346    /// Ditto
7347    static if (hasMobileElements!InnerRange)
7348    {
7349        E moveFront()
7350        {
7351            return _input.front.moveAt(_n);
7352        }
7353    }
7354
7355    /// Ditto
7356    static if (hasAssignableElements!InnerRange)
7357    {
7358        @property void front(E val)
7359        {
7360            _input.front[_n] = val;
7361        }
7362    }
7363
7364
7365    /// Ditto
7366    void popFront()
7367    {
7368        assert(!empty, "Attempting to popFront an empty Transversal");
7369        _input.popFront();
7370        prime();
7371    }
7372
7373    /// Ditto
7374    static if (isForwardRange!RangeOfRanges)
7375    {
7376        @property typeof(this) save()
7377        {
7378            auto ret = this;
7379            ret._input = _input.save;
7380            return ret;
7381        }
7382    }
7383
7384    static if (isBidirectionalRange!RangeOfRanges)
7385    {
7386/**
7387   Bidirectional primitives. They are offered if $(D
7388   isBidirectionalRange!RangeOfRanges).
7389*/
7390        @property auto ref back()
7391        {
7392            assert(!empty, "Attempting to fetch the back of an empty Transversal");
7393            return _input.back[_n];
7394        }
7395
7396        /// Ditto
7397        void popBack()
7398        {
7399            assert(!empty, "Attempting to popBack an empty Transversal");
7400            _input.popBack();
7401            prime();
7402        }
7403
7404        /// Ditto
7405        static if (hasMobileElements!InnerRange)
7406        {
7407            E moveBack()
7408            {
7409                return _input.back.moveAt(_n);
7410            }
7411        }
7412
7413        /// Ditto
7414        static if (hasAssignableElements!InnerRange)
7415        {
7416            @property void back(E val)
7417            {
7418                _input.back[_n] = val;
7419            }
7420        }
7421
7422    }
7423
7424    static if (isRandomAccessRange!RangeOfRanges &&
7425            (opt == TransverseOptions.assumeNotJagged ||
7426                    opt == TransverseOptions.enforceNotJagged))
7427    {
7428/**
7429   Random-access primitive. It is offered if $(D
7430   isRandomAccessRange!RangeOfRanges && (opt ==
7431   TransverseOptions.assumeNotJagged || opt ==
7432   TransverseOptions.enforceNotJagged)).
7433*/
7434        auto ref opIndex(size_t n)
7435        {
7436            return _input[n][_n];
7437        }
7438
7439        /// Ditto
7440        static if (hasMobileElements!InnerRange)
7441        {
7442            E moveAt(size_t n)
7443            {
7444                return _input[n].moveAt(_n);
7445            }
7446        }
7447
7448        /// Ditto
7449        static if (hasAssignableElements!InnerRange)
7450        {
7451            void opIndexAssign(E val, size_t n)
7452            {
7453                _input[n][_n] = val;
7454            }
7455        }
7456
7457        mixin ImplementLength!_input;
7458
7459/**
7460   Slicing if offered if `RangeOfRanges` supports slicing and all the
7461   conditions for supporting indexing are met.
7462*/
7463        static if (hasSlicing!RangeOfRanges)
7464        {
7465            typeof(this) opSlice(size_t lower, size_t upper)
7466            {
7467                return typeof(this)(_input[lower .. upper], _n);
7468            }
7469        }
7470    }
7471
7472    auto opSlice() { return this; }
7473
7474private:
7475    RangeOfRanges _input;
7476    size_t _n;
7477}
7478
7479/// Ditto
7480Transversal!(RangeOfRanges, opt) transversal
7481(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
7482(RangeOfRanges rr, size_t n)
7483{
7484    return typeof(return)(rr, n);
7485}
7486
7487///
7488@safe unittest
7489{
7490    import std.algorithm.comparison : equal;
7491    int[][] x = new int[][2];
7492    x[0] = [1, 2];
7493    x[1] = [3, 4];
7494    auto ror = transversal(x, 1);
7495    assert(equal(ror, [ 2, 4 ]));
7496}
7497
7498/// The following code does a full unzip
7499@safe unittest
7500{
7501    import std.algorithm.comparison : equal;
7502    import std.algorithm.iteration : map;
7503    int[][] y = [[1, 2, 3], [4, 5, 6]];
7504    auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
7505    assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
7506}
7507
7508@safe unittest
7509{
7510    import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
7511
7512    int[][] x = new int[][2];
7513    x[0] = [ 1, 2 ];
7514    x[1] = [3, 4];
7515    auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
7516    auto witness = [ 2, 4 ];
7517    uint i;
7518    foreach (e; ror) assert(e == witness[i++]);
7519    assert(i == 2);
7520    assert(ror.length == 2);
7521
7522    static assert(is(Transversal!(immutable int[][])));
7523
7524    // Make sure ref, assign is being propagated.
7525    {
7526        ror.front++;
7527        scope(exit) ror.front--;
7528        assert(x[0][1] == 3);
7529    }
7530    {
7531        ror.front = 5;
7532        scope(exit) ror.front = 2;
7533        assert(x[0][1] == 5);
7534        assert(ror.moveFront() == 5);
7535    }
7536    {
7537        ror.back = 999;
7538        scope(exit) ror.back = 4;
7539        assert(x[1][1] == 999);
7540        assert(ror.moveBack() == 999);
7541    }
7542    {
7543        ror[0] = 999;
7544        scope(exit) ror[0] = 2;
7545        assert(x[0][1] == 999);
7546        assert(ror.moveAt(0) == 999);
7547    }
7548
7549    // Test w/o ref return.
7550    alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
7551    auto drs = [D.init, D.init];
7552    foreach (num; 0 .. 10)
7553    {
7554        auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
7555        assert(t[0] == t[1]);
7556        assert(t[1] == num + 1);
7557    }
7558
7559    static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
7560
7561    // Test slicing.
7562    auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
7563    auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
7564    assert(mat1[0] == 6);
7565    assert(mat1[1] == 10);
7566}
7567
7568struct Transposed(RangeOfRanges,
7569    TransverseOptions opt = TransverseOptions.assumeJagged)
7570if (isForwardRange!RangeOfRanges &&
7571    isInputRange!(ElementType!RangeOfRanges) &&
7572    hasAssignableElements!RangeOfRanges)
7573{
7574    this(RangeOfRanges input)
7575    {
7576        this._input = input;
7577        static if (opt == TransverseOptions.enforceNotJagged)
7578        {
7579            import std.exception : enforce;
7580
7581            if (empty) return;
7582            immutable commonLength = _input.front.length;
7583            foreach (e; _input)
7584            {
7585                enforce(e.length == commonLength);
7586            }
7587        }
7588    }
7589
7590    @property auto front()
7591    {
7592        import std.algorithm.iteration : filter, map;
7593        return _input.save
7594                     .filter!(a => !a.empty)
7595                     .map!(a => a.front);
7596    }
7597
7598    void popFront()
7599    {
7600        // Advance the position of each subrange.
7601        auto r = _input.save;
7602        while (!r.empty)
7603        {
7604            auto e = r.front;
7605            if (!e.empty)
7606            {
7607                e.popFront();
7608                r.front = e;
7609            }
7610
7611            r.popFront();
7612        }
7613    }
7614
7615    static if (isRandomAccessRange!(ElementType!RangeOfRanges))
7616    {
7617        auto ref opIndex(size_t n)
7618        {
7619            return transversal!opt(_input, n);
7620        }
7621    }
7622
7623    @property bool empty()
7624    {
7625        if (_input.empty) return true;
7626        foreach (e; _input.save)
7627        {
7628            if (!e.empty) return false;
7629        }
7630        return true;
7631    }
7632
7633    auto opSlice() { return this; }
7634
7635private:
7636    RangeOfRanges _input;
7637}
7638
7639@safe unittest
7640{
7641    // Boundary case: transpose of empty range should be empty
7642    int[][] ror = [];
7643    assert(transposed(ror).empty);
7644}
7645
7646// https://issues.dlang.org/show_bug.cgi?id=9507
7647@safe unittest
7648{
7649    import std.algorithm.comparison : equal;
7650
7651    auto r = [[1,2], [3], [4,5], [], [6]];
7652    assert(r.transposed.equal!equal([
7653        [1, 3, 4, 6],
7654        [2, 5]
7655    ]));
7656}
7657
7658// https://issues.dlang.org/show_bug.cgi?id=17742
7659@safe unittest
7660{
7661    import std.algorithm.iteration : map;
7662    import std.algorithm.comparison : equal;
7663    auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
7664    assert(ror[3][2] == 6);
7665    auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
7666    assert(result[2][3] == 6);
7667
7668    auto x = [[1,2,3],[4,5,6]];
7669    auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
7670    assert(y.front.equal([1,4]));
7671    assert(y[0].equal([1,4]));
7672    assert(y[0][0] == 1);
7673    assert(y[1].equal([2,5]));
7674    assert(y[1][1] == 5);
7675
7676    auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
7677    assert(yy.front.equal([1,4]));
7678    assert(yy[0].equal([1,4]));
7679    assert(yy[0][0] == 1);
7680    assert(yy[1].equal([2,5]));
7681    assert(yy[1][1] == 5);
7682
7683    auto z = x.transposed; // assumeJagged
7684    assert(z.front.equal([1,4]));
7685    assert(z[0].equal([1,4]));
7686    assert(!is(typeof(z[0][0])));
7687}
7688
7689@safe unittest
7690{
7691    import std.exception : assertThrown;
7692
7693    auto r = [[1,2], [3], [4,5], [], [6]];
7694    assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
7695}
7696
7697/**
7698Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
7699contains the $(I i)'th elements of the original subranges.
7700
7701Params:
7702    opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
7703    rr = Range of ranges
7704 */
7705Transposed!(RangeOfRanges, opt) transposed
7706(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
7707(RangeOfRanges rr)
7708if (isForwardRange!RangeOfRanges &&
7709    isInputRange!(ElementType!RangeOfRanges) &&
7710    hasAssignableElements!RangeOfRanges)
7711{
7712    return Transposed!(RangeOfRanges, opt)(rr);
7713}
7714
7715///
7716@safe unittest
7717{
7718    import std.algorithm.comparison : equal;
7719    int[][] ror = [
7720        [1, 2, 3],
7721        [4, 5, 6]
7722    ];
7723    auto xp = transposed(ror);
7724    assert(equal!"a.equal(b)"(xp, [
7725        [1, 4],
7726        [2, 5],
7727        [3, 6]
7728    ]));
7729}
7730
7731///
7732@safe unittest
7733{
7734    int[][] x = new int[][2];
7735    x[0] = [1, 2];
7736    x[1] = [3, 4];
7737    auto tr = transposed(x);
7738    int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
7739    uint i;
7740
7741    foreach (e; tr)
7742    {
7743        assert(array(e) == witness[i++]);
7744    }
7745}
7746
7747// https://issues.dlang.org/show_bug.cgi?id=8764
7748@safe unittest
7749{
7750    import std.algorithm.comparison : equal;
7751    ulong[] t0 = [ 123 ];
7752
7753    assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
7754    assert(!is(typeof(transposed(t0[].chunks(1)))));
7755    assert(is(typeof(transposed(t0[].chunks(1).array()))));
7756
7757    auto t1 = transposed(t0[].chunks(1).array());
7758    assert(equal!"a.equal(b)"(t1, [[123]]));
7759}
7760
7761/**
7762This struct takes two ranges, `source` and `indices`, and creates a view
7763of `source` as if its elements were reordered according to `indices`.
7764`indices` may include only a subset of the elements of `source` and
7765may also repeat elements.
7766
7767`Source` must be a random access range.  The returned range will be
7768bidirectional or random-access if `Indices` is bidirectional or
7769random-access, respectively.
7770*/
7771struct Indexed(Source, Indices)
7772if (isRandomAccessRange!Source && isInputRange!Indices &&
7773    is(typeof(Source.init[ElementType!(Indices).init])))
7774{
7775    this(Source source, Indices indices)
7776    {
7777        this._source = source;
7778        this._indices = indices;
7779    }
7780
7781    /// Range primitives
7782    @property auto ref front()
7783    {
7784        assert(!empty, "Attempting to fetch the front of an empty Indexed");
7785        return _source[_indices.front];
7786    }
7787
7788    /// Ditto
7789    void popFront()
7790    {
7791        assert(!empty, "Attempting to popFront an empty Indexed");
7792        _indices.popFront();
7793    }
7794
7795    static if (isInfinite!Indices)
7796    {
7797        enum bool empty = false;
7798    }
7799    else
7800    {
7801        /// Ditto
7802        @property bool empty()
7803        {
7804            return _indices.empty;
7805        }
7806    }
7807
7808    static if (isForwardRange!Indices)
7809    {
7810        /// Ditto
7811        @property typeof(this) save()
7812        {
7813            // Don't need to save _source because it's never consumed.
7814            return typeof(this)(_source, _indices.save);
7815        }
7816    }
7817
7818    /// Ditto
7819    static if (hasAssignableElements!Source)
7820    {
7821        @property auto ref front(ElementType!Source newVal)
7822        {
7823            assert(!empty);
7824            return _source[_indices.front] = newVal;
7825        }
7826    }
7827
7828
7829    static if (hasMobileElements!Source)
7830    {
7831        /// Ditto
7832        auto moveFront()
7833        {
7834            assert(!empty);
7835            return _source.moveAt(_indices.front);
7836        }
7837    }
7838
7839    static if (isBidirectionalRange!Indices)
7840    {
7841        /// Ditto
7842        @property auto ref back()
7843        {
7844            assert(!empty, "Attempting to fetch the back of an empty Indexed");
7845            return _source[_indices.back];
7846        }
7847
7848        /// Ditto
7849        void popBack()
7850        {
7851           assert(!empty, "Attempting to popBack an empty Indexed");
7852           _indices.popBack();
7853        }
7854
7855        /// Ditto
7856        static if (hasAssignableElements!Source)
7857        {
7858            @property auto ref back(ElementType!Source newVal)
7859            {
7860                assert(!empty);
7861                return _source[_indices.back] = newVal;
7862            }
7863        }
7864
7865
7866        static if (hasMobileElements!Source)
7867        {
7868            /// Ditto
7869            auto moveBack()
7870            {
7871                assert(!empty);
7872                return _source.moveAt(_indices.back);
7873            }
7874        }
7875    }
7876
7877    mixin ImplementLength!_indices;
7878
7879    static if (isRandomAccessRange!Indices)
7880    {
7881        /// Ditto
7882        auto ref opIndex(size_t index)
7883        {
7884            return _source[_indices[index]];
7885        }
7886
7887        static if (hasSlicing!Indices)
7888        {
7889            /// Ditto
7890            typeof(this) opSlice(size_t a, size_t b)
7891            {
7892                return typeof(this)(_source, _indices[a .. b]);
7893            }
7894        }
7895
7896
7897        static if (hasAssignableElements!Source)
7898        {
7899            /// Ditto
7900            auto opIndexAssign(ElementType!Source newVal, size_t index)
7901            {
7902                return _source[_indices[index]] = newVal;
7903            }
7904        }
7905
7906
7907        static if (hasMobileElements!Source)
7908        {
7909            /// Ditto
7910            auto moveAt(size_t index)
7911            {
7912                return _source.moveAt(_indices[index]);
7913            }
7914        }
7915    }
7916
7917    // All this stuff is useful if someone wants to index an Indexed
7918    // without adding a layer of indirection.
7919
7920    /**
7921    Returns the source range.
7922    */
7923    @property Source source()
7924    {
7925        return _source;
7926    }
7927
7928    /**
7929    Returns the indices range.
7930    */
7931     @property Indices indices()
7932    {
7933        return _indices;
7934    }
7935
7936    static if (isRandomAccessRange!Indices)
7937    {
7938        /**
7939        Returns the physical index into the source range corresponding to a
7940        given logical index.  This is useful, for example, when indexing
7941        an `Indexed` without adding another layer of indirection.
7942        */
7943        size_t physicalIndex(size_t logicalIndex)
7944        {
7945            return _indices[logicalIndex];
7946        }
7947
7948        ///
7949        @safe unittest
7950        {
7951            auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
7952            assert(ind.physicalIndex(0) == 1);
7953        }
7954    }
7955
7956private:
7957    Source _source;
7958    Indices _indices;
7959
7960}
7961
7962/// Ditto
7963Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
7964{
7965    return typeof(return)(source, indices);
7966}
7967
7968///
7969@safe unittest
7970{
7971    import std.algorithm.comparison : equal;
7972    auto source = [1, 2, 3, 4, 5];
7973    auto indices = [4, 3, 1, 2, 0, 4];
7974    auto ind = indexed(source, indices);
7975    assert(equal(ind, [5, 4, 2, 3, 1, 5]));
7976    assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
7977}
7978
7979@safe unittest
7980{
7981    {
7982        auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
7983        assert(ind.physicalIndex(0) == 1);
7984    }
7985
7986    auto source = [1, 2, 3, 4, 5];
7987    auto indices = [4, 3, 1, 2, 0, 4];
7988    auto ind = indexed(source, indices);
7989
7990    // When elements of indices are duplicated and Source has lvalue elements,
7991    // these are aliased in ind.
7992    ind[0]++;
7993    assert(ind[0] == 6);
7994    assert(ind[5] == 6);
7995}
7996
7997@safe unittest
7998{
7999    import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
8000        propagatesRangeType, RangeType;
8001
8002    foreach (DummyType; AllDummyRanges)
8003    {
8004        auto d = DummyType.init;
8005        auto r = indexed([1, 2, 3, 4, 5], d);
8006        static assert(propagatesRangeType!(DummyType, typeof(r)));
8007        static assert(propagatesLength!(DummyType, typeof(r)));
8008    }
8009}
8010
8011/**
8012This range iterates over fixed-sized chunks of size `chunkSize` of a
8013`source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8014`chunkSize` must be greater than zero.
8015
8016If `!isInfinite!Source` and `source.walkLength` is not evenly
8017divisible by `chunkSize`, the back element of this range will contain
8018fewer than `chunkSize` elements.
8019
8020If `Source` is a forward range, the resulting range will be forward ranges as
8021well. Otherwise, the resulting chunks will be input ranges consuming the same
8022input: iterating over `front` will shrink the chunk such that subsequent
8023invocations of `front` will no longer return the full chunk, and calling
8024`popFront` on the outer range will invalidate any lingering references to
8025previous values of `front`.
8026
8027Params:
8028    source = Range from which the chunks will be selected
8029    chunkSize = Chunk size
8030
8031See_Also: $(LREF slide)
8032
8033Returns: Range of chunks.
8034*/
8035struct Chunks(Source)
8036if (isInputRange!Source)
8037{
8038    static if (isForwardRange!Source)
8039    {
8040        /// Standard constructor
8041        this(Source source, size_t chunkSize)
8042        {
8043            assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8044            _source = source;
8045            _chunkSize = chunkSize;
8046        }
8047
8048        /// Input range primitives. Always present.
8049        @property auto front()
8050        {
8051            assert(!empty, "Attempting to fetch the front of an empty Chunks");
8052            return _source.save.take(_chunkSize);
8053        }
8054
8055        /// Ditto
8056        void popFront()
8057        {
8058            assert(!empty, "Attempting to popFront and empty Chunks");
8059            _source.popFrontN(_chunkSize);
8060        }
8061
8062        static if (!isInfinite!Source)
8063            /// Ditto
8064            @property bool empty()
8065            {
8066                return _source.empty;
8067            }
8068        else
8069            // undocumented
8070            enum empty = false;
8071
8072        /// Forward range primitives. Only present if `Source` is a forward range.
8073        @property typeof(this) save()
8074        {
8075            return typeof(this)(_source.save, _chunkSize);
8076        }
8077
8078        static if (hasLength!Source)
8079        {
8080            /// Length. Only if `hasLength!Source` is `true`
8081            @property size_t length()
8082            {
8083                // Note: _source.length + _chunkSize may actually overflow.
8084                // We cast to ulong to mitigate the problem on x86 machines.
8085                // For x64 machines, we just suppose we'll never overflow.
8086                // The "safe" code would require either an extra branch, or a
8087                //   modulo operation, which is too expensive for such a rare case
8088                return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8089            }
8090            //Note: No point in defining opDollar here without slicing.
8091            //opDollar is defined below in the hasSlicing!Source section
8092        }
8093
8094        static if (hasSlicing!Source)
8095        {
8096            //Used for various purposes
8097            private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8098
8099            /**
8100            Indexing and slicing operations. Provided only if
8101            `hasSlicing!Source` is `true`.
8102             */
8103            auto opIndex(size_t index)
8104            {
8105                immutable start = index * _chunkSize;
8106                immutable end   = start + _chunkSize;
8107
8108                static if (isInfinite!Source)
8109                    return _source[start .. end];
8110                else
8111                {
8112                    import std.algorithm.comparison : min;
8113                    immutable len = _source.length;
8114                    assert(start < len, "chunks index out of bounds");
8115                    return _source[start .. min(end, len)];
8116                }
8117            }
8118
8119            /// Ditto
8120            static if (hasLength!Source)
8121                typeof(this) opSlice(size_t lower, size_t upper)
8122                {
8123                    import std.algorithm.comparison : min;
8124                    assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8125                    immutable len = _source.length;
8126                    return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8127                }
8128            else static if (hasSliceToEnd)
8129                //For slicing an infinite chunk, we need to slice the source to the end.
8130                typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8131                {
8132                    assert(lower <= upper, "chunks slicing index out of bounds");
8133                    return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8134                }
8135
8136            static if (isInfinite!Source)
8137            {
8138                static if (hasSliceToEnd)
8139                {
8140                    private static struct DollarToken{}
8141                    DollarToken opDollar()
8142                    {
8143                        return DollarToken();
8144                    }
8145                    //Slice to dollar
8146                    typeof(this) opSlice(size_t lower, DollarToken)
8147                    {
8148                        return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8149                    }
8150                }
8151            }
8152            else
8153            {
8154                //Dollar token carries a static type, with no extra information.
8155                //It can lazily transform into _source.length on algorithmic
8156                //operations such as : chunks[$/2, $-1];
8157                private static struct DollarToken
8158                {
8159                    Chunks!Source* mom;
8160                    @property size_t momLength()
8161                    {
8162                        return mom.length;
8163                    }
8164                    alias momLength this;
8165                }
8166                DollarToken opDollar()
8167                {
8168                    return DollarToken(&this);
8169                }
8170
8171                //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8172                //1. Evaluate chunks.length
8173                //2. Multiply by _chunksSize
8174                //3. To finally just compare it (with min) to the original length of source (!)
8175                //These overloads avoid that.
8176                typeof(this) opSlice(DollarToken, DollarToken)
8177                {
8178                    static if (hasSliceToEnd)
8179                        return chunks(_source[$ .. $], _chunkSize);
8180                    else
8181                    {
8182                        immutable len = _source.length;
8183                        return chunks(_source[len .. len], _chunkSize);
8184                    }
8185                }
8186                typeof(this) opSlice(size_t lower, DollarToken)
8187                {
8188                    import std.algorithm.comparison : min;
8189                    assert(lower <= length, "chunks slicing index out of bounds");
8190                    static if (hasSliceToEnd)
8191                        return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8192                    else
8193                    {
8194                        immutable len = _source.length;
8195                        return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8196                    }
8197                }
8198                typeof(this) opSlice(DollarToken, size_t upper)
8199                {
8200                    assert(upper == length, "chunks slicing index out of bounds");
8201                    return this[$ .. $];
8202                }
8203            }
8204        }
8205
8206        //Bidirectional range primitives
8207        static if (hasSlicing!Source && hasLength!Source)
8208        {
8209            /**
8210            Bidirectional range primitives. Provided only if both
8211            `hasSlicing!Source` and `hasLength!Source` are `true`.
8212             */
8213            @property auto back()
8214            {
8215                assert(!empty, "back called on empty chunks");
8216                immutable len = _source.length;
8217                immutable start = (len - 1) / _chunkSize * _chunkSize;
8218                return _source[start .. len];
8219            }
8220
8221            /// Ditto
8222            void popBack()
8223            {
8224                assert(!empty, "popBack() called on empty chunks");
8225                immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8226                _source = _source[0 .. end];
8227            }
8228        }
8229
8230    private:
8231        Source _source;
8232        size_t _chunkSize;
8233    }
8234    else // is input range only
8235    {
8236        import std.typecons : RefCounted;
8237
8238        static struct Chunk
8239        {
8240            private RefCounted!Impl impl;
8241
8242            @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8243            @property auto front() { return impl.r.front; }
8244            void popFront()
8245            {
8246                assert(impl.curSizeLeft > 0 && !impl.r.empty);
8247                impl.curSizeLeft--;
8248                impl.r.popFront();
8249            }
8250        }
8251
8252        static struct Impl
8253        {
8254            private Source r;
8255            private size_t chunkSize;
8256            private size_t curSizeLeft;
8257        }
8258
8259        private RefCounted!Impl impl;
8260
8261        private this(Source r, size_t chunkSize)
8262        {
8263            impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8264        }
8265
8266        @property bool empty() { return impl.chunkSize == 0; }
8267        @property Chunk front() return { return Chunk(impl); }
8268
8269        void popFront()
8270        {
8271            impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8272            if (!impl.r.empty)
8273                impl.curSizeLeft = impl.chunkSize;
8274            else
8275                impl.chunkSize = 0;
8276        }
8277
8278        static assert(isInputRange!(typeof(this)));
8279    }
8280}
8281
8282/// Ditto
8283Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8284if (isInputRange!Source)
8285{
8286    return typeof(return)(source, chunkSize);
8287}
8288
8289///
8290@safe unittest
8291{
8292    import std.algorithm.comparison : equal;
8293    auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8294    auto chunks = chunks(source, 4);
8295    assert(chunks[0] == [1, 2, 3, 4]);
8296    assert(chunks[1] == [5, 6, 7, 8]);
8297    assert(chunks[2] == [9, 10]);
8298    assert(chunks.back == chunks[2]);
8299    assert(chunks.front == chunks[0]);
8300    assert(chunks.length == 3);
8301    assert(equal(retro(array(chunks)), array(retro(chunks))));
8302}
8303
8304/// Non-forward input ranges are supported, but with limited semantics.
8305@system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8306{
8307    import std.algorithm.comparison : equal;
8308
8309    int i;
8310
8311    // The generator doesn't save state, so it cannot be a forward range.
8312    auto inputRange = generate!(() => ++i).take(10);
8313
8314    // We can still process it in chunks, but it will be single-pass only.
8315    auto chunked = inputRange.chunks(2);
8316
8317    assert(chunked.front.equal([1, 2]));
8318    assert(chunked.front.empty); // Iterating the chunk has consumed it
8319    chunked.popFront;
8320    assert(chunked.front.equal([3, 4]));
8321}
8322
8323@system /*@safe*/ unittest
8324{
8325    import std.algorithm.comparison : equal;
8326    import std.internal.test.dummyrange : ReferenceInputRange;
8327
8328    auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
8329    auto r = new ReferenceInputRange!int(data).chunks(3);
8330    assert(r.equal!equal([
8331        [ 1, 2, 3 ],
8332        [ 4, 5, 6 ],
8333        [ 7, 8, 9 ],
8334        [ 10 ]
8335    ]));
8336
8337    auto data2 = [ 1, 2, 3, 4, 5, 6 ];
8338    auto r2 = new ReferenceInputRange!int(data2).chunks(3);
8339    assert(r2.equal!equal([
8340        [ 1, 2, 3 ],
8341        [ 4, 5, 6 ]
8342    ]));
8343
8344    auto data3 = [ 1, 2, 3, 4, 5 ];
8345    auto r3 = new ReferenceInputRange!int(data3).chunks(2);
8346    assert(r3.front.equal([1, 2]));
8347    r3.popFront();
8348    assert(!r3.empty);
8349    r3.popFront();
8350    assert(r3.front.equal([5]));
8351}
8352
8353@safe unittest
8354{
8355    auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8356    auto chunks = chunks(source, 4);
8357    auto chunks2 = chunks.save;
8358    chunks.popFront();
8359    assert(chunks[0] == [5, 6, 7, 8]);
8360    assert(chunks[1] == [9, 10]);
8361    chunks2.popBack();
8362    assert(chunks2[1] == [5, 6, 7, 8]);
8363    assert(chunks2.length == 2);
8364
8365    static assert(isRandomAccessRange!(typeof(chunks)));
8366}
8367
8368@safe unittest
8369{
8370    import std.algorithm.comparison : equal;
8371
8372    //Extra toying with slicing and indexing.
8373    auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
8374    auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
8375
8376    assert(chunks1.length == 5);
8377    assert(chunks2.length == 5);
8378    assert(chunks1[4] == [4]);
8379    assert(chunks2[4] == [4, 4]);
8380    assert(chunks1.back == [4]);
8381    assert(chunks2.back == [4, 4]);
8382
8383    assert(chunks1[0 .. 1].equal([[0, 0]]));
8384    assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
8385    assert(chunks1[4 .. 5].equal([[4]]));
8386    assert(chunks2[4 .. 5].equal([[4, 4]]));
8387
8388    assert(chunks1[0 .. 0].equal((int[][]).init));
8389    assert(chunks1[5 .. 5].equal((int[][]).init));
8390    assert(chunks2[5 .. 5].equal((int[][]).init));
8391
8392    //Fun with opDollar
8393    assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
8394    assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
8395    assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
8396    assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
8397    assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
8398    assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
8399
8400    assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
8401}
8402
8403@safe unittest
8404{
8405    import std.algorithm.comparison : equal;
8406    import std.algorithm.iteration : filter;
8407
8408    //ForwardRange
8409    auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
8410    assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
8411
8412    //InfiniteRange w/o RA
8413    auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
8414    assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
8415
8416    //InfiniteRange w/ RA and slicing
8417    auto odds = sequence!("a[0] + n * a[1]")(1, 2);
8418    auto oddsByPairs = odds.chunks(2);
8419    assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
8420
8421    //Requires phobos#991 for Sequence to have slice to end
8422    static assert(hasSlicing!(typeof(odds)));
8423    assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
8424    assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
8425}
8426
8427
8428
8429/**
8430This range splits a `source` range into `chunkCount` chunks of
8431approximately equal length. `Source` must be a forward range with
8432known length.
8433
8434Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
8435The returned range will contain zero or more $(D source.length /
8436chunkCount + 1) elements followed by $(D source.length / chunkCount)
8437elements. If $(D source.length < chunkCount), some chunks will be empty.
8438
8439`chunkCount` must not be zero, unless `source` is also empty.
8440*/
8441struct EvenChunks(Source)
8442if (isForwardRange!Source && hasLength!Source)
8443{
8444    /// Standard constructor
8445    this(Source source, size_t chunkCount)
8446    {
8447        assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
8448        _source = source;
8449        _chunkCount = chunkCount;
8450    }
8451
8452    /// Forward range primitives. Always present.
8453    @property auto front()
8454    {
8455        assert(!empty, "Attempting to fetch the front of an empty evenChunks");
8456        return _source.save.take(_chunkPos(1));
8457    }
8458
8459    /// Ditto
8460    void popFront()
8461    {
8462        assert(!empty, "Attempting to popFront an empty evenChunks");
8463        _source.popFrontN(_chunkPos(1));
8464        _chunkCount--;
8465    }
8466
8467    /// Ditto
8468    @property bool empty()
8469    {
8470        return _chunkCount == 0;
8471    }
8472
8473    /// Ditto
8474    @property typeof(this) save()
8475    {
8476        return typeof(this)(_source.save, _chunkCount);
8477    }
8478
8479    /// Length
8480    @property size_t length() const
8481    {
8482        return _chunkCount;
8483    }
8484    //Note: No point in defining opDollar here without slicing.
8485    //opDollar is defined below in the hasSlicing!Source section
8486
8487    static if (hasSlicing!Source)
8488    {
8489        /**
8490        Indexing, slicing and bidirectional operations and range primitives.
8491        Provided only if `hasSlicing!Source` is `true`.
8492         */
8493        auto opIndex(size_t index)
8494        {
8495            assert(index < _chunkCount, "evenChunks index out of bounds");
8496            return _source[_chunkPos(index) .. _chunkPos(index+1)];
8497        }
8498
8499        /// Ditto
8500        typeof(this) opSlice(size_t lower, size_t upper)
8501        {
8502            assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
8503            return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
8504        }
8505
8506        /// Ditto
8507        @property auto back()
8508        {
8509            assert(!empty, "back called on empty evenChunks");
8510            return _source[_chunkPos(_chunkCount - 1) .. _source.length];
8511        }
8512
8513        /// Ditto
8514        void popBack()
8515        {
8516            assert(!empty, "popBack() called on empty evenChunks");
8517            _source = _source[0 .. _chunkPos(_chunkCount - 1)];
8518            _chunkCount--;
8519        }
8520    }
8521
8522private:
8523    Source _source;
8524    size_t _chunkCount;
8525
8526    size_t _chunkPos(size_t i)
8527    {
8528        /*
8529            _chunkCount = 5, _source.length = 13:
8530
8531               chunk0
8532                 |   chunk3
8533                 |     |
8534                 v     v
8535                +-+-+-+-+-+   ^
8536                |0|3|.| | |   |
8537                +-+-+-+-+-+   | div
8538                |1|4|.| | |   |
8539                +-+-+-+-+-+   v
8540                |2|5|.|
8541                +-+-+-+
8542
8543                <----->
8544                  mod
8545
8546                <--------->
8547                _chunkCount
8548
8549            One column is one chunk.
8550            popFront and popBack pop the left-most
8551            and right-most column, respectively.
8552        */
8553
8554        auto div = _source.length / _chunkCount;
8555        auto mod = _source.length % _chunkCount;
8556        auto pos = i <= mod
8557            ? i   * (div+1)
8558            : mod * (div+1) + (i-mod) * div
8559        ;
8560        //auto len = i < mod
8561        //    ? div+1
8562        //    : div
8563        //;
8564        return pos;
8565    }
8566}
8567
8568/// Ditto
8569EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
8570if (isForwardRange!Source && hasLength!Source)
8571{
8572    return typeof(return)(source, chunkCount);
8573}
8574
8575///
8576@safe unittest
8577{
8578    import std.algorithm.comparison : equal;
8579    auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8580    auto chunks = evenChunks(source, 3);
8581    assert(chunks[0] == [1, 2, 3, 4]);
8582    assert(chunks[1] == [5, 6, 7]);
8583    assert(chunks[2] == [8, 9, 10]);
8584}
8585
8586@safe unittest
8587{
8588    import std.algorithm.comparison : equal;
8589
8590    auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8591    auto chunks = evenChunks(source, 3);
8592    assert(chunks.back == chunks[2]);
8593    assert(chunks.front == chunks[0]);
8594    assert(chunks.length == 3);
8595    assert(equal(retro(array(chunks)), array(retro(chunks))));
8596
8597    auto chunks2 = chunks.save;
8598    chunks.popFront();
8599    assert(chunks[0] == [5, 6, 7]);
8600    assert(chunks[1] == [8, 9, 10]);
8601    chunks2.popBack();
8602    assert(chunks2[1] == [5, 6, 7]);
8603    assert(chunks2.length == 2);
8604
8605    static assert(isRandomAccessRange!(typeof(chunks)));
8606}
8607
8608@safe unittest
8609{
8610    import std.algorithm.comparison : equal;
8611
8612    int[] source = [];
8613    auto chunks = source.evenChunks(0);
8614    assert(chunks.length == 0);
8615    chunks = source.evenChunks(3);
8616    assert(equal(chunks, [[], [], []]));
8617    chunks = [1, 2, 3].evenChunks(5);
8618    assert(equal(chunks, [[1], [2], [3], [], []]));
8619}
8620
8621/**
8622A fixed-sized sliding window iteration
8623of size `windowSize` over a `source` range by a custom `stepSize`.
8624
8625The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
8626and the `windowSize` must be greater than zero.
8627
8628For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
8629For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
8630
8631Params:
8632    f = Whether the last element has fewer elements than `windowSize`
8633        it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
8634    source = Range from which the slide will be selected
8635    windowSize = Sliding window size
8636    stepSize = Steps between the windows (by default 1)
8637
8638Returns: Range of all sliding windows with propagated bi-directionality,
8639         forwarding, random access, and slicing.
8640
8641Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
8642      is only available when $(REF hasSlicing, std,range,primitives)
8643      and $(REF hasLength, std,range,primitives) are true.
8644
8645See_Also: $(LREF chunks)
8646*/
8647auto slide(Flag!"withPartial" f = Yes.withPartial,
8648            Source)(Source source, size_t windowSize, size_t stepSize = 1)
8649if (isForwardRange!Source)
8650{
8651    return Slides!(f, Source)(source, windowSize, stepSize);
8652}
8653
8654/// Iterate over ranges with windows
8655@safe pure nothrow unittest
8656{
8657    import std.algorithm.comparison : equal;
8658
8659    assert([0, 1, 2, 3].slide(2).equal!equal(
8660        [[0, 1], [1, 2], [2, 3]]
8661    ));
8662
8663    assert(5.iota.slide(3).equal!equal(
8664        [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
8665    ));
8666}
8667
8668/// set a custom stepsize (default 1)
8669@safe pure nothrow unittest
8670{
8671    import std.algorithm.comparison : equal;
8672
8673    assert(6.iota.slide(1, 2).equal!equal(
8674        [[0], [2], [4]]
8675    ));
8676
8677    assert(6.iota.slide(2, 4).equal!equal(
8678        [[0, 1], [4, 5]]
8679    ));
8680
8681    assert(iota(7).slide(2, 2).equal!equal(
8682        [[0, 1], [2, 3], [4, 5], [6]]
8683    ));
8684
8685    assert(iota(12).slide(2, 4).equal!equal(
8686        [[0, 1], [4, 5], [8, 9]]
8687    ));
8688}
8689
8690/// Allow the last slide to have fewer elements than windowSize
8691@safe pure nothrow unittest
8692{
8693    import std.algorithm.comparison : equal;
8694
8695    assert(3.iota.slide!(No.withPartial)(4).empty);
8696    assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
8697        [[0, 1, 2]]
8698    ));
8699}
8700
8701/// Count all the possible substrings of length 2
8702@safe pure nothrow unittest
8703{
8704    import std.algorithm.iteration : each;
8705
8706    int[dstring] d;
8707    "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
8708    assert(d == ["AG"d: 2, "GA"d: 2]);
8709}
8710
8711/// withPartial only has an effect if last element in the range doesn't have the full size
8712@safe pure nothrow unittest
8713{
8714    import std.algorithm.comparison : equal;
8715
8716    assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
8717    assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
8718    assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
8719
8720    assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
8721    assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
8722    assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
8723}
8724
8725private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
8726if (isForwardRange!Source)
8727{
8728private:
8729    Source source;
8730    size_t windowSize;
8731    size_t stepSize;
8732
8733    static if (hasLength!Source)
8734    {
8735        enum needsEndTracker = false;
8736    }
8737    else
8738    {
8739        // If there's no information about the length, track needs to be kept manually
8740        Source nextSource;
8741        enum needsEndTracker = true;
8742    }
8743
8744    bool _empty;
8745
8746    static if (hasSlicing!Source)
8747        enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
8748
8749    static if (withPartial)
8750        bool hasShownPartialBefore;
8751
8752public:
8753    /// Standard constructor
8754    this(Source source, size_t windowSize, size_t stepSize)
8755    {
8756        assert(windowSize > 0, "windowSize must be greater than zero");
8757        assert(stepSize > 0, "stepSize must be greater than zero");
8758        this.source = source;
8759        this.windowSize = windowSize;
8760        this.stepSize = stepSize;
8761
8762        static if (needsEndTracker)
8763        {
8764            // `nextSource` is used to "look one step into the future" and check for the end
8765            // this means `nextSource` is advanced by `stepSize` on every `popFront`
8766            nextSource = source.save.drop(windowSize);
8767        }
8768
8769        if (source.empty)
8770        {
8771            _empty = true;
8772            return;
8773        }
8774
8775        static if (withPartial)
8776        {
8777            static if (needsEndTracker)
8778            {
8779                if (nextSource.empty)
8780                    hasShownPartialBefore = true;
8781            }
8782            else
8783            {
8784                if (source.length <= windowSize)
8785                    hasShownPartialBefore = true;
8786            }
8787
8788        }
8789        else
8790        {
8791            // empty source range is needed, s.t. length, slicing etc. works properly
8792            static if (needsEndTracker)
8793            {
8794                if (nextSource.empty)
8795                     _empty = true;
8796            }
8797            else
8798            {
8799                if (source.length < windowSize)
8800                     _empty = true;
8801            }
8802        }
8803    }
8804
8805    /// Forward range primitives. Always present.
8806    @property auto front()
8807    {
8808        assert(!empty, "Attempting to access front on an empty slide.");
8809        static if (hasSlicing!Source && hasLength!Source)
8810        {
8811            static if (withPartial)
8812            {
8813                import std.algorithm.comparison : min;
8814                return source[0 .. min(windowSize, source.length)];
8815            }
8816            else
8817            {
8818                assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
8819                return source[0 .. windowSize];
8820            }
8821        }
8822        else
8823        {
8824            static if (withPartial)
8825                return source.save.take(windowSize);
8826            else
8827                return source.save.takeExactly(windowSize);
8828        }
8829    }
8830
8831    /// Ditto
8832    void popFront()
8833    {
8834        assert(!empty, "Attempting to call popFront() on an empty slide.");
8835        source.popFrontN(stepSize);
8836
8837        if (source.empty)
8838        {
8839            _empty = true;
8840            return;
8841        }
8842
8843        static if (withPartial)
8844        {
8845            if (hasShownPartialBefore)
8846                _empty = true;
8847        }
8848
8849        static if (needsEndTracker)
8850        {
8851            // Check the upcoming slide
8852            auto poppedElements = nextSource.popFrontN(stepSize);
8853            static if (withPartial)
8854            {
8855                if (poppedElements < stepSize || nextSource.empty)
8856                    hasShownPartialBefore = true;
8857            }
8858            else
8859            {
8860                if (poppedElements < stepSize)
8861                    _empty = true;
8862            }
8863        }
8864        else
8865        {
8866            static if (withPartial)
8867            {
8868                if (source.length <= windowSize)
8869                    hasShownPartialBefore = true;
8870            }
8871            else
8872            {
8873                if (source.length < windowSize)
8874                    _empty = true;
8875            }
8876        }
8877    }
8878
8879    static if (!isInfinite!Source)
8880    {
8881        /// Ditto
8882        @property bool empty() const
8883        {
8884            return _empty;
8885        }
8886    }
8887    else
8888    {
8889        // undocumented
8890        enum empty = false;
8891    }
8892
8893    /// Ditto
8894    @property typeof(this) save()
8895    {
8896        return typeof(this)(source.save, windowSize, stepSize);
8897    }
8898
8899    static if (hasLength!Source)
8900    {
8901        // gaps between the last element and the end of the range
8902        private size_t gap()
8903        {
8904            /*
8905            * Note:
8906            * - In the following `end` is the exclusive end as used in opSlice
8907            * - For the trivial case with `stepSize = 1`  `end` is at `len`:
8908            *
8909            *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]]    (end = 4)
8910            *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]      (end = 4)
8911            *
8912            * - For the non-trivial cases, we need to calculate the gap
8913            *   between `len` and `end` - this is the number of missing elements
8914            *   from the input range:
8915            *
8916            *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
8917            *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
8918            *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
8919            *
8920            *   As it can be seen `gap` can be at most `stepSize - 1`
8921            *   More generally the elements of the sliding window with
8922            *   `w = windowSize` and `s = stepSize` are:
8923            *
8924            *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
8925            *
8926            *  We can thus calculate the gap between the `end` and `len` as:
8927            *
8928            *     gap = len - (n * s + w) = len - w - (n * s)
8929            *
8930            *  As we aren't interested in exact value of `n`, but the best
8931            *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
8932            *
8933            *     gap = len - w - (s - s ... - s) = (len - w) % s
8934            *
8935            *  So for example:
8936            *
8937            *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
8938            *      gap: (7 - 2) % 3 = 5 % 3 = 2
8939            *      end: 7 - 2 = 5
8940            *
8941            *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
8942            *      gap: (7 - 4) % 2 = 3 % 2 = 1
8943            *      end: 7 - 1 = 6
8944            */
8945            return (source.length - windowSize)  % stepSize;
8946        }
8947
8948        private size_t numberOfFullFrames()
8949        {
8950            /**
8951            5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
8952            7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (3)
8953            7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (2)
8954            6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5]         (2)
8955            7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (2)
8956
8957            As the last window is only added iff its complete,
8958            we don't count the last window except if it's full due to integer rounding.
8959            */
8960            return 1 + (source.length - windowSize) / stepSize;
8961        }
8962
8963        // Whether the last slide frame size is less than windowSize
8964        private bool hasPartialElements()
8965        {
8966            static if (withPartial)
8967                return gap != 0 && source.length > numberOfFullFrames * stepSize;
8968            else
8969                return 0;
8970        }
8971
8972        /// Length. Only if `hasLength!Source` is `true`
8973        @property size_t length()
8974        {
8975            if (source.length < windowSize)
8976            {
8977                static if (withPartial)
8978                    return source.length > 0;
8979                else
8980                    return 0;
8981            }
8982            else
8983            {
8984                /***
8985                  We bump the pointer by stepSize for every element.
8986                  If withPartial, we don't count the last element if its size
8987                  isn't windowSize
8988
8989                  At most:
8990                      [p, p + stepSize, ..., p + stepSize * n]
8991
8992                5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4]       (4)
8993                7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6]          (4)
8994                7.iota.slides(2, 3) => [0, 1], [3, 4], [6]                  (3)
8995                7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6]      (3)
8996                7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6]            (3)
8997                */
8998                return numberOfFullFrames + hasPartialElements;
8999            }
9000        }
9001    }
9002
9003    static if (hasSlicing!Source)
9004    {
9005        /**
9006        Indexing and slicing operations. Provided only if
9007        `hasSlicing!Source` is `true`.
9008         */
9009        auto opIndex(size_t index)
9010        {
9011            immutable start = index * stepSize;
9012
9013            static if (isInfinite!Source)
9014            {
9015                immutable end = start + windowSize;
9016            }
9017            else
9018            {
9019                import std.algorithm.comparison : min;
9020
9021                immutable len = source.length;
9022                assert(start < len, "slide index out of bounds");
9023                immutable end = min(start + windowSize, len);
9024            }
9025
9026            return source[start .. end];
9027        }
9028
9029        static if (!isInfinite!Source)
9030        {
9031            /// ditto
9032            typeof(this) opSlice(size_t lower, size_t upper)
9033            {
9034                import std.algorithm.comparison : min;
9035
9036                assert(upper <= length, "slide slicing index out of bounds");
9037                assert(lower <= upper, "slide slicing index out of bounds");
9038
9039                lower *= stepSize;
9040                upper *= stepSize;
9041
9042                immutable len = source.length;
9043
9044                static if (withPartial)
9045                {
9046                    import std.algorithm.comparison : max;
9047
9048                    if (lower == upper)
9049                        return this[$ .. $];
9050
9051                    /*
9052                    A) If `stepSize` >= `windowSize` => `rightPos = upper`
9053
9054                       [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9055                         rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9056                         6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9057
9058                    B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9059
9060                       [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9061                         rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9062                         1.iota.slide(2) = [[0]]
9063
9064                         rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9065                         1.iota.slide(2) = [[0, 1]]
9066
9067                       More complex:
9068
9069                       20.iota.slide(7, 6)[0 .. 2]
9070                         rightPos: (upper=2) * (stepSize=6) = 12.iota
9071                         12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9072
9073                       Now we add up for the difference between `windowSize` and `stepSize`:
9074
9075                         rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9076                         13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9077                    */
9078                    immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9079                }
9080                else
9081                {
9082                    /*
9083                    After we have normalized `lower` and `upper` by `stepSize`,
9084                    we only need to look at the case of `stepSize=1`.
9085                    As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9086                    Notice that starting from `upper`,
9087                    we only need to move for `windowSize - 1` to the right:
9088
9089                      - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9090                        rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9091
9092                      - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9093                        rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9094
9095                      - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9096                        rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9097                    */
9098                    immutable rightPos = min(upper + windowSize - 1, len);
9099                }
9100
9101                return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9102            }
9103        }
9104        else static if (hasSliceToEnd)
9105        {
9106            // For slicing an infinite chunk, we need to slice the source to the infinite end.
9107            auto opSlice(size_t lower, size_t upper)
9108            {
9109                assert(lower <= upper, "slide slicing index out of bounds");
9110                return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9111                                    .takeExactly(upper - lower);
9112            }
9113        }
9114
9115        static if (isInfinite!Source)
9116        {
9117            static if (hasSliceToEnd)
9118            {
9119                private static struct DollarToken{}
9120                DollarToken opDollar()
9121                {
9122                    return DollarToken();
9123                }
9124                //Slice to dollar
9125                typeof(this) opSlice(size_t lower, DollarToken)
9126                {
9127                    return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9128                }
9129            }
9130        }
9131        else
9132        {
9133            // Dollar token carries a static type, with no extra information.
9134            // It can lazily transform into source.length on algorithmic
9135            // operations such as : slide[$/2, $-1];
9136            private static struct DollarToken
9137            {
9138                private size_t _length;
9139                alias _length this;
9140            }
9141
9142            DollarToken opDollar()
9143            {
9144                return DollarToken(this.length);
9145            }
9146
9147            // Optimized slice overloads optimized for using dollar.
9148            typeof(this) opSlice(DollarToken, DollarToken)
9149            {
9150                static if (hasSliceToEnd)
9151                {
9152                    return typeof(this)(source[$ .. $], windowSize, stepSize);
9153                }
9154                else
9155                {
9156                    immutable len = source.length;
9157                    return typeof(this)(source[len .. len], windowSize, stepSize);
9158                }
9159            }
9160
9161            // Optimized slice overloads optimized for using dollar.
9162            typeof(this) opSlice(size_t lower, DollarToken)
9163            {
9164                import std.algorithm.comparison : min;
9165                assert(lower <= length, "slide slicing index out of bounds");
9166                lower *= stepSize;
9167                static if (hasSliceToEnd)
9168                {
9169                    return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9170                }
9171                else
9172                {
9173                    immutable len = source.length;
9174                    return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9175                }
9176            }
9177
9178            // Optimized slice overloads optimized for using dollar.
9179            typeof(this) opSlice(DollarToken, size_t upper)
9180            {
9181                assert(upper == length, "slide slicing index out of bounds");
9182                return this[$ .. $];
9183            }
9184        }
9185
9186        // Bidirectional range primitives
9187        static if (!isInfinite!Source)
9188        {
9189            /**
9190            Bidirectional range primitives. Provided only if both
9191            `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9192             */
9193            @property auto back()
9194            {
9195                import std.algorithm.comparison : max;
9196
9197                assert(!empty, "Attempting to access front on an empty slide");
9198
9199                immutable len = source.length;
9200
9201                static if (withPartial)
9202                {
9203                    if (source.length <= windowSize)
9204                        return source[0 .. source.length];
9205
9206                    if (hasPartialElements)
9207                        return source[numberOfFullFrames * stepSize .. len];
9208                }
9209
9210                // check for underflow
9211                immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9212                return source[start .. len - gap];
9213            }
9214
9215            /// Ditto
9216            void popBack()
9217            {
9218                assert(!empty, "Attempting to call popBack() on an empty slide");
9219
9220                // Move by stepSize
9221                immutable end = source.length > stepSize ? source.length - stepSize : 0;
9222
9223                static if (withPartial)
9224                {
9225                    if (hasShownPartialBefore || source.empty)
9226                    {
9227                        _empty = true;
9228                        return;
9229                    }
9230
9231                    // pop by stepSize, except for the partial frame at the end
9232                    if (hasPartialElements)
9233                        source = source[0 .. source.length - gap];
9234                    else
9235                        source = source[0 .. end];
9236                }
9237                else
9238                {
9239                    source = source[0 .. end];
9240                }
9241
9242                if (source.length < windowSize)
9243                    _empty = true;
9244            }
9245        }
9246    }
9247}
9248
9249// test @nogc
9250@safe pure nothrow @nogc unittest
9251{
9252    import std.algorithm.comparison : equal;
9253
9254    static immutable res1 = [[0], [1], [2], [3]];
9255    assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9256
9257    static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9258    assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9259}
9260
9261// test different window sizes
9262@safe pure nothrow unittest
9263{
9264    import std.array : array;
9265    import std.algorithm.comparison : equal;
9266
9267    assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9268    assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9269    assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9270    assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9271    assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9272    assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9273
9274    assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9275    assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9276    assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9277    assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9278    assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9279    assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9280    assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9281}
9282
9283// test combinations
9284@safe pure nothrow unittest
9285{
9286    import std.algorithm.comparison : equal;
9287    import std.typecons : tuple;
9288
9289    alias t = tuple;
9290    auto list = [
9291        t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9292        t(t(1, 2), [[0], [2], [4]]),
9293        t(t(1, 3), [[0], [3]]),
9294        t(t(1, 4), [[0], [4]]),
9295        t(t(1, 5), [[0], [5]]),
9296        t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9297        t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9298        t(t(2, 3), [[0, 1], [3, 4]]),
9299        t(t(2, 4), [[0, 1], [4, 5]]),
9300        t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9301        t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9302        t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9303        t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9304        t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9305    ];
9306
9307    static foreach (Partial; [Yes.withPartial, No.withPartial])
9308        foreach (e; list)
9309            assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9310
9311    auto listSpecial = [
9312        t(t(2, 5), [[0, 1], [5]]),
9313        t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9314        t(t(3, 4), [[0, 1, 2], [4, 5]]),
9315        t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9316        t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9317        t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9318    ];
9319    foreach (e; listSpecial)
9320    {
9321        assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
9322        assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
9323    }
9324}
9325
9326// test emptiness and copyability
9327@safe pure nothrow unittest
9328{
9329    import std.algorithm.comparison : equal;
9330    import std.algorithm.iteration : map;
9331
9332    // check with empty input
9333    int[] d;
9334    assert(d.slide!(Yes.withPartial)(2).empty);
9335    assert(d.slide!(Yes.withPartial)(2, 2).empty);
9336
9337    // is copyable?
9338    auto e = iota(5).slide!(Yes.withPartial)(2);
9339    e.popFront;
9340    assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9341    assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
9342    assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
9343}
9344
9345// test with strings
9346@safe pure nothrow unittest
9347{
9348    import std.algorithm.iteration : each;
9349
9350    int[dstring] f;
9351    "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
9352    assert(f == ["AGA"d: 2, "GAG"d: 1]);
9353
9354    int[dstring] g;
9355    "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
9356    assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
9357    g = null;
9358    "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
9359    assert(g == ["ABC"d:1, "DEF"d:1]);
9360}
9361
9362// test with utf8 strings
9363@safe unittest
9364{
9365    import std.stdio;
9366    import std.algorithm.comparison : equal;
9367
9368    assert("��.��.��.".slide!(Yes.withPartial)(3, 2).equal!equal(["��.��", "��.��", "��."]));
9369    assert("��.��.��.".slide!(No.withPartial)(3, 2).equal!equal(["��.��", "��.��"]));
9370
9371    "����������������������������������������".slide!(Yes.withPartial)(2, 4).equal!equal(["��������", "��������", "��������"]);
9372    "����������������������������������������".slide!(No.withPartial)(2, 4).equal!equal(["��������", "��������", "��������"]);
9373    "����������������������������������������".slide!(Yes.withPartial)(3, 3).equal!equal(["������������", "������������", "������������", "����"]);
9374    "����������������������������������������".slide!(No.withPartial)(3, 3).equal!equal(["������������", "������������", "������������"]);
9375}
9376
9377// test length
9378@safe pure nothrow unittest
9379{
9380    // Slides with fewer elements are empty or 1 for Yes.withPartial
9381    static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
9382    {{
9383        assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
9384        assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
9385        assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
9386    }}
9387
9388    static immutable list = [
9389    //  iota   slide    expected
9390        [4,    2, 1,     3, 3],
9391        [5,    3, 1,     3, 3],
9392        [7,    2, 2,     4, 3],
9393        [12,   2, 4,     3, 3],
9394        [6,    1, 2,     3, 3],
9395        [6,    2, 4,     2, 2],
9396        [3,    2, 4,     1, 1],
9397        [5,    2, 1,     4, 4],
9398        [7,    2, 2,     4, 3],
9399        [7,    2, 3,     3, 2],
9400        [7,    3, 2,     3, 3],
9401        [7,    3, 3,     3, 2],
9402    ];
9403    foreach (e; list)
9404    {
9405        assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
9406        assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
9407    }
9408}
9409
9410// test index and slicing
9411@safe pure nothrow unittest
9412{
9413    import std.algorithm.comparison : equal;
9414    import std.array : array;
9415
9416    static foreach (Partial; [Yes.withPartial, No.withPartial])
9417    {
9418        foreach (s; [5, 7, 10, 15, 20])
9419        foreach (windowSize; 1 .. 10)
9420        foreach (stepSize; 1 .. 10)
9421        {
9422            auto r = s.iota.slide!Partial(windowSize, stepSize);
9423            auto arr = r.array;
9424            assert(r.length == arr.length);
9425
9426            // test indexing
9427            foreach (i; 0 .. arr.length)
9428                assert(r[i] == arr[i]);
9429
9430            // test slicing
9431            foreach (i; 0 .. arr.length)
9432            {
9433                foreach (j; i .. arr.length)
9434                    assert(r[i .. j].equal(arr[i .. j]));
9435
9436                assert(r[i .. $].equal(arr[i .. $]));
9437            }
9438
9439            // test opDollar slicing
9440            assert(r[$/2 .. $].equal(arr[$/2 .. $]));
9441            assert(r[$ .. $].empty);
9442            if (arr.empty)
9443            {
9444                assert(r[$ .. 0].empty);
9445                assert(r[$/2 .. $].empty);
9446
9447            }
9448        }
9449    }
9450}
9451
9452// test with infinite ranges
9453@safe pure nothrow unittest
9454{
9455    import std.algorithm.comparison : equal;
9456
9457    static foreach (Partial; [Yes.withPartial, No.withPartial])
9458    {{
9459        // InfiniteRange without RandomAccess
9460        auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
9461        assert(fibs.slide!Partial(2).take(2).equal!equal([[1,  1], [1,  2]]));
9462        assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
9463
9464        // InfiniteRange with RandomAccess and slicing
9465        auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9466        auto oddsByPairs = odds.slide!Partial(2);
9467        assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
9468        assert(oddsByPairs[1].equal([3, 5]));
9469        assert(oddsByPairs[4].equal([9, 11]));
9470
9471        static assert(hasSlicing!(typeof(odds)));
9472        assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
9473        assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
9474
9475        auto oddsWithGaps = odds.slide!Partial(2, 4);
9476        assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
9477        assert(oddsWithGaps[2].equal([17, 19]));
9478        assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
9479        assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
9480    }}
9481}
9482
9483// test reverse
9484@safe pure nothrow unittest
9485{
9486    import std.algorithm.comparison : equal;
9487
9488    static foreach (Partial; [Yes.withPartial, No.withPartial])
9489    {{
9490        foreach (windowSize; 1 .. 15)
9491        foreach (stepSize; 1 .. 15)
9492        {
9493            auto r = 20.iota.slide!Partial(windowSize, stepSize);
9494            auto rArr = r.array.retro;
9495            auto rRetro = r.retro;
9496
9497            assert(rRetro.length == rArr.length);
9498            assert(rRetro.equal(rArr));
9499            assert(rRetro.array.retro.equal(r));
9500        }
9501    }}
9502}
9503
9504// test with dummy ranges
9505@safe pure nothrow unittest
9506{
9507    import std.algorithm.comparison : equal;
9508    import std.internal.test.dummyrange : AllDummyRanges;
9509    import std.meta : Filter;
9510
9511    static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9512    {{
9513        Range r;
9514
9515        static foreach (Partial; [Yes.withPartial, No.withPartial])
9516        {
9517            assert(r.slide!Partial(1).equal!equal(
9518                [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
9519            ));
9520            assert(r.slide!Partial(2).equal!equal(
9521                [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
9522            ));
9523            assert(r.slide!Partial(3).equal!equal(
9524                [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
9525                [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
9526            ));
9527            assert(r.slide!Partial(6).equal!equal(
9528                [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
9529                [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
9530            ));
9531        }
9532
9533        // special cases
9534        assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
9535        assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
9536        assert(r.slide!(No.withPartial)(15).empty);
9537        assert(r.slide!(No.withPartial)(15).walkLength == 0);
9538    }}
9539}
9540
9541// test with dummy ranges
9542@safe pure nothrow unittest
9543{
9544    import std.algorithm.comparison : equal;
9545    import std.internal.test.dummyrange : AllDummyRanges;
9546    import std.meta : Filter;
9547    import std.typecons : tuple;
9548
9549    alias t = tuple;
9550    static immutable list = [
9551    // iota   slide    expected
9552        t(6,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
9553        t(6,  t(4, 6), [[1, 2, 3, 4]]),
9554        t(6,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
9555        t(7,  t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
9556        t(7,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
9557        t(8,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
9558        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]]),
9559        t(8,  t(3, 4), [[1, 2, 3], [5, 6, 7]]),
9560        t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
9561    ];
9562
9563    static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9564    static foreach (Partial; [Yes.withPartial, No.withPartial])
9565    foreach (e; list)
9566        assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
9567
9568    static immutable listSpecial = [
9569    // iota   slide    expected
9570        t(6,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
9571        t(7,  t(4, 5), [[1, 2, 3, 4], [6, 7]]),
9572        t(7,  t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
9573        t(7,  t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
9574        t(8,  t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
9575        t(8,  t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
9576        t(8,  t(3, 6), [[1, 2, 3], [7, 8]]),
9577        t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
9578        t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
9579    ];
9580    static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
9581    static foreach (Partial; [Yes.withPartial, No.withPartial])
9582    foreach (e; listSpecial)
9583    {
9584        Range r;
9585        assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
9586        assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
9587    }
9588}
9589
9590// test reverse with dummy ranges
9591@safe pure nothrow unittest
9592{
9593    import std.algorithm.comparison : equal;
9594    import std.internal.test.dummyrange : AllDummyRanges;
9595    import std.meta : Filter, templateAnd;
9596    import std.typecons : tuple;
9597    alias t = tuple;
9598
9599    static immutable list = [
9600    //   slide   expected
9601        t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
9602        t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
9603        t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
9604                 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
9605        t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
9606        t(2, 4, [[9, 10], [5, 6], [1, 2]]),
9607    ];
9608
9609    static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
9610    {{
9611        Range r;
9612        static foreach (Partial; [Yes.withPartial, No.withPartial])
9613        {
9614            foreach (e; list)
9615                assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
9616
9617            // front = back
9618            foreach (windowSize; 1 .. 10)
9619            foreach (stepSize; 1 .. 10)
9620            {
9621                auto slider = r.slide!Partial(windowSize, stepSize);
9622                auto sliderRetro = slider.retro.array;
9623                assert(slider.length == sliderRetro.length);
9624                assert(sliderRetro.retro.equal!equal(slider));
9625            }
9626        }
9627
9628        // special cases
9629        assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
9630        assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
9631    }}
9632}
9633
9634// test different sliceable ranges
9635@safe pure nothrow unittest
9636{
9637    import std.algorithm.comparison : equal;
9638    import std.internal.test.dummyrange : AllDummyRanges;
9639    import std.meta : AliasSeq;
9640
9641    struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
9642                                 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
9643    {
9644        Range arr = 10.iota.array; // similar to DummyRange
9645        @property auto save() { return typeof(this)(arr); }
9646        @property auto front() { return arr[0]; }
9647        void popFront() { arr.popFront(); }
9648        auto opSlice(size_t i, size_t j)
9649        {
9650            // subslices can't be infinite
9651            return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
9652        }
9653
9654        static if (withInfiniteness)
9655        {
9656            enum empty = false;
9657        }
9658        else
9659        {
9660            @property bool empty() { return arr.empty; }
9661            @property auto length() { return arr.length; }
9662        }
9663
9664        static if (withOpDollar)
9665        {
9666            static if (withInfiniteness)
9667            {
9668                struct Dollar {}
9669                Dollar opDollar() const { return Dollar.init; }
9670
9671                // Slice to dollar
9672                typeof(this) opSlice(size_t lower, Dollar)
9673                {
9674                    return typeof(this)(arr[lower .. $]);
9675                }
9676
9677            }
9678            else
9679            {
9680                alias opDollar = length;
9681            }
9682        }
9683    }
9684
9685    import std.meta : Filter,  templateNot;
9686    alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
9687
9688    static foreach (Partial; [Yes.withPartial, No.withPartial])
9689    {{
9690        static foreach (Range; SliceableDummyRanges)
9691        {{
9692            Range r;
9693            r.reinit;
9694            r.arr[] -= 1; // use a 0-based array (for clarity)
9695
9696            assert(r.slide!Partial(2)[0].equal([0, 1]));
9697            assert(r.slide!Partial(2)[1].equal([1, 2]));
9698
9699            // saveable
9700            auto s = r.slide!Partial(2);
9701            assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
9702            s.save.popFront;
9703            assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
9704
9705            assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
9706        }}
9707
9708        static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
9709        {{
9710            Range r;
9711            r.reinit;
9712            r.arr[] -= 1; // use a 0-based array (for clarity)
9713
9714            assert(r.slide!(No.withPartial)(6).equal!equal(
9715                [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
9716                [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
9717            ));
9718            assert(r.slide!(No.withPartial)(16).empty);
9719
9720            assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
9721            assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
9722            assert(r.slide!Partial(2)[$ .. $].empty);
9723
9724            assert(r.slide!Partial(3).retro.equal!equal(
9725                [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
9726            ));
9727        }}
9728
9729        alias T = int[];
9730
9731        // separate checks for infinity
9732        auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
9733        assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
9734        assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
9735
9736        auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
9737        assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
9738        assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
9739        assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
9740    }}
9741}
9742
9743// https://issues.dlang.org/show_bug.cgi?id=19082
9744@safe unittest
9745{
9746    import std.algorithm.comparison : equal;
9747    import std.algorithm.iteration : map;
9748    assert([1].map!(x => x).slide(2).equal!equal([[1]]));
9749}
9750
9751private struct OnlyResult(Values...)
9752if (Values.length > 1)
9753{
9754    private enum arity = Values.length;
9755
9756    private alias UnqualValues = staticMap!(Unqual, Values);
9757
9758    private this(return scope ref Values values)
9759    {
9760        ref @trusted unqual(T)(ref T x){return cast() x;}
9761
9762        // TODO: this calls any possible copy constructors without qualifiers.
9763        // Find a way to initialize values using qualified copy constructors.
9764        static foreach (i; 0 .. Values.length)
9765        {
9766            this.values[i] = unqual(values[i]);
9767        }
9768        this.backIndex = arity;
9769    }
9770
9771    bool empty() @property
9772    {
9773        return frontIndex >= backIndex;
9774    }
9775
9776    CommonType!Values front() @property
9777    {
9778        assert(!empty, "Attempting to fetch the front of an empty Only range");
9779        return this[0];
9780    }
9781
9782    void popFront()
9783    {
9784        assert(!empty, "Attempting to popFront an empty Only range");
9785        ++frontIndex;
9786    }
9787
9788    CommonType!Values back() @property
9789    {
9790        assert(!empty, "Attempting to fetch the back of an empty Only range");
9791        return this[$ - 1];
9792    }
9793
9794    void popBack()
9795    {
9796        assert(!empty, "Attempting to popBack an empty Only range");
9797        --backIndex;
9798    }
9799
9800    OnlyResult save() @property
9801    {
9802        return this;
9803    }
9804
9805    size_t length() const @property
9806    {
9807        return backIndex - frontIndex;
9808    }
9809
9810    alias opDollar = length;
9811
9812    @trusted CommonType!Values opIndex(size_t idx)
9813    {
9814        // when i + idx points to elements popped
9815        // with popBack
9816        assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
9817        final switch (frontIndex + idx)
9818            static foreach (i, T; Values)
9819            case i:
9820                return cast(T) values[i];
9821    }
9822
9823    OnlyResult opSlice()
9824    {
9825        return this;
9826    }
9827
9828    OnlyResult opSlice(size_t from, size_t to)
9829    {
9830        OnlyResult result = this;
9831        result.frontIndex += from;
9832        result.backIndex = this.frontIndex + to;
9833        assert(
9834            from <= to,
9835            "Attempting to slice an Only range with a larger first argument than the second."
9836        );
9837        assert(
9838            to <= length,
9839            "Attempting to slice using an out of bounds index on an Only range"
9840        );
9841        return result;
9842    }
9843
9844    private size_t frontIndex = 0;
9845    private size_t backIndex = 0;
9846
9847    // https://issues.dlang.org/show_bug.cgi?id=10643
9848    version (none)
9849    {
9850        import std.traits : hasElaborateAssign;
9851        static if (hasElaborateAssign!T)
9852            private UnqualValues values;
9853        else
9854            private UnqualValues values = void;
9855    }
9856    else
9857        // These may alias to shared or immutable data. Do not let the user
9858        // to access these directly, and do not allow mutation without checking
9859        // the qualifier.
9860        private UnqualValues values;
9861}
9862
9863// Specialize for single-element results
9864private struct OnlyResult(T)
9865{
9866    @property T front()
9867    {
9868        assert(!empty, "Attempting to fetch the front of an empty Only range");
9869        return fetchFront();
9870    }
9871    @property T back()
9872    {
9873        assert(!empty, "Attempting to fetch the back of an empty Only range");
9874        return fetchFront();
9875    }
9876    @property bool empty() const { return _empty; }
9877    @property size_t length() const { return !_empty; }
9878    @property auto save() { return this; }
9879    void popFront()
9880    {
9881        assert(!_empty, "Attempting to popFront an empty Only range");
9882        _empty = true;
9883    }
9884    void popBack()
9885    {
9886        assert(!_empty, "Attempting to popBack an empty Only range");
9887        _empty = true;
9888    }
9889    alias opDollar = length;
9890
9891    private this()(return scope auto ref T value)
9892    {
9893        ref @trusted unqual(ref T x){return cast() x;}
9894        // TODO: this calls the possible copy constructor without qualifiers.
9895        // Find a way to initialize value using a qualified copy constructor.
9896        this._value = unqual(value);
9897        this._empty = false;
9898    }
9899
9900    T opIndex(size_t i)
9901    {
9902        assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
9903        return fetchFront();
9904    }
9905
9906    OnlyResult opSlice()
9907    {
9908        return this;
9909    }
9910
9911    OnlyResult opSlice(size_t from, size_t to)
9912    {
9913        assert(
9914            from <= to,
9915            "Attempting to slice an Only range with a larger first argument than the second."
9916        );
9917        assert(
9918            to <= length,
9919            "Attempting to slice using an out of bounds index on an Only range"
9920        );
9921        OnlyResult copy = this;
9922        copy._empty = _empty || from == to;
9923        return copy;
9924    }
9925
9926    // This may alias to shared or immutable data. Do not let the user
9927    // to access this directly, and do not allow mutation without checking
9928    // the qualifier.
9929    private Unqual!T _value;
9930    private bool _empty = true;
9931    private @trusted T fetchFront()
9932    {
9933        return *cast(T*)&_value;
9934    }
9935}
9936
9937/**
9938Assemble `values` into a range that carries all its
9939elements in-situ.
9940
9941Useful when a single value or multiple disconnected values
9942must be passed to an algorithm expecting a range, without
9943having to perform dynamic memory allocation.
9944
9945As copying the range means copying all elements, it can be
9946safely returned from functions. For the same reason, copying
9947the returned range may be expensive for a large number of arguments.
9948
9949Params:
9950    values = the values to assemble together
9951
9952Returns:
9953    A `RandomAccessRange` of the assembled values.
9954
9955See_Also: $(LREF chain) to chain ranges
9956 */
9957auto only(Values...)(return scope Values values)
9958if (!is(CommonType!Values == void))
9959{
9960    return OnlyResult!Values(values);
9961}
9962
9963/// ditto
9964auto only()()
9965{
9966    // cannot use noreturn due to issue 22383
9967    struct EmptyElementType {}
9968    EmptyElementType[] result;
9969    return result;
9970}
9971
9972///
9973@safe unittest
9974{
9975    import std.algorithm.comparison : equal;
9976    import std.algorithm.iteration : filter, joiner, map;
9977    import std.algorithm.searching : findSplitBefore;
9978    import std.uni : isUpper;
9979
9980    assert(equal(only('���'), "���"));
9981    assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
9982
9983    assert(only("one", "two", "three").joiner(" ").equal("one two three"));
9984
9985    string title = "The D Programming Language";
9986    assert(title
9987        .filter!isUpper // take the upper case letters
9988        .map!only       // make each letter its own range
9989        .joiner(".")    // join the ranges together lazily
9990        .equal("T.D.P.L"));
9991}
9992
9993// https://issues.dlang.org/show_bug.cgi?id=20314
9994@safe unittest
9995{
9996    import std.algorithm.iteration : joiner;
9997
9998    const string s = "foo", t = "bar";
9999
10000    assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
10001}
10002
10003// Tests the zero-element result
10004@safe unittest
10005{
10006    import std.algorithm.comparison : equal;
10007
10008    auto emptyRange = only();
10009
10010    alias EmptyRange = typeof(emptyRange);
10011    static assert(isInputRange!EmptyRange);
10012    static assert(isForwardRange!EmptyRange);
10013    static assert(isBidirectionalRange!EmptyRange);
10014    static assert(isRandomAccessRange!EmptyRange);
10015    static assert(hasLength!EmptyRange);
10016    static assert(hasSlicing!EmptyRange);
10017
10018    assert(emptyRange.empty);
10019    assert(emptyRange.length == 0);
10020    assert(emptyRange.equal(emptyRange[]));
10021    assert(emptyRange.equal(emptyRange.save));
10022    assert(emptyRange[0 .. 0].equal(emptyRange));
10023}
10024
10025// Tests the single-element result
10026@safe unittest
10027{
10028    import std.algorithm.comparison : equal;
10029    import std.typecons : tuple;
10030    foreach (x; tuple(1, '1', 1.0, "1", [1]))
10031    {
10032        auto a = only(x);
10033        typeof(x)[] e = [];
10034        assert(a.front == x);
10035        assert(a.back == x);
10036        assert(!a.empty);
10037        assert(a.length == 1);
10038        assert(equal(a, a[]));
10039        assert(equal(a, a[0 .. 1]));
10040        assert(equal(a[0 .. 0], e));
10041        assert(equal(a[1 .. 1], e));
10042        assert(a[0] == x);
10043
10044        auto b = a.save;
10045        assert(equal(a, b));
10046        a.popFront();
10047        assert(a.empty && a.length == 0 && a[].empty);
10048        b.popBack();
10049        assert(b.empty && b.length == 0 && b[].empty);
10050
10051        alias A = typeof(a);
10052        static assert(isInputRange!A);
10053        static assert(isForwardRange!A);
10054        static assert(isBidirectionalRange!A);
10055        static assert(isRandomAccessRange!A);
10056        static assert(hasLength!A);
10057        static assert(hasSlicing!A);
10058    }
10059
10060    auto imm = only!(immutable int)(1);
10061    immutable int[] imme = [];
10062    assert(imm.front == 1);
10063    assert(imm.back == 1);
10064    assert(!imm.empty);
10065    assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10066    assert(imm.length == 1);
10067    assert(equal(imm, imm[]));
10068    assert(equal(imm, imm[0 .. 1]));
10069    assert(equal(imm[0 .. 0], imme));
10070    assert(equal(imm[1 .. 1], imme));
10071    assert(imm[0] == 1);
10072}
10073
10074// Tests multiple-element results
10075@safe unittest
10076{
10077    import std.algorithm.comparison : equal;
10078    import std.algorithm.iteration : joiner;
10079    import std.meta : AliasSeq;
10080    static assert(!__traits(compiles, only(1, "1")));
10081
10082    auto nums = only!(byte, uint, long)(1, 2, 3);
10083    static assert(is(ElementType!(typeof(nums)) == long));
10084    assert(nums.length == 3);
10085
10086    foreach (i; 0 .. 3)
10087        assert(nums[i] == i + 1);
10088
10089    auto saved = nums.save;
10090
10091    foreach (i; 1 .. 4)
10092    {
10093        assert(nums.front == nums[0]);
10094        assert(nums.front == i);
10095        nums.popFront();
10096        assert(nums.length == 3 - i);
10097    }
10098
10099    assert(nums.empty);
10100
10101    assert(saved.equal(only(1, 2, 3)));
10102    assert(saved.equal(saved[]));
10103    assert(saved[0 .. 1].equal(only(1)));
10104    assert(saved[0 .. 2].equal(only(1, 2)));
10105    assert(saved[0 .. 3].equal(saved));
10106    assert(saved[1 .. 3].equal(only(2, 3)));
10107    assert(saved[2 .. 3].equal(only(3)));
10108    assert(saved[0 .. 0].empty);
10109    assert(saved[3 .. 3].empty);
10110
10111    alias data = AliasSeq!("one", "two", "three", "four");
10112    static joined =
10113        ["one two", "one two three", "one two three four"];
10114    string[] joinedRange = joined;
10115
10116    static foreach (argCount; 2 .. 5)
10117    {{
10118        auto values = only(data[0 .. argCount]);
10119        alias Values = typeof(values);
10120        static assert(is(ElementType!Values == string));
10121        static assert(isInputRange!Values);
10122        static assert(isForwardRange!Values);
10123        static assert(isBidirectionalRange!Values);
10124        static assert(isRandomAccessRange!Values);
10125        static assert(hasSlicing!Values);
10126        static assert(hasLength!Values);
10127
10128        assert(values.length == argCount);
10129        assert(values[0 .. $].equal(values[0 .. values.length]));
10130        assert(values.joiner(" ").equal(joinedRange.front));
10131        joinedRange.popFront();
10132    }}
10133
10134    assert(saved.retro.equal(only(3, 2, 1)));
10135    assert(saved.length == 3);
10136
10137    assert(saved.back == 3);
10138    saved.popBack();
10139    assert(saved.length == 2);
10140    assert(saved.back == 2);
10141
10142    assert(saved.front == 1);
10143    saved.popFront();
10144    assert(saved.length == 1);
10145    assert(saved.front == 2);
10146
10147    saved.popBack();
10148    assert(saved.empty);
10149
10150    auto imm = only!(immutable int, immutable int)(42, 24);
10151    alias Imm = typeof(imm);
10152    static assert(is(ElementType!Imm == immutable(int)));
10153    assert(!imm.empty);
10154    assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10155    assert(imm.front == 42);
10156    imm.popFront();
10157    assert(imm.front == 24);
10158    imm.popFront();
10159    assert(imm.empty);
10160
10161    static struct Test { int* a; }
10162    immutable(Test) test;
10163    cast(void) only(test, test); // Works with mutable indirection
10164}
10165
10166// https://issues.dlang.org/show_bug.cgi?id=21129
10167@safe unittest
10168{
10169    auto range = () @safe {
10170        const(char)[5] staticStr = "Hello";
10171
10172        // `only` must store a char[5] - not a char[]!
10173        return only(staticStr, " World");
10174    } ();
10175
10176    assert(range.join == "Hello World");
10177}
10178
10179// https://issues.dlang.org/show_bug.cgi?id=21129
10180@safe unittest
10181{
10182    struct AliasedString
10183    {
10184        const(char)[5] staticStr = "Hello";
10185
10186        @property const(char)[] slice() const
10187        {
10188            return staticStr[];
10189        }
10190        alias slice this;
10191    }
10192
10193    auto range = () @safe {
10194        auto hello = AliasedString();
10195
10196        // a copy of AliasedString is stored in the range.
10197        return only(hello, " World");
10198    } ();
10199
10200    assert(range.join == "Hello World");
10201}
10202
10203// https://issues.dlang.org/show_bug.cgi?id=21022
10204@safe pure nothrow unittest
10205{
10206    struct S
10207    {
10208        int* mem;
10209    }
10210
10211    immutable S x;
10212    immutable(S)[] arr;
10213    auto r1 = arr.chain(x.only, only(x, x));
10214}
10215
10216/**
10217Iterate over `range` with an attached index variable.
10218
10219Each element is a $(REF Tuple, std,typecons) containing the index
10220and the element, in that order, where the index member is named `index`
10221and the element member is named `value`.
10222
10223The index starts at `start` and is incremented by one on every iteration.
10224
10225Overflow:
10226    If `range` has length, then it is an error to pass a value for `start`
10227    so that `start + range.length` is bigger than `Enumerator.max`, thus
10228    it is ensured that overflow cannot happen.
10229
10230    If `range` does not have length, and `popFront` is called when
10231    `front.index == Enumerator.max`, the index will overflow and
10232    continue from `Enumerator.min`.
10233
10234Params:
10235    range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
10236    start = the number to start the index counter from
10237
10238Returns:
10239    At minimum, an input range. All other range primitives are given in the
10240    resulting range if `range` has them. The exceptions are the bidirectional
10241    primitives, which are propagated only if `range` has length.
10242
10243Example:
10244Useful for using `foreach` with an index loop variable:
10245----
10246    import std.stdio : stdin, stdout;
10247    import std.range : enumerate;
10248
10249    foreach (lineNum, line; stdin.byLine().enumerate(1))
10250        stdout.writefln("line #%s: %s", lineNum, line);
10251----
10252*/
10253auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
10254if (isIntegral!Enumerator && isInputRange!Range)
10255in
10256{
10257    static if (hasLength!Range)
10258    {
10259        // TODO: core.checkedint supports mixed signedness yet?
10260        import core.checkedint : adds, addu;
10261        import std.conv : ConvException, to;
10262        import std.traits : isSigned, Largest, Signed;
10263
10264        alias LengthType = typeof(range.length);
10265        bool overflow;
10266        static if (isSigned!Enumerator && isSigned!LengthType)
10267            auto result = adds(start, range.length, overflow);
10268        else static if (isSigned!Enumerator)
10269        {
10270            alias signed_t = Largest!(Enumerator, Signed!LengthType);
10271            signed_t signedLength;
10272            //This is to trick the compiler because if length is enum
10273            //the compiler complains about unreachable code.
10274            auto getLength()
10275            {
10276                return range.length;
10277            }
10278            //Can length fit in the signed type
10279            assert(getLength() < signed_t.max,
10280                "a signed length type is required but the range's length() is too great");
10281            signedLength = range.length;
10282            auto result = adds(start, signedLength, overflow);
10283        }
10284        else
10285        {
10286            static if (isSigned!LengthType)
10287                assert(range.length >= 0);
10288            auto result = addu(start, range.length, overflow);
10289        }
10290
10291        assert(!overflow && result <= Enumerator.max);
10292    }
10293}
10294do
10295{
10296    // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
10297    static struct Result
10298    {
10299        import std.typecons : Tuple;
10300
10301        private:
10302        alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
10303        Range range;
10304        Unqual!Enumerator index;
10305
10306        public:
10307        ElemType front() @property
10308        {
10309            assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
10310            return typeof(return)(index, range.front);
10311        }
10312
10313        static if (isInfinite!Range)
10314            enum bool empty = false;
10315        else
10316        {
10317            bool empty() @property
10318            {
10319                return range.empty;
10320            }
10321        }
10322
10323        void popFront()
10324        {
10325            assert(!range.empty, "Attempting to popFront an empty enumerate");
10326            range.popFront();
10327            ++index; // When !hasLength!Range, overflow is expected
10328        }
10329
10330        static if (isForwardRange!Range)
10331        {
10332            Result save() @property
10333            {
10334                return typeof(return)(range.save, index);
10335            }
10336        }
10337
10338        static if (hasLength!Range)
10339        {
10340            mixin ImplementLength!range;
10341
10342            static if (isBidirectionalRange!Range)
10343            {
10344                ElemType back() @property
10345                {
10346                    assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
10347                    return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
10348                }
10349
10350                void popBack()
10351                {
10352                    assert(!range.empty, "Attempting to popBack an empty enumerate");
10353                    range.popBack();
10354                }
10355            }
10356        }
10357
10358        static if (isRandomAccessRange!Range)
10359        {
10360             ElemType opIndex(size_t i)
10361             {
10362                return typeof(return)(cast(Enumerator)(index + i), range[i]);
10363             }
10364        }
10365
10366        static if (hasSlicing!Range)
10367        {
10368            static if (hasLength!Range)
10369            {
10370                Result opSlice(size_t i, size_t j)
10371                {
10372                    return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
10373                }
10374            }
10375            else
10376            {
10377                static struct DollarToken {}
10378                enum opDollar = DollarToken.init;
10379
10380                Result opSlice(size_t i, DollarToken)
10381                {
10382                    return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
10383                }
10384
10385                auto opSlice(size_t i, size_t j)
10386                {
10387                    return this[i .. $].takeExactly(j - 1);
10388                }
10389            }
10390        }
10391    }
10392
10393    return Result(range, start);
10394}
10395
10396/// Can start enumeration from a negative position:
10397pure @safe nothrow unittest
10398{
10399    import std.array : assocArray;
10400    import std.range : enumerate;
10401
10402    bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
10403    assert(aa[-1]);
10404    assert(aa[0]);
10405    assert(aa[1]);
10406}
10407
10408// Make sure passing qualified types works
10409pure @safe nothrow unittest
10410{
10411    char[4] v;
10412    immutable start = 2;
10413    v[2 .. $].enumerate(start);
10414}
10415
10416pure @safe nothrow unittest
10417{
10418    import std.internal.test.dummyrange : AllDummyRanges;
10419    import std.meta : AliasSeq;
10420    import std.typecons : tuple;
10421
10422    static struct HasSlicing
10423    {
10424        typeof(this) front() @property { return typeof(this).init; }
10425        bool empty() @property { return true; }
10426        void popFront() {}
10427
10428        typeof(this) opSlice(size_t, size_t)
10429        {
10430            return typeof(this)();
10431        }
10432    }
10433
10434    static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
10435    {{
10436        alias R = typeof(enumerate(DummyType.init));
10437        static assert(isInputRange!R);
10438        static assert(isForwardRange!R == isForwardRange!DummyType);
10439        static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
10440        static assert(!hasAssignableElements!R);
10441
10442        static if (hasLength!DummyType)
10443        {
10444            static assert(hasLength!R);
10445            static assert(isBidirectionalRange!R ==
10446                isBidirectionalRange!DummyType);
10447        }
10448
10449        static assert(hasSlicing!R == hasSlicing!DummyType);
10450    }}
10451
10452    static immutable values = ["zero", "one", "two", "three"];
10453    auto enumerated = values[].enumerate();
10454    assert(!enumerated.empty);
10455    assert(enumerated.front == tuple(0, "zero"));
10456    assert(enumerated.back == tuple(3, "three"));
10457
10458    typeof(enumerated) saved = enumerated.save;
10459    saved.popFront();
10460    assert(enumerated.front == tuple(0, "zero"));
10461    assert(saved.front == tuple(1, "one"));
10462    assert(saved.length == enumerated.length - 1);
10463    saved.popBack();
10464    assert(enumerated.back == tuple(3, "three"));
10465    assert(saved.back == tuple(2, "two"));
10466    saved.popFront();
10467    assert(saved.front == tuple(2, "two"));
10468    assert(saved.back == tuple(2, "two"));
10469    saved.popFront();
10470    assert(saved.empty);
10471
10472    size_t control = 0;
10473    foreach (i, v; enumerated)
10474    {
10475        static assert(is(typeof(i) == size_t));
10476        static assert(is(typeof(v) == typeof(values[0])));
10477        assert(i == control);
10478        assert(v == values[i]);
10479        assert(tuple(i, v) == enumerated[i]);
10480        ++control;
10481    }
10482
10483    assert(enumerated[0 .. $].front == tuple(0, "zero"));
10484    assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
10485
10486    foreach (i; 0 .. 10)
10487    {
10488        auto shifted = values[0 .. 2].enumerate(i);
10489        assert(shifted.front == tuple(i, "zero"));
10490        assert(shifted[0] == shifted.front);
10491
10492        auto next = tuple(i + 1, "one");
10493        assert(shifted[1] == next);
10494        shifted.popFront();
10495        assert(shifted.front == next);
10496        shifted.popFront();
10497        assert(shifted.empty);
10498    }
10499
10500    static foreach (T; AliasSeq!(ubyte, byte, uint, int))
10501    {{
10502        auto inf = 42.repeat().enumerate(T.max);
10503        alias Inf = typeof(inf);
10504        static assert(isInfinite!Inf);
10505        static assert(hasSlicing!Inf);
10506
10507        // test overflow
10508        assert(inf.front == tuple(T.max, 42));
10509        inf.popFront();
10510        assert(inf.front == tuple(T.min, 42));
10511
10512        // test slicing
10513        inf = inf[42 .. $];
10514        assert(inf.front == tuple(T.min + 42, 42));
10515        auto window = inf[0 .. 2];
10516        assert(window.length == 1);
10517        assert(window.front == inf.front);
10518        window.popFront();
10519        assert(window.empty);
10520    }}
10521}
10522
10523pure @safe unittest
10524{
10525    import std.algorithm.comparison : equal;
10526    import std.meta : AliasSeq;
10527    static immutable int[] values = [0, 1, 2, 3, 4];
10528    static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
10529    {{
10530        auto enumerated = values.enumerate!T();
10531        static assert(is(typeof(enumerated.front.index) == T));
10532        assert(enumerated.equal(values[].zip(values)));
10533
10534        foreach (T i; 0 .. 5)
10535        {
10536            auto subset = values[cast(size_t) i .. $];
10537            auto offsetEnumerated = subset.enumerate(i);
10538            static assert(is(typeof(enumerated.front.index) == T));
10539            assert(offsetEnumerated.equal(subset.zip(subset)));
10540        }
10541    }}
10542}
10543@nogc @safe unittest
10544{
10545   const val = iota(1, 100).enumerate(1);
10546}
10547@nogc @safe unittest
10548{
10549    import core.exception : AssertError;
10550    import std.exception : assertThrown;
10551    struct RangePayload {
10552        enum length = size_t.max;
10553        void popFront() {}
10554        int front() { return 0; }
10555        bool empty() { return true; }
10556    }
10557    RangePayload thePayload;
10558    //Assertion won't happen when contracts are disabled for -release.
10559    debug assertThrown!AssertError(enumerate(thePayload, -10));
10560}
10561// https://issues.dlang.org/show_bug.cgi?id=10939
10562version (none)
10563{
10564    // Re-enable (or remove) if 10939 is resolved.
10565    /+pure+/ @safe unittest // Impure because of std.conv.to
10566    {
10567        import core.exception : RangeError;
10568        import std.exception : assertNotThrown, assertThrown;
10569        import std.meta : AliasSeq;
10570
10571        static immutable values = [42];
10572
10573        static struct SignedLengthRange
10574        {
10575            immutable(int)[] _values = values;
10576
10577            int front() @property { assert(false); }
10578            bool empty() @property { assert(false); }
10579            void popFront() { assert(false); }
10580
10581            int length() @property
10582            {
10583                return cast(int)_values.length;
10584            }
10585        }
10586
10587        SignedLengthRange svalues;
10588        static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
10589        {
10590            assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
10591            assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
10592            assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
10593
10594            assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
10595            assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
10596            assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
10597        }
10598
10599        static foreach (Enumerator; AliasSeq!(byte, short, int))
10600        {
10601            assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
10602        }
10603
10604        assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
10605    }
10606}
10607
10608/**
10609  Returns true if `fn` accepts variables of type T1 and T2 in any order.
10610  The following code should compile:
10611  ---
10612  (ref T1 a, ref T2 b)
10613  {
10614    fn(a, b);
10615    fn(b, a);
10616  }
10617  ---
10618*/
10619template isTwoWayCompatible(alias fn, T1, T2)
10620{
10621    enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
10622        {
10623            cast(void) fn(a, b);
10624            cast(void) fn(b, a);
10625        }
10626    ));
10627}
10628
10629///
10630@safe unittest
10631{
10632    void func1(int a, int b);
10633    void func2(int a, float b);
10634
10635    static assert(isTwoWayCompatible!(func1, int, int));
10636    static assert(isTwoWayCompatible!(func1, short, int));
10637    static assert(!isTwoWayCompatible!(func2, int, float));
10638
10639    void func3(ref int a, ref int b);
10640    static assert( isTwoWayCompatible!(func3, int, int));
10641    static assert(!isTwoWayCompatible!(func3, short, int));
10642}
10643
10644
10645/**
10646   Policy used with the searching primitives `lowerBound`, $(D
10647   upperBound), and `equalRange` of $(LREF SortedRange) below.
10648 */
10649enum SearchPolicy
10650{
10651    /**
10652       Searches in a linear fashion.
10653    */
10654    linear,
10655
10656    /**
10657       Searches with a step that is grows linearly (1, 2, 3,...)
10658       leading to a quadratic search schedule (indexes tried are 0, 1,
10659       3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
10660       the remaining interval is searched using binary search. The
10661       search is completed in $(BIGOH sqrt(n)) time. Use it when you
10662       are reasonably confident that the value is around the beginning
10663       of the range.
10664    */
10665    trot,
10666
10667    /**
10668       Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
10669       galloping search algorithm), i.e. searches
10670       with a step that doubles every time, (1, 2, 4, 8, ...)  leading
10671       to an exponential search schedule (indexes tried are 0, 1, 3,
10672       7, 15, 31, 63,...) Once the search overshoots its target, the
10673       remaining interval is searched using binary search. A value is
10674       found in $(BIGOH log(n)) time.
10675    */
10676    gallop,
10677
10678    /**
10679       Searches using a classic interval halving policy. The search
10680       starts in the middle of the range, and each search step cuts
10681       the range in half. This policy finds a value in $(BIGOH log(n))
10682       time but is less cache friendly than `gallop` for large
10683       ranges. The `binarySearch` policy is used as the last step
10684       of `trot`, `gallop`, `trotBackwards`, and $(D
10685       gallopBackwards) strategies.
10686    */
10687    binarySearch,
10688
10689    /**
10690       Similar to `trot` but starts backwards. Use it when
10691       confident that the value is around the end of the range.
10692    */
10693    trotBackwards,
10694
10695    /**
10696       Similar to `gallop` but starts backwards. Use it when
10697       confident that the value is around the end of the range.
10698    */
10699    gallopBackwards
10700}
10701
10702///
10703@safe unittest
10704{
10705    import std.algorithm.comparison : equal;
10706
10707    auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
10708    auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
10709    assert(p1.equal([4, 5, 6, 7, 8, 9]));
10710
10711    auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
10712    assert(p2.equal([0, 1, 2, 3]));
10713}
10714
10715/**
10716   Options for $(LREF SortedRange) ranges (below).
10717*/
10718enum SortedRangeOptions
10719{
10720   /**
10721      Assume, that the range is sorted without checking.
10722   */
10723   assumeSorted,
10724
10725   /**
10726      All elements of the range are checked to be sorted.
10727      The check is performed in O(n) time.
10728   */
10729   checkStrictly,
10730
10731   /**
10732      Some elements of the range are checked to be sorted.
10733      For ranges with random order, this will almost surely
10734      detect, that it is not sorted. For almost sorted ranges
10735      it's more likely to fail. The checked elements are choosen
10736      in a deterministic manner, which makes this check reproducable.
10737      The check is performed in O(log(n)) time.
10738   */
10739   checkRoughly,
10740}
10741
10742///
10743@safe pure unittest
10744{
10745    // create a SortedRange, that's checked strictly
10746    SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
10747}
10748
10749/**
10750   Represents a sorted range. In addition to the regular range
10751   primitives, supports additional operations that take advantage of the
10752   ordering, such as merge and binary search. To obtain a $(D
10753   SortedRange) from an unsorted range `r`, use
10754   $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
10755   corresponding `SortedRange`. To construct a `SortedRange` from a range
10756   `r` that is known to be already sorted, use $(LREF assumeSorted).
10757
10758   Params:
10759       pred: The predicate used to define the sortedness
10760       opt: Controls how strongly the range is checked for sortedness.
10761            Will only be used for `RandomAccessRanges`.
10762            Will not be used in CTFE.
10763*/
10764struct SortedRange(Range, alias pred = "a < b",
10765    SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
10766if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
10767{
10768    import std.functional : binaryFun;
10769
10770    private alias predFun = binaryFun!pred;
10771    private bool geq(L, R)(L lhs, R rhs)
10772    {
10773        return !predFun(lhs, rhs);
10774    }
10775    private bool gt(L, R)(L lhs, R rhs)
10776    {
10777        return predFun(rhs, lhs);
10778    }
10779    private Range _input;
10780
10781    // Undocummented because a clearer way to invoke is by calling
10782    // assumeSorted.
10783    this(Range input)
10784    {
10785        static if (opt == SortedRangeOptions.checkRoughly)
10786        {
10787            roughlyVerifySorted(input);
10788        }
10789        static if (opt == SortedRangeOptions.checkStrictly)
10790        {
10791            strictlyVerifySorted(input);
10792        }
10793        this._input = input;
10794    }
10795
10796    // Assertion only.
10797    static if (opt == SortedRangeOptions.checkRoughly)
10798    private void roughlyVerifySorted(Range r)
10799    {
10800        if (!__ctfe)
10801        {
10802            static if (isRandomAccessRange!Range && hasLength!Range)
10803            {
10804                import core.bitop : bsr;
10805                import std.algorithm.sorting : isSorted;
10806                import std.exception : enforce;
10807
10808                // Check the sortedness of the input
10809                if (r.length < 2) return;
10810
10811                immutable size_t msb = bsr(r.length) + 1;
10812                assert(msb > 0 && msb <= r.length);
10813                immutable step = r.length / msb;
10814                auto st = stride(r, step);
10815
10816                enforce(isSorted!pred(st), "Range is not sorted");
10817            }
10818        }
10819    }
10820
10821    // Assertion only.
10822    static if (opt == SortedRangeOptions.checkStrictly)
10823    private void strictlyVerifySorted(Range r)
10824    {
10825        if (!__ctfe)
10826        {
10827            static if (isRandomAccessRange!Range && hasLength!Range)
10828            {
10829                import std.algorithm.sorting : isSorted;
10830                import std.exception : enforce;
10831
10832                enforce(isSorted!pred(r), "Range is not sorted");
10833            }
10834        }
10835    }
10836
10837    /// Range primitives.
10838    @property bool empty()             //const
10839    {
10840        return this._input.empty;
10841    }
10842
10843    /// Ditto
10844    static if (isForwardRange!Range)
10845    @property auto save()
10846    {
10847        // Avoid the constructor
10848        typeof(this) result = this;
10849        result._input = _input.save;
10850        return result;
10851    }
10852
10853    /// Ditto
10854    @property auto ref front()
10855    {
10856        return _input.front;
10857    }
10858
10859    /// Ditto
10860    void popFront()
10861    {
10862        _input.popFront();
10863    }
10864
10865    /// Ditto
10866    static if (isBidirectionalRange!Range)
10867    {
10868        @property auto ref back()
10869        {
10870            return _input.back;
10871        }
10872
10873        /// Ditto
10874        void popBack()
10875        {
10876            _input.popBack();
10877        }
10878    }
10879
10880    /// Ditto
10881    static if (isRandomAccessRange!Range)
10882        auto ref opIndex(size_t i)
10883        {
10884            return _input[i];
10885        }
10886
10887    /// Ditto
10888    static if (hasSlicing!Range)
10889        auto opSlice(size_t a, size_t b) return scope
10890        {
10891            assert(
10892                a <= b,
10893                "Attempting to slice a SortedRange with a larger first argument than the second."
10894            );
10895            typeof(this) result = this;
10896            result._input = _input[a .. b];// skip checking
10897            return result;
10898        }
10899
10900    mixin ImplementLength!_input;
10901
10902/**
10903    Releases the controlled range and returns it.
10904
10905    This does the opposite of $(LREF assumeSorted): instead of turning a range
10906    into a `SortedRange`, it extracts the original range back out of the `SortedRange`
10907    using $(REF, move, std,algorithm,mutation).
10908*/
10909    auto release() return scope
10910    {
10911        import std.algorithm.mutation : move;
10912        return move(_input);
10913    }
10914
10915    ///
10916    static if (is(Range : int[]))
10917    @safe unittest
10918    {
10919        import std.algorithm.sorting : sort;
10920        int[3] data = [ 1, 2, 3 ];
10921        auto a = assumeSorted(data[]);
10922        assert(a == sort!"a < b"(data[]));
10923        int[] p = a.release();
10924        assert(p == [ 1, 2, 3 ]);
10925    }
10926
10927    // Assuming a predicate "test" that returns 0 for a left portion
10928    // of the range and then 1 for the rest, returns the index at
10929    // which the first 1 appears. Used internally by the search routines.
10930    private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
10931    if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
10932    {
10933        size_t first = 0, count = _input.length;
10934        while (count > 0)
10935        {
10936            immutable step = count / 2, it = first + step;
10937            if (!test(_input[it], v))
10938            {
10939                first = it + 1;
10940                count -= step + 1;
10941            }
10942            else
10943            {
10944                count = step;
10945            }
10946        }
10947        return first;
10948    }
10949
10950    // Specialization for trot and gallop
10951    private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
10952    if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
10953        && isRandomAccessRange!Range)
10954    {
10955        if (empty || test(front, v)) return 0;
10956        immutable count = length;
10957        if (count == 1) return 1;
10958        size_t below = 0, above = 1, step = 2;
10959        while (!test(_input[above], v))
10960        {
10961            // Still too small, update below and increase gait
10962            below = above;
10963            immutable next = above + step;
10964            if (next >= count)
10965            {
10966                // Overshot - the next step took us beyond the end. So
10967                // now adjust next and simply exit the loop to do the
10968                // binary search thingie.
10969                above = count;
10970                break;
10971            }
10972            // Still in business, increase step and continue
10973            above = next;
10974            static if (sp == SearchPolicy.trot)
10975                ++step;
10976            else
10977                step <<= 1;
10978        }
10979        return below + this[below .. above].getTransitionIndex!(
10980            SearchPolicy.binarySearch, test, V)(v);
10981    }
10982
10983    // Specialization for trotBackwards and gallopBackwards
10984    private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
10985    if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
10986        && isRandomAccessRange!Range)
10987    {
10988        immutable count = length;
10989        if (empty || !test(back, v)) return count;
10990        if (count == 1) return 0;
10991        size_t below = count - 2, above = count - 1, step = 2;
10992        while (test(_input[below], v))
10993        {
10994            // Still too large, update above and increase gait
10995            above = below;
10996            if (below < step)
10997            {
10998                // Overshot - the next step took us beyond the end. So
10999                // now adjust next and simply fall through to do the
11000                // binary search thingie.
11001                below = 0;
11002                break;
11003            }
11004            // Still in business, increase step and continue
11005            below -= step;
11006            static if (sp == SearchPolicy.trot)
11007                ++step;
11008            else
11009                step <<= 1;
11010        }
11011        return below + this[below .. above].getTransitionIndex!(
11012            SearchPolicy.binarySearch, test, V)(v);
11013    }
11014
11015// lowerBound
11016/**
11017   This function uses a search with policy `sp` to find the
11018   largest left subrange on which $(D pred(x, value)) is `true` for
11019   all `x` (e.g., if `pred` is "less than", returns the portion of
11020   the range with elements strictly smaller than `value`). The search
11021   schedule and its complexity are documented in
11022   $(LREF SearchPolicy).
11023*/
11024    auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11025    if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11026         && hasSlicing!Range)
11027    {
11028        return this[0 .. getTransitionIndex!(sp, geq)(value)];
11029    }
11030
11031    ///
11032    static if (is(Range : int[]))
11033    @safe unittest
11034    {
11035        import std.algorithm.comparison : equal;
11036        auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
11037        auto p = a.lowerBound(4);
11038        assert(equal(p, [ 0, 1, 2, 3 ]));
11039    }
11040
11041// upperBound
11042/**
11043This function searches with policy `sp` to find the largest right
11044subrange on which $(D pred(value, x)) is `true` for all `x`
11045(e.g., if `pred` is "less than", returns the portion of the range
11046with elements strictly greater than `value`). The search schedule
11047and its complexity are documented in $(LREF SearchPolicy).
11048
11049For ranges that do not offer random access, `SearchPolicy.linear`
11050is the only policy allowed (and it must be specified explicitly lest it exposes
11051user code to unexpected inefficiencies). For random-access searches, all
11052policies are allowed, and `SearchPolicy.binarySearch` is the default.
11053*/
11054    auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11055    if (isTwoWayCompatible!(predFun, ElementType!Range, V))
11056    {
11057        static assert(hasSlicing!Range || sp == SearchPolicy.linear,
11058            "Specify SearchPolicy.linear explicitly for "
11059            ~ typeof(this).stringof);
11060        static if (sp == SearchPolicy.linear)
11061        {
11062            for (; !_input.empty && !predFun(value, _input.front);
11063                 _input.popFront())
11064            {
11065            }
11066            return this;
11067        }
11068        else
11069        {
11070            return this[getTransitionIndex!(sp, gt)(value) .. length];
11071        }
11072    }
11073
11074    ///
11075    static if (is(Range : int[]))
11076    @safe unittest
11077    {
11078        import std.algorithm.comparison : equal;
11079        auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
11080        auto p = a.upperBound(3);
11081        assert(equal(p, [4, 4, 5, 6]));
11082    }
11083
11084
11085// equalRange
11086/**
11087   Returns the subrange containing all elements `e` for which both $(D
11088   pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11089   if `pred` is "less than", returns the portion of the range with
11090   elements equal to `value`). Uses a classic binary search with
11091   interval halving until it finds a value that satisfies the condition,
11092   then uses `SearchPolicy.gallopBackwards` to find the left boundary
11093   and `SearchPolicy.gallop` to find the right boundary. These
11094   policies are justified by the fact that the two boundaries are likely
11095   to be near the first found value (i.e., equal ranges are relatively
11096   small). Completes the entire search in $(BIGOH log(n)) time.
11097*/
11098    auto equalRange(V)(V value)
11099    if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11100        && isRandomAccessRange!Range)
11101    {
11102        size_t first = 0, count = _input.length;
11103        while (count > 0)
11104        {
11105            immutable step = count / 2;
11106            auto it = first + step;
11107            if (predFun(_input[it], value))
11108            {
11109                // Less than value, bump left bound up
11110                first = it + 1;
11111                count -= step + 1;
11112            }
11113            else if (predFun(value, _input[it]))
11114            {
11115                // Greater than value, chop count
11116                count = step;
11117            }
11118            else
11119            {
11120                // Equal to value, do binary searches in the
11121                // leftover portions
11122                // Gallop towards the left end as it's likely nearby
11123                immutable left = first
11124                    + this[first .. it]
11125                    .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11126                first += count;
11127                // Gallop towards the right end as it's likely nearby
11128                immutable right = first
11129                    - this[it + 1 .. first]
11130                    .upperBound!(SearchPolicy.gallop)(value).length;
11131                return this[left .. right];
11132            }
11133        }
11134        return this.init;
11135    }
11136
11137    ///
11138    static if (is(Range : int[]))
11139    @safe unittest
11140    {
11141        import std.algorithm.comparison : equal;
11142        auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11143        auto r = a.assumeSorted.equalRange(3);
11144        assert(equal(r, [ 3, 3, 3 ]));
11145    }
11146
11147// trisect
11148/**
11149Returns a tuple `r` such that `r[0]` is the same as the result
11150of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11151equalRange(value)), and `r[2]` is the same as the result of $(D
11152upperBound(value)). The call is faster than computing all three
11153separately. Uses a search schedule similar to $(D
11154equalRange). Completes the entire search in $(BIGOH log(n)) time.
11155*/
11156    auto trisect(V)(V value)
11157    if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11158        && isRandomAccessRange!Range && hasLength!Range)
11159    {
11160        import std.typecons : tuple;
11161        size_t first = 0, count = _input.length;
11162        while (count > 0)
11163        {
11164            immutable step = count / 2;
11165            auto it = first + step;
11166            if (predFun(_input[it], value))
11167            {
11168                // Less than value, bump left bound up
11169                first = it + 1;
11170                count -= step + 1;
11171            }
11172            else if (predFun(value, _input[it]))
11173            {
11174                // Greater than value, chop count
11175                count = step;
11176            }
11177            else
11178            {
11179                // Equal to value, do binary searches in the
11180                // leftover portions
11181                // Gallop towards the left end as it's likely nearby
11182                immutable left = first
11183                    + this[first .. it]
11184                    .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11185                first += count;
11186                // Gallop towards the right end as it's likely nearby
11187                immutable right = first
11188                    - this[it + 1 .. first]
11189                    .upperBound!(SearchPolicy.gallop)(value).length;
11190                return tuple(this[0 .. left], this[left .. right],
11191                        this[right .. length]);
11192            }
11193        }
11194        // No equal element was found
11195        return tuple(this[0 .. first], this.init, this[first .. length]);
11196    }
11197
11198    ///
11199    static if (is(Range : int[]))
11200    @safe unittest
11201    {
11202        import std.algorithm.comparison : equal;
11203        auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11204        auto r = assumeSorted(a).trisect(3);
11205        assert(equal(r[0], [ 1, 2 ]));
11206        assert(equal(r[1], [ 3, 3, 3 ]));
11207        assert(equal(r[2], [ 4, 4, 5, 6 ]));
11208    }
11209
11210// contains
11211/**
11212Returns `true` if and only if `value` can be found in $(D
11213range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
11214evaluations of `pred`.
11215 */
11216
11217    bool contains(V)(V value)
11218    if (isRandomAccessRange!Range)
11219    {
11220        if (empty) return false;
11221        immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
11222        if (i >= length) return false;
11223        return !predFun(value, _input[i]);
11224    }
11225
11226/**
11227Like `contains`, but the value is specified before the range.
11228*/
11229    bool opBinaryRight(string op, V)(V value)
11230    if (op == "in" && isRandomAccessRange!Range)
11231    {
11232        return contains(value);
11233    }
11234
11235// groupBy
11236/**
11237Returns a range of subranges of elements that are equivalent according to the
11238sorting relation.
11239 */
11240    auto groupBy()()
11241    {
11242        import std.algorithm.iteration : chunkBy;
11243        return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
11244    }
11245}
11246
11247/// ditto
11248template SortedRange(Range, alias pred = "a < b",
11249                     SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11250if (isInstanceOf!(SortedRange, Range))
11251{
11252    // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
11253    alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
11254}
11255
11256///
11257@safe unittest
11258{
11259    import std.algorithm.sorting : sort;
11260    auto a = [ 1, 2, 3, 42, 52, 64 ];
11261    auto r = assumeSorted(a);
11262    assert(r.contains(3));
11263    assert(!(32 in r));
11264    auto r1 = sort!"a > b"(a);
11265    assert(3 in r1);
11266    assert(!r1.contains(32));
11267    assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
11268}
11269
11270/**
11271`SortedRange` could accept ranges weaker than random-access, but it
11272is unable to provide interesting functionality for them. Therefore,
11273`SortedRange` is currently restricted to random-access ranges.
11274
11275No copy of the original range is ever made. If the underlying range is
11276changed concurrently with its corresponding `SortedRange` in ways
11277that break its sorted-ness, `SortedRange` will work erratically.
11278*/
11279@safe unittest
11280{
11281    import std.algorithm.mutation : swap;
11282    auto a = [ 1, 2, 3, 42, 52, 64 ];
11283    auto r = assumeSorted(a);
11284    assert(r.contains(42));
11285    swap(a[3], a[5]);         // illegal to break sortedness of original range
11286    assert(!r.contains(42));  // passes although it shouldn't
11287}
11288
11289/**
11290`SortedRange` can be searched with predicates that do not take
11291two elements of the underlying range as arguments.
11292
11293This is useful, if a range of structs is sorted by a member and you
11294want to search in that range by only providing a value for that member.
11295
11296*/
11297@safe unittest
11298{
11299    import std.algorithm.comparison : equal;
11300    static struct S { int i; }
11301    static bool byI(A, B)(A a, B b)
11302    {
11303        static if (is(A == S))
11304            return a.i < b;
11305        else
11306            return a < b.i;
11307    }
11308    auto r = assumeSorted!byI([S(1), S(2), S(3)]);
11309    auto lessThanTwo = r.lowerBound(2);
11310    assert(equal(lessThanTwo, [S(1)]));
11311}
11312
11313@safe unittest
11314{
11315    import std.exception : assertThrown, assertNotThrown;
11316
11317    assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
11318    assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
11319
11320    // these two checks are implementation depended
11321    assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
11322    assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
11323}
11324
11325@safe unittest
11326{
11327    import std.algorithm.comparison : equal;
11328
11329    auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
11330    auto r = assumeSorted(a).trisect(30);
11331    assert(equal(r[0], [ 10, 20 ]));
11332    assert(equal(r[1], [ 30, 30, 30 ]));
11333    assert(equal(r[2], [ 40, 40, 50, 60 ]));
11334
11335    r = assumeSorted(a).trisect(35);
11336    assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
11337    assert(r[1].empty);
11338    assert(equal(r[2], [ 40, 40, 50, 60 ]));
11339}
11340
11341@safe unittest
11342{
11343    import std.algorithm.comparison : equal;
11344    auto a = [ "A", "AG", "B", "E", "F" ];
11345    auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
11346    assert(equal(r[0], [ "A", "AG" ]));
11347    assert(equal(r[1], [ "B" ]));
11348    assert(equal(r[2], [ "E", "F" ]));
11349    r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
11350    assert(r[0].empty);
11351    assert(equal(r[1], [ "A" ]));
11352    assert(equal(r[2], [ "AG", "B", "E", "F" ]));
11353}
11354
11355@safe unittest
11356{
11357    import std.algorithm.comparison : equal;
11358    static void test(SearchPolicy pol)()
11359    {
11360        auto a = [ 1, 2, 3, 42, 52, 64 ];
11361        auto r = assumeSorted(a);
11362        assert(equal(r.lowerBound(42), [1, 2, 3]));
11363
11364        assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
11365        assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
11366        assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
11367        assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
11368        assert(equal(r.lowerBound!(pol)(3), [1, 2]));
11369        assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
11370        assert(equal(r.lowerBound!(pol)(420), a));
11371        assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
11372
11373        assert(equal(r.upperBound!(pol)(42), [52, 64]));
11374        assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
11375        assert(equal(r.upperBound!(pol)(43), [52, 64]));
11376        assert(equal(r.upperBound!(pol)(51), [52, 64]));
11377        assert(equal(r.upperBound!(pol)(53), [64]));
11378        assert(equal(r.upperBound!(pol)(55), [64]));
11379        assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
11380        assert(equal(r.upperBound!(pol)(0), a));
11381    }
11382
11383    test!(SearchPolicy.trot)();
11384    test!(SearchPolicy.gallop)();
11385    test!(SearchPolicy.trotBackwards)();
11386    test!(SearchPolicy.gallopBackwards)();
11387    test!(SearchPolicy.binarySearch)();
11388}
11389
11390@safe unittest
11391{
11392    // Check for small arrays
11393    int[] a;
11394    auto r = assumeSorted(a);
11395    a = [ 1 ];
11396    r = assumeSorted(a);
11397    a = [ 1, 2 ];
11398    r = assumeSorted(a);
11399    a = [ 1, 2, 3 ];
11400    r = assumeSorted(a);
11401}
11402
11403@safe unittest
11404{
11405    import std.algorithm.mutation : swap;
11406    auto a = [ 1, 2, 3, 42, 52, 64 ];
11407    auto r = assumeSorted(a);
11408    assert(r.contains(42));
11409    swap(a[3], a[5]);                  // illegal to break sortedness of original range
11410    assert(!r.contains(42));            // passes although it shouldn't
11411}
11412
11413@betterC @nogc nothrow @safe unittest
11414{
11415    static immutable(int)[] arr = [ 1, 2, 3 ];
11416    auto s = assumeSorted(arr);
11417}
11418
11419@system unittest
11420{
11421    import std.algorithm.comparison : equal;
11422    int[] arr = [100, 101, 102, 200, 201, 300];
11423    auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
11424    assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
11425}
11426
11427// Test on an input range
11428@system unittest
11429{
11430    import std.conv : text;
11431    import std.file : exists, remove, tempDir;
11432    import std.path : buildPath;
11433    import std.stdio : File;
11434    import std.uuid : randomUUID;
11435    auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
11436                          "." ~ randomUUID().toString());
11437    auto f = File(name, "w");
11438    scope(exit) if (exists(name)) remove(name);
11439    // write a sorted range of lines to the file
11440    f.write("abc\ndef\nghi\njkl");
11441    f.close();
11442    f.open(name, "r");
11443    auto r = assumeSorted(f.byLine());
11444    auto r1 = r.upperBound!(SearchPolicy.linear)("def");
11445    assert(r1.front == "ghi", r1.front);
11446    f.close();
11447}
11448
11449// https://issues.dlang.org/show_bug.cgi?id=19337
11450@safe unittest
11451{
11452    import std.algorithm.sorting : sort;
11453    auto a = [ 1, 2, 3, 42, 52, 64 ];
11454    a.sort.sort!"a > b";
11455}
11456
11457/**
11458Assumes `r` is sorted by predicate `pred` and returns the
11459corresponding $(D SortedRange!(pred, R)) having `r` as support.
11460To check for sorted-ness at
11461cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
11462 */
11463auto assumeSorted(alias pred = "a < b", R)(R r)
11464if (isInputRange!(Unqual!R))
11465{
11466    // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
11467    static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
11468    {
11469        static if (isInputRange!R && __traits(isSame, pred, RPred))
11470            // If the predicate is the same and we don't need to cast away
11471            // constness for the result to be an input range.
11472            return r;
11473        else
11474            return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
11475    }
11476    else
11477    {
11478        return SortedRange!(Unqual!R, pred)(r);
11479    }
11480}
11481
11482///
11483@safe unittest
11484{
11485    import std.algorithm.comparison : equal;
11486
11487    int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
11488    auto p = assumeSorted(a);
11489
11490    assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
11491    assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
11492    assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
11493    assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
11494}
11495
11496@safe unittest
11497{
11498    import std.algorithm.comparison : equal;
11499    static assert(isRandomAccessRange!(SortedRange!(int[])));
11500    int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11501    auto p = assumeSorted(a).upperBound(3);
11502    assert(equal(p, [4, 4, 5, 6 ]));
11503    p = assumeSorted(a).upperBound(4.2);
11504    assert(equal(p, [ 5, 6 ]));
11505
11506    // https://issues.dlang.org/show_bug.cgi?id=18933
11507    // don't create senselessly nested SortedRange types.
11508    assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
11509    assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
11510}
11511
11512@safe unittest
11513{
11514    import std.algorithm.comparison : equal;
11515    import std.conv : text;
11516
11517    int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11518    auto p = assumeSorted(a).equalRange(3);
11519    assert(equal(p, [ 3, 3, 3 ]), text(p));
11520    p = assumeSorted(a).equalRange(4);
11521    assert(equal(p, [ 4, 4 ]), text(p));
11522    p = assumeSorted(a).equalRange(2);
11523    assert(equal(p, [ 2 ]));
11524    p = assumeSorted(a).equalRange(0);
11525    assert(p.empty);
11526    p = assumeSorted(a).equalRange(7);
11527    assert(p.empty);
11528    p = assumeSorted(a).equalRange(3.0);
11529    assert(equal(p, [ 3, 3, 3]));
11530}
11531
11532@safe unittest
11533{
11534    int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11535    if (a.length)
11536    {
11537        auto b = a[a.length / 2];
11538        //auto r = sort(a);
11539        //assert(r.contains(b));
11540    }
11541}
11542
11543@safe unittest
11544{
11545    auto a = [ 5, 7, 34, 345, 677 ];
11546    auto r = assumeSorted(a);
11547    a = null;
11548    r = assumeSorted(a);
11549    a = [ 1 ];
11550    r = assumeSorted(a);
11551}
11552
11553// https://issues.dlang.org/show_bug.cgi?id=15003
11554@nogc @safe unittest
11555{
11556    static immutable a = [1, 2, 3, 4];
11557    auto r = a.assumeSorted;
11558}
11559
11560/++
11561    Wrapper which effectively makes it possible to pass a range by reference.
11562    Both the original range and the RefRange will always have the exact same
11563    elements. Any operation done on one will affect the other. So, for instance,
11564    if it's passed to a function which would implicitly copy the original range
11565    if it were passed to it, the original range is $(I not) copied but is
11566    consumed as if it were a reference type.
11567
11568    Note:
11569        `save` works as normal and operates on a new range, so if
11570        `save` is ever called on the `RefRange`, then no operations on the
11571        saved range will affect the original.
11572
11573    Params:
11574        range = the range to construct the `RefRange` from
11575
11576    Returns:
11577        A `RefRange`. If the given range is a class type
11578        (and thus is already a reference type), then the original
11579        range is returned rather than a `RefRange`.
11580  +/
11581struct RefRange(R)
11582if (isInputRange!R)
11583{
11584public:
11585
11586    /++ +/
11587    this(R* range) @safe pure nothrow
11588    {
11589        _range = range;
11590    }
11591
11592
11593    /++
11594        This does not assign the pointer of `rhs` to this `RefRange`.
11595        Rather it assigns the range pointed to by `rhs` to the range pointed
11596        to by this `RefRange`. This is because $(I any) operation on a
11597        `RefRange` is the same is if it occurred to the original range. The
11598        one exception is when a `RefRange` is assigned `null` either
11599        directly or because `rhs` is `null`. In that case, `RefRange`
11600        no longer refers to the original range but is `null`.
11601      +/
11602    auto opAssign(RefRange rhs)
11603    {
11604        if (_range && rhs._range)
11605            *_range = *rhs._range;
11606        else
11607            _range = rhs._range;
11608
11609        return this;
11610    }
11611
11612    /++ +/
11613    void opAssign(typeof(null) rhs)
11614    {
11615        _range = null;
11616    }
11617
11618
11619    /++
11620        A pointer to the wrapped range.
11621      +/
11622    @property inout(R*) ptr() @safe inout pure nothrow
11623    {
11624        return _range;
11625    }
11626
11627
11628    version (StdDdoc)
11629    {
11630        /++ +/
11631        @property auto front() {assert(0);}
11632        /++ Ditto +/
11633        @property auto front() const {assert(0);}
11634        /++ Ditto +/
11635        @property auto front(ElementType!R value) {assert(0);}
11636    }
11637    else
11638    {
11639        @property auto front()
11640        {
11641            return (*_range).front;
11642        }
11643
11644        static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
11645        {
11646            return (*_range).front;
11647        }
11648
11649        static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
11650        {
11651            return (*_range).front = value;
11652        }
11653    }
11654
11655
11656    version (StdDdoc)
11657    {
11658        @property bool empty(); ///
11659        @property bool empty() const; ///Ditto
11660    }
11661    else static if (isInfinite!R)
11662        enum empty = false;
11663    else
11664    {
11665        @property bool empty()
11666        {
11667            return (*_range).empty;
11668        }
11669
11670        static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
11671        {
11672            return (*_range).empty;
11673        }
11674    }
11675
11676
11677    /++ +/
11678    void popFront()
11679    {
11680        return (*_range).popFront();
11681    }
11682
11683
11684    version (StdDdoc)
11685    {
11686        /++
11687            Only defined if `isForwardRange!R` is `true`.
11688          +/
11689        @property auto save() {assert(0);}
11690        /++ Ditto +/
11691        @property auto save() const {assert(0);}
11692        /++ Ditto +/
11693        auto opSlice() {assert(0);}
11694        /++ Ditto +/
11695        auto opSlice() const {assert(0);}
11696    }
11697    else static if (isForwardRange!R)
11698    {
11699        import std.traits : isSafe;
11700        private alias S = typeof((*_range).save);
11701
11702        static if (is(typeof((*cast(const R*)_range).save)))
11703            private alias CS = typeof((*cast(const R*)_range).save);
11704
11705        static if (isSafe!((R* r) => (*r).save))
11706        {
11707            @property RefRange!S save() @trusted
11708            {
11709                mixin(_genSave());
11710            }
11711
11712            static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
11713            {
11714                mixin(_genSave());
11715            }
11716        }
11717        else
11718        {
11719            @property RefRange!S save()
11720            {
11721                mixin(_genSave());
11722            }
11723
11724            static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
11725            {
11726                mixin(_genSave());
11727            }
11728        }
11729
11730        auto opSlice()()
11731        {
11732            return save;
11733        }
11734
11735        auto opSlice()() const
11736        {
11737            return save;
11738        }
11739
11740        private static string _genSave() @safe pure nothrow
11741        {
11742            return `import core.lifetime : emplace;` ~
11743                   `alias S = typeof((*_range).save);` ~
11744                   `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
11745                   `auto mem = new void[S.sizeof];` ~
11746                   `emplace!S(mem, cast(S)(*_range).save);` ~
11747                   `return RefRange!S(cast(S*) mem.ptr);`;
11748        }
11749
11750        static assert(isForwardRange!RefRange);
11751    }
11752
11753
11754    version (StdDdoc)
11755    {
11756        /++
11757            Only defined if `isBidirectionalRange!R` is `true`.
11758          +/
11759        @property auto back() {assert(0);}
11760        /++ Ditto +/
11761        @property auto back() const {assert(0);}
11762        /++ Ditto +/
11763        @property auto back(ElementType!R value) {assert(0);}
11764    }
11765    else static if (isBidirectionalRange!R)
11766    {
11767        @property auto back()
11768        {
11769            return (*_range).back;
11770        }
11771
11772        static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
11773        {
11774            return (*_range).back;
11775        }
11776
11777        static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
11778        {
11779            return (*_range).back = value;
11780        }
11781    }
11782
11783
11784    /++ Ditto +/
11785    static if (isBidirectionalRange!R) void popBack()
11786    {
11787        return (*_range).popBack();
11788    }
11789
11790
11791    version (StdDdoc)
11792    {
11793        /++
11794            Only defined if `isRandomAccessRange!R` is `true`.
11795          +/
11796        auto ref opIndex(IndexType)(IndexType index) {assert(0);}
11797
11798        /++ Ditto +/
11799        auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
11800    }
11801    else static if (isRandomAccessRange!R)
11802    {
11803        auto ref opIndex(IndexType)(IndexType index)
11804            if (is(typeof((*_range)[index])))
11805        {
11806            return (*_range)[index];
11807        }
11808
11809        auto ref opIndex(IndexType)(IndexType index) const
11810            if (is(typeof((*cast(const R*)_range)[index])))
11811        {
11812            return (*_range)[index];
11813        }
11814    }
11815
11816
11817    /++
11818        Only defined if `hasMobileElements!R` and `isForwardRange!R` are
11819        `true`.
11820      +/
11821    static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
11822    {
11823        return (*_range).moveFront();
11824    }
11825
11826
11827    /++
11828        Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
11829        are `true`.
11830      +/
11831    static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
11832    {
11833        return (*_range).moveBack();
11834    }
11835
11836
11837    /++
11838        Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
11839        are `true`.
11840      +/
11841    static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
11842    {
11843        return (*_range).moveAt(index);
11844    }
11845
11846
11847    version (StdDdoc)
11848    {
11849        /// Only defined if `hasLength!R` is `true`.
11850        @property size_t length();
11851        /// ditto
11852        @property size_t length() const;
11853        /// Ditto
11854        alias opDollar = length;
11855    }
11856    else static if (hasLength!R)
11857    {
11858        @property auto length()
11859        {
11860            return (*_range).length;
11861        }
11862        static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
11863        {
11864            return (*_range).length;
11865        }
11866        alias opDollar = length;
11867    }
11868
11869
11870    version (StdDdoc)
11871    {
11872        /++
11873            Only defined if `hasSlicing!R` is `true`.
11874          +/
11875        auto opSlice(IndexType1, IndexType2)
11876                    (IndexType1 begin, IndexType2 end) {assert(0);}
11877
11878        /++ Ditto +/
11879        auto opSlice(IndexType1, IndexType2)
11880                    (IndexType1 begin, IndexType2 end) const {assert(0);}
11881    }
11882    else static if (hasSlicing!R)
11883    {
11884        private alias T = typeof((*_range)[1 .. 2]);
11885        static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
11886        {
11887            private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
11888        }
11889
11890        RefRange!T opSlice(IndexType1, IndexType2)
11891                    (IndexType1 begin, IndexType2 end)
11892            if (is(typeof((*_range)[begin .. end])))
11893        {
11894            mixin(_genOpSlice());
11895        }
11896
11897        RefRange!CT opSlice(IndexType1, IndexType2)
11898                    (IndexType1 begin, IndexType2 end) const
11899            if (is(typeof((*cast(const R*)_range)[begin .. end])))
11900        {
11901            mixin(_genOpSlice());
11902        }
11903
11904        private static string _genOpSlice() @safe pure nothrow
11905        {
11906            return `import core.lifetime : emplace;` ~
11907                   `alias S = typeof((*_range)[begin .. end]);` ~
11908                   `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
11909                   `auto mem = new void[S.sizeof];` ~
11910                   `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
11911                   `return RefRange!S(cast(S*) mem.ptr);`;
11912        }
11913    }
11914
11915
11916private:
11917
11918    R* _range;
11919}
11920
11921/// Basic Example
11922@system unittest
11923{
11924    import std.algorithm.searching : find;
11925    ubyte[] buffer = [1, 9, 45, 12, 22];
11926    auto found1 = find(buffer, 45);
11927    assert(found1 == [45, 12, 22]);
11928    assert(buffer == [1, 9, 45, 12, 22]);
11929
11930    auto wrapped1 = refRange(&buffer);
11931    auto found2 = find(wrapped1, 45);
11932    assert(*found2.ptr == [45, 12, 22]);
11933    assert(buffer == [45, 12, 22]);
11934
11935    auto found3 = find(wrapped1.save, 22);
11936    assert(*found3.ptr == [22]);
11937    assert(buffer == [45, 12, 22]);
11938
11939    string str = "hello world";
11940    auto wrappedStr = refRange(&str);
11941    assert(str.front == 'h');
11942    str.popFrontN(5);
11943    assert(str == " world");
11944    assert(wrappedStr.front == ' ');
11945    assert(*wrappedStr.ptr == " world");
11946}
11947
11948/// opAssign Example.
11949@system unittest
11950{
11951    ubyte[] buffer1 = [1, 2, 3, 4, 5];
11952    ubyte[] buffer2 = [6, 7, 8, 9, 10];
11953    auto wrapped1 = refRange(&buffer1);
11954    auto wrapped2 = refRange(&buffer2);
11955    assert(wrapped1.ptr is &buffer1);
11956    assert(wrapped2.ptr is &buffer2);
11957    assert(wrapped1.ptr !is wrapped2.ptr);
11958    assert(buffer1 != buffer2);
11959
11960    wrapped1 = wrapped2;
11961
11962    //Everything points to the same stuff as before.
11963    assert(wrapped1.ptr is &buffer1);
11964    assert(wrapped2.ptr is &buffer2);
11965    assert(wrapped1.ptr !is wrapped2.ptr);
11966
11967    //But buffer1 has changed due to the assignment.
11968    assert(buffer1 == [6, 7, 8, 9, 10]);
11969    assert(buffer2 == [6, 7, 8, 9, 10]);
11970
11971    buffer2 = [11, 12, 13, 14, 15];
11972
11973    //Everything points to the same stuff as before.
11974    assert(wrapped1.ptr is &buffer1);
11975    assert(wrapped2.ptr is &buffer2);
11976    assert(wrapped1.ptr !is wrapped2.ptr);
11977
11978    //But buffer2 has changed due to the assignment.
11979    assert(buffer1 == [6, 7, 8, 9, 10]);
11980    assert(buffer2 == [11, 12, 13, 14, 15]);
11981
11982    wrapped2 = null;
11983
11984    //The pointer changed for wrapped2 but not wrapped1.
11985    assert(wrapped1.ptr is &buffer1);
11986    assert(wrapped2.ptr is null);
11987    assert(wrapped1.ptr !is wrapped2.ptr);
11988
11989    //buffer2 is not affected by the assignment.
11990    assert(buffer1 == [6, 7, 8, 9, 10]);
11991    assert(buffer2 == [11, 12, 13, 14, 15]);
11992}
11993
11994@system unittest
11995{
11996    import std.algorithm.iteration : filter;
11997    {
11998        ubyte[] buffer = [1, 2, 3, 4, 5];
11999        auto wrapper = refRange(&buffer);
12000        auto p = wrapper.ptr;
12001        auto f = wrapper.front;
12002        wrapper.front = f;
12003        auto e = wrapper.empty;
12004        wrapper.popFront();
12005        auto s = wrapper.save;
12006        auto b = wrapper.back;
12007        wrapper.back = b;
12008        wrapper.popBack();
12009        auto i = wrapper[0];
12010        wrapper.moveFront();
12011        wrapper.moveBack();
12012        wrapper.moveAt(0);
12013        auto l = wrapper.length;
12014        auto sl = wrapper[0 .. 1];
12015        assert(wrapper[0 .. $].length == buffer[0 .. $].length);
12016    }
12017
12018    {
12019        ubyte[] buffer = [1, 2, 3, 4, 5];
12020        const wrapper = refRange(&buffer);
12021        const p = wrapper.ptr;
12022        const f = wrapper.front;
12023        const e = wrapper.empty;
12024        const s = wrapper.save;
12025        const b = wrapper.back;
12026        const i = wrapper[0];
12027        const l = wrapper.length;
12028        const sl = wrapper[0 .. 1];
12029    }
12030
12031    {
12032        ubyte[] buffer = [1, 2, 3, 4, 5];
12033        auto filtered = filter!"true"(buffer);
12034        auto wrapper = refRange(&filtered);
12035        auto p = wrapper.ptr;
12036        auto f = wrapper.front;
12037        wrapper.front = f;
12038        auto e = wrapper.empty;
12039        wrapper.popFront();
12040        auto s = wrapper.save;
12041        wrapper.moveFront();
12042    }
12043
12044    {
12045        ubyte[] buffer = [1, 2, 3, 4, 5];
12046        auto filtered = filter!"true"(buffer);
12047        const wrapper = refRange(&filtered);
12048        const p = wrapper.ptr;
12049
12050        //Cannot currently be const. filter needs to be updated to handle const.
12051        /+
12052        const f = wrapper.front;
12053        const e = wrapper.empty;
12054        const s = wrapper.save;
12055        +/
12056    }
12057
12058    {
12059        string str = "hello world";
12060        auto wrapper = refRange(&str);
12061        auto p = wrapper.ptr;
12062        auto f = wrapper.front;
12063        auto e = wrapper.empty;
12064        wrapper.popFront();
12065        auto s = wrapper.save;
12066        auto b = wrapper.back;
12067        wrapper.popBack();
12068    }
12069
12070    {
12071        // https://issues.dlang.org/show_bug.cgi?id=16534
12072        // opDollar should be defined if the wrapped range defines length.
12073        auto range = 10.iota.takeExactly(5);
12074        auto wrapper = refRange(&range);
12075        assert(wrapper.length == 5);
12076        assert(wrapper[0 .. $ - 1].length == 4);
12077    }
12078}
12079
12080//Test assignment.
12081@system unittest
12082{
12083    ubyte[] buffer1 = [1, 2, 3, 4, 5];
12084    ubyte[] buffer2 = [6, 7, 8, 9, 10];
12085    RefRange!(ubyte[]) wrapper1;
12086    RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
12087    assert(wrapper1.ptr is null);
12088    assert(wrapper2.ptr is &buffer2);
12089
12090    wrapper1 = refRange(&buffer1);
12091    assert(wrapper1.ptr is &buffer1);
12092
12093    wrapper1 = wrapper2;
12094    assert(wrapper1.ptr is &buffer1);
12095    assert(buffer1 == buffer2);
12096
12097    wrapper1 = RefRange!(ubyte[]).init;
12098    assert(wrapper1.ptr is null);
12099    assert(wrapper2.ptr is &buffer2);
12100    assert(buffer1 == buffer2);
12101    assert(buffer1 == [6, 7, 8, 9, 10]);
12102
12103    wrapper2 = null;
12104    assert(wrapper2.ptr is null);
12105    assert(buffer2 == [6, 7, 8, 9, 10]);
12106}
12107
12108@system unittest
12109{
12110    import std.algorithm.comparison : equal;
12111    import std.algorithm.mutation : bringToFront;
12112    import std.algorithm.searching : commonPrefix, find, until;
12113    import std.algorithm.sorting : sort;
12114
12115    //Test that ranges are properly consumed.
12116    {
12117        int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12118        auto wrapper = refRange(&arr);
12119
12120        assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12121        assert(arr == [41, 3, 40, 4, 42, 9]);
12122
12123        assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12124        assert(arr == [40, 4, 42, 9]);
12125
12126        assert(equal(until(wrapper, 42), [40, 4]));
12127        assert(arr == [42, 9]);
12128
12129        assert(find(wrapper, 12).empty);
12130        assert(arr.empty);
12131    }
12132
12133    {
12134        string str = "Hello, world-like object.";
12135        auto wrapper = refRange(&str);
12136
12137        assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12138        assert(str == "llo, world-like object.");
12139
12140        assert(equal(take(wrapper, 5), "llo, "));
12141        assert(str == "world-like object.");
12142    }
12143
12144    //Test that operating on saved ranges does not consume the original.
12145    {
12146        int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12147        auto wrapper = refRange(&arr);
12148        auto saved = wrapper.save;
12149        saved.popFrontN(3);
12150        assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12151        assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12152    }
12153
12154    {
12155        string str = "Hello, world-like object.";
12156        auto wrapper = refRange(&str);
12157        auto saved = wrapper.save;
12158        saved.popFrontN(13);
12159        assert(*saved.ptr == "like object.");
12160        assert(str == "Hello, world-like object.");
12161    }
12162
12163    //Test that functions which use save work properly.
12164    {
12165        int[] arr = [1, 42];
12166        auto wrapper = refRange(&arr);
12167        assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12168    }
12169
12170    {
12171        int[] arr = [4, 5, 6, 7, 1, 2, 3];
12172        auto wrapper = refRange(&arr);
12173        assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12174        assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12175    }
12176
12177    //Test bidirectional functions.
12178    {
12179        int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12180        auto wrapper = refRange(&arr);
12181
12182        assert(wrapper.back == 9);
12183        assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12184
12185        wrapper.popBack();
12186        assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12187    }
12188
12189    {
12190        string str = "Hello, world-like object.";
12191        auto wrapper = refRange(&str);
12192
12193        assert(wrapper.back == '.');
12194        assert(str == "Hello, world-like object.");
12195
12196        wrapper.popBack();
12197        assert(str == "Hello, world-like object");
12198    }
12199
12200    //Test random access functions.
12201    {
12202        int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12203        auto wrapper = refRange(&arr);
12204
12205        assert(wrapper[2] == 2);
12206        assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12207
12208        assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
12209        assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12210    }
12211
12212    //Test move functions.
12213    {
12214        int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12215        auto wrapper = refRange(&arr);
12216
12217        auto t1 = wrapper.moveFront();
12218        auto t2 = wrapper.moveBack();
12219        wrapper.front = t2;
12220        wrapper.back = t1;
12221        assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
12222
12223        sort(wrapper.save);
12224        assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
12225    }
12226}
12227
12228@system unittest
12229{
12230    struct S
12231    {
12232        @property int front() @safe const pure nothrow { return 0; }
12233        enum bool empty = false;
12234        void popFront() @safe pure nothrow { }
12235        @property auto save() @safe pure nothrow return scope { return this; }
12236    }
12237
12238    S s;
12239    auto wrapper = refRange(&s);
12240    static assert(isInfinite!(typeof(wrapper)));
12241}
12242
12243@system unittest
12244{
12245    class C
12246    {
12247        @property int front() @safe const pure nothrow { return 0; }
12248        @property bool empty() @safe const pure nothrow { return false; }
12249        void popFront() @safe pure nothrow { }
12250        @property auto save() @safe pure nothrow return scope { return this; }
12251    }
12252    static assert(isForwardRange!C);
12253
12254    auto c = new C;
12255    auto cWrapper = refRange(&c);
12256    static assert(is(typeof(cWrapper) == C));
12257    assert(cWrapper is c);
12258}
12259
12260// https://issues.dlang.org/show_bug.cgi?id=14373
12261@system unittest
12262{
12263    static struct R
12264    {
12265        @property int front() {return 0;}
12266        void popFront() {empty = true;}
12267        bool empty = false;
12268    }
12269    R r;
12270    refRange(&r).popFront();
12271    assert(r.empty);
12272}
12273
12274// https://issues.dlang.org/show_bug.cgi?id=14575
12275@system unittest
12276{
12277    struct R
12278    {
12279        Object front;
12280        alias back = front;
12281        bool empty = false;
12282        void popFront() {empty = true;}
12283        alias popBack = popFront;
12284        @property R save() {return this;}
12285    }
12286    static assert(isBidirectionalRange!R);
12287    R r;
12288    auto rr = refRange(&r);
12289
12290    struct R2
12291    {
12292        @property Object front() {return null;}
12293        @property const(Object) front() const {return null;}
12294        alias back = front;
12295        bool empty = false;
12296        void popFront() {empty = true;}
12297        alias popBack = popFront;
12298        @property R2 save() {return this;}
12299    }
12300    static assert(isBidirectionalRange!R2);
12301    R2 r2;
12302    auto rr2 = refRange(&r2);
12303}
12304
12305/// ditto
12306auto refRange(R)(R* range)
12307if (isInputRange!R)
12308{
12309    static if (!is(R == class))
12310        return RefRange!R(range);
12311    else
12312        return *range;
12313}
12314
12315// https://issues.dlang.org/show_bug.cgi?id=9060
12316@safe unittest
12317{
12318    import std.algorithm.iteration : map, joiner, group;
12319    import std.algorithm.searching : until;
12320    // fix for std.algorithm
12321    auto r = map!(x => 0)([1]);
12322    chain(r, r);
12323    zip(r, r);
12324    roundRobin(r, r);
12325
12326    struct NRAR {
12327        typeof(r) input;
12328        @property empty() { return input.empty; }
12329        @property front() { return input.front; }
12330        void popFront()   { input.popFront(); }
12331        @property save()  { return NRAR(input.save); }
12332    }
12333    auto n1 = NRAR(r);
12334    cycle(n1);  // non random access range version
12335
12336    assumeSorted(r);
12337
12338    // fix for std.range
12339    joiner([r], [9]);
12340
12341    struct NRAR2 {
12342        NRAR input;
12343        @property empty() { return true; }
12344        @property front() { return input; }
12345        void popFront() { }
12346        @property save()  { return NRAR2(input.save); }
12347    }
12348    auto n2 = NRAR2(n1);
12349    joiner(n2);
12350
12351    group(r);
12352
12353    until(r, 7);
12354    static void foo(R)(R r) { until!(x => x > 7)(r); }
12355    foo(r);
12356}
12357
12358private struct Bitwise(R)
12359if (isInputRange!R && isIntegral!(ElementType!R))
12360{
12361    import std.traits : Unsigned;
12362private:
12363    alias ElemType = ElementType!R;
12364    alias UnsignedElemType = Unsigned!ElemType;
12365
12366    R parent;
12367    enum bitsNum = ElemType.sizeof * 8;
12368    size_t maskPos = 1;
12369
12370    static if (isBidirectionalRange!R)
12371    {
12372        size_t backMaskPos = bitsNum;
12373    }
12374
12375public:
12376    this()(auto ref R range)
12377    {
12378        parent = range;
12379    }
12380
12381    static if (isInfinite!R)
12382    {
12383        enum empty = false;
12384    }
12385    else
12386    {
12387        /**
12388         * Check if the range is empty
12389         *
12390         * Returns: a boolean true or false
12391         */
12392        bool empty()
12393        {
12394            static if (hasLength!R)
12395            {
12396                return length == 0;
12397            }
12398            else static if (isBidirectionalRange!R)
12399            {
12400                if (parent.empty)
12401                {
12402                    return true;
12403                }
12404                else
12405                {
12406                    /*
12407                       If we have consumed the last element of the range both from
12408                       the front and the back, then the masks positions will overlap
12409                     */
12410                    return parent.save.dropOne.empty && (maskPos > backMaskPos);
12411                }
12412            }
12413            else
12414            {
12415                /*
12416                   If we consumed the last element of the range, but not all the
12417                   bits in the last element
12418                 */
12419                return parent.empty;
12420            }
12421        }
12422    }
12423
12424    bool front()
12425    {
12426        assert(!empty);
12427        return (parent.front & mask(maskPos)) != 0;
12428    }
12429
12430    void popFront()
12431    {
12432        assert(!empty);
12433        ++maskPos;
12434        if (maskPos > bitsNum)
12435        {
12436            parent.popFront;
12437            maskPos = 1;
12438        }
12439    }
12440
12441    static if (hasLength!R)
12442    {
12443        size_t length()
12444        {
12445            auto len = parent.length * bitsNum - (maskPos - 1);
12446            static if (isBidirectionalRange!R)
12447            {
12448                len -= bitsNum - backMaskPos;
12449            }
12450            return len;
12451        }
12452
12453        alias opDollar = length;
12454    }
12455
12456    static if (isForwardRange!R)
12457    {
12458        typeof(this) save()
12459        {
12460            auto result = this;
12461            result.parent = parent.save;
12462            return result;
12463        }
12464    }
12465
12466    static if (isBidirectionalRange!R)
12467    {
12468        bool back()
12469        {
12470            assert(!empty);
12471            return (parent.back & mask(backMaskPos)) != 0;
12472        }
12473
12474        void popBack()
12475        {
12476            assert(!empty);
12477            --backMaskPos;
12478            if (backMaskPos == 0)
12479            {
12480                parent.popBack;
12481                backMaskPos = bitsNum;
12482            }
12483        }
12484    }
12485
12486    static if (isRandomAccessRange!R)
12487    {
12488        /**
12489          Return the `n`th bit within the range
12490         */
12491        bool opIndex(size_t n)
12492        in
12493        {
12494            /*
12495               If it does not have the length property, it means that R is
12496               an infinite range
12497             */
12498            static if (hasLength!R)
12499            {
12500                assert(n < length, "Index out of bounds");
12501            }
12502        }
12503        do
12504        {
12505            immutable size_t remainingBits = bitsNum - maskPos + 1;
12506            // If n >= maskPos, then the bit sign will be 1, otherwise 0
12507            immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12508            /*
12509               By truncating n with remainingBits bits we have skipped the
12510               remaining bits in parent[0], so we need to add 1 to elemIndex.
12511
12512               Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
12513             */
12514            import core.bitop : bsf;
12515            immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12516
12517            /*
12518               Since the indexing is from LSB to MSB, we need to index at the
12519               remainder of (n - remainingBits).
12520
12521               Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
12522             */
12523            immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12524                             + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12525
12526            return (parent[elemIndex] & mask(elemMaskPos)) != 0;
12527        }
12528
12529        static if (hasAssignableElements!R)
12530        {
12531            /**
12532              Assigns `flag` to the `n`th bit within the range
12533             */
12534            void opIndexAssign(bool flag, size_t n)
12535                in
12536                {
12537                    static if (hasLength!R)
12538                    {
12539                        assert(n < length, "Index out of bounds");
12540                    }
12541                }
12542            do
12543            {
12544                import core.bitop : bsf;
12545
12546                immutable size_t remainingBits = bitsNum - maskPos + 1;
12547                immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12548                immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
12549                immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
12550                    + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
12551
12552                auto elem = parent[elemIndex];
12553                auto elemMask = mask(elemMaskPos);
12554                parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
12555                        + (flag ^ 1) * (elem & ~elemMask));
12556            }
12557        }
12558
12559        Bitwise!R opSlice()
12560        {
12561            return this.save;
12562        }
12563
12564        Bitwise!R opSlice(size_t start, size_t end)
12565        in
12566        {
12567            assert(start < end, "Invalid bounds: end <= start");
12568        }
12569        do
12570        {
12571            import core.bitop : bsf;
12572
12573            size_t remainingBits = bitsNum - maskPos + 1;
12574            ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12575            immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
12576            immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
12577                                              + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
12578
12579            immutable size_t sliceLen = end - start - 1;
12580            remainingBits = bitsNum - startElemMaskPos + 1;
12581            sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
12582            immutable size_t endElemIndex = startElemIndex
12583                                          + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
12584            immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
12585                                            + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
12586
12587            typeof(return) result;
12588            // Get the slice to be returned from the parent
12589            result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
12590            result.maskPos = startElemMaskPos;
12591            static if (isBidirectionalRange!R)
12592            {
12593                result.backMaskPos = endElemMaskPos;
12594            }
12595            return result;
12596        }
12597    }
12598
12599private:
12600    auto mask(size_t maskPos)
12601    {
12602        return (1UL << (maskPos - 1UL));
12603    }
12604}
12605
12606/**
12607Bitwise adapter over an integral type range. Consumes the range elements bit by
12608bit, from the least significant bit to the most significant bit.
12609
12610Params:
12611    R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
12612    range = range to consume bit by by
12613
12614Returns:
12615    A `Bitwise` input range with propagated forward, bidirectional
12616    and random access capabilities
12617*/
12618auto bitwise(R)(auto ref R range)
12619if (isInputRange!R && isIntegral!(ElementType!R))
12620{
12621    return Bitwise!R(range);
12622}
12623
12624///
12625@safe pure unittest
12626{
12627    import std.algorithm.comparison : equal;
12628    import std.format : format;
12629
12630    // 00000011 00001001
12631    ubyte[] arr = [3, 9];
12632    auto r = arr.bitwise;
12633
12634    // iterate through it as with any other range
12635    assert(format("%(%d%)", r) == "1100000010010000");
12636    assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
12637
12638    auto r2 = r[5 .. $];
12639    // set a bit
12640    r[2] = 1;
12641    assert(arr[0] == 7);
12642    assert(r[5] == r2[0]);
12643}
12644
12645/// You can use bitwise to implement an uniform bool generator
12646@safe unittest
12647{
12648    import std.algorithm.comparison : equal;
12649    import std.random : rndGen;
12650
12651    auto rb = rndGen.bitwise;
12652    static assert(isInfinite!(typeof(rb)));
12653
12654    auto rb2 = rndGen.bitwise;
12655    // Don't forget that structs are passed by value
12656    assert(rb.take(10).equal(rb2.take(10)));
12657}
12658
12659// Test nogc inference
12660@safe @nogc unittest
12661{
12662    static ubyte[] arr = [3, 9];
12663    auto bw = arr.bitwise;
12664    auto bw2 = bw[];
12665    auto bw3 = bw[8 .. $];
12666    bw3[2] = true;
12667
12668    assert(arr[1] == 13);
12669    assert(bw[$ - 6]);
12670    assert(bw[$ - 6] == bw2[$ - 6]);
12671    assert(bw[$ - 6] == bw3[$ - 6]);
12672}
12673
12674// Test all range types over all integral types
12675@safe pure nothrow unittest
12676{
12677    import std.meta : AliasSeq;
12678    import std.internal.test.dummyrange;
12679
12680    alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
12681            long, ulong);
12682    foreach (IntegralType; IntegralTypes)
12683    {
12684        foreach (T; AllDummyRangesType!(IntegralType[]))
12685        {
12686            T a;
12687            auto bw = Bitwise!T(a);
12688
12689            static if (isForwardRange!T)
12690            {
12691                auto bwFwdSave = bw.save;
12692            }
12693
12694            static if (isBidirectionalRange!T)
12695            {
12696                auto bwBack = bw.save;
12697                auto bwBackSave = bw.save;
12698            }
12699
12700            static if (hasLength!T)
12701            {
12702                auto bwLength = bw.length;
12703                assert(bw.length == (IntegralType.sizeof * 8 * a.length));
12704                static if (isForwardRange!T)
12705                {
12706                    assert(bw.length == bwFwdSave.length);
12707                }
12708            }
12709
12710            // Make sure front and back are not the mechanisms that modify the range
12711            long numCalls = 42;
12712            bool initialFrontValue;
12713
12714            if (!bw.empty)
12715            {
12716                initialFrontValue = bw.front;
12717            }
12718
12719            while (!bw.empty && (--numCalls))
12720            {
12721                bw.front;
12722                assert(bw.front == initialFrontValue);
12723            }
12724
12725            /*
12726               Check that empty works properly and that popFront does not get called
12727               more times than it should
12728             */
12729            numCalls = 0;
12730            while (!bw.empty)
12731            {
12732                ++numCalls;
12733
12734                static if (hasLength!T)
12735                {
12736                    assert(bw.length == bwLength);
12737                    --bwLength;
12738                }
12739
12740                static if (isForwardRange!T)
12741                {
12742                    assert(bw.front == bwFwdSave.front);
12743                    bwFwdSave.popFront();
12744                }
12745
12746                static if (isBidirectionalRange!T)
12747                {
12748                    assert(bwBack.front == bwBackSave.front);
12749                    bwBack.popBack();
12750                    bwBackSave.popBack();
12751                }
12752                bw.popFront();
12753            }
12754
12755            auto rangeLen = numCalls / (IntegralType.sizeof * 8);
12756            assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
12757            assert(bw.empty);
12758            static if (isForwardRange!T)
12759            {
12760                assert(bwFwdSave.empty);
12761            }
12762
12763            static if (isBidirectionalRange!T)
12764            {
12765                assert(bwBack.empty);
12766            }
12767        }
12768    }
12769}
12770
12771// Test opIndex and opSlice
12772@system unittest
12773{
12774    import std.meta : AliasSeq;
12775    alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
12776            long, ulong);
12777    foreach (IntegralType; IntegralTypes)
12778    {
12779        size_t bitsNum = IntegralType.sizeof * 8;
12780
12781        auto first = cast(IntegralType)(1);
12782
12783        // 2 ^ (bitsNum - 1)
12784        auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
12785
12786        IntegralType[] a = [first, second];
12787        auto bw = Bitwise!(IntegralType[])(a);
12788
12789        // Check against lsb of a[0]
12790        assert(bw[0] == true);
12791        // Check against msb - 1 of a[1]
12792        assert(bw[2 * bitsNum - 2] == true);
12793
12794        bw.popFront();
12795        assert(bw[2 * bitsNum - 3] == true);
12796
12797        import std.exception : assertThrown;
12798
12799        version (D_NoBoundsChecks) {}
12800        else
12801        {
12802            // Check out of bounds error
12803            assertThrown!Error(bw[2 * bitsNum - 1]);
12804        }
12805
12806        bw[2] = true;
12807        assert(bw[2] == true);
12808        bw.popFront();
12809        assert(bw[1] == true);
12810
12811        auto bw2 = bw[0 .. $ - 5];
12812        auto bw3 = bw2[];
12813        assert(bw2.length == (bw.length - 5));
12814        assert(bw2.length == bw3.length);
12815        bw2.popFront();
12816        assert(bw2.length != bw3.length);
12817    }
12818}
12819
12820/*********************************
12821 * An OutputRange that discards the data it receives.
12822 */
12823struct NullSink
12824{
12825    void put(E)(scope const E) pure @safe @nogc nothrow {}
12826}
12827
12828/// ditto
12829auto ref nullSink()
12830{
12831    static NullSink sink;
12832    return sink;
12833}
12834
12835///
12836@safe nothrow unittest
12837{
12838    import std.algorithm.iteration : map;
12839    import std.algorithm.mutation : copy;
12840    [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
12841}
12842
12843///
12844@safe unittest
12845{
12846    import std.csv : csvNextToken;
12847
12848    string line = "a,b,c";
12849
12850    // ignore the first column
12851    line.csvNextToken(nullSink, ',', '"');
12852    line.popFront;
12853
12854    // look at the second column
12855    Appender!string app;
12856    line.csvNextToken(app, ',', '"');
12857    assert(app.data == "b");
12858}
12859
12860@safe unittest
12861{
12862    auto r = 10.iota
12863                .tee(nullSink)
12864                .dropOne;
12865
12866    assert(r.front == 1);
12867}
12868
12869/++
12870
12871  Implements a "tee" style pipe, wrapping an input range so that elements of the
12872  range can be passed to a provided function or $(LREF OutputRange) as they are
12873  iterated over. This is useful for printing out intermediate values in a long
12874  chain of range code, performing some operation with side-effects on each call
12875  to `front` or `popFront`, or diverting the elements of a range into an
12876  auxiliary $(LREF OutputRange).
12877
12878  It is important to note that as the resultant range is evaluated lazily,
12879  in the case of the version of `tee` that takes a function, the function
12880  will not actually be executed until the range is "walked" using functions
12881  that evaluate ranges, such as $(REF array, std,array) or
12882  $(REF fold, std,algorithm,iteration).
12883
12884  Params:
12885  pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
12886  calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
12887  respectively, `fun`). Note that each `popFront()` call will mirror the
12888  old `front` value, not the new one. This means that the last value will
12889  not be forwarded if the range isn't iterated until empty. If
12890  `No.pipeOnPop`, only elements for which `front` does get called will be
12891  also sent to `outputRange`/`fun`. If `front` is called twice for the same
12892  element, it will still be sent only once. If this caching is undesired,
12893  consider using $(REF map, std,algorithm,iteration) instead.
12894  inputRange = The input range being passed through.
12895  outputRange = This range will receive elements of `inputRange` progressively
12896  as iteration proceeds.
12897  fun = This function will be called with elements of `inputRange`
12898  progressively as iteration proceeds.
12899
12900  Returns:
12901  An input range that offers the elements of `inputRange`. Regardless of
12902  whether `inputRange` is a more powerful range (forward, bidirectional etc),
12903  the result is always an input range. Reading this causes `inputRange` to be
12904  iterated and returns its elements in turn. In addition, the same elements
12905  will be passed to `outputRange` or `fun` as well.
12906
12907  See_Also: $(REF each, std,algorithm,iteration)
12908+/
12909auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
12910if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
12911{
12912    static struct Result
12913    {
12914        private R1 _input;
12915        private R2 _output;
12916        static if (!pipeOnPop)
12917        {
12918            private bool _frontAccessed;
12919        }
12920
12921        mixin ImplementLength!_input;
12922
12923        static if (isInfinite!R1)
12924        {
12925            enum bool empty = false;
12926        }
12927        else
12928        {
12929            @property bool empty() { return _input.empty; }
12930        }
12931
12932        void popFront()
12933        {
12934            assert(!_input.empty, "Attempting to popFront an empty tee");
12935            static if (pipeOnPop)
12936            {
12937                put(_output, _input.front);
12938            }
12939            else
12940            {
12941                _frontAccessed = false;
12942            }
12943            _input.popFront();
12944        }
12945
12946        @property auto ref front()
12947        {
12948            assert(!_input.empty, "Attempting to fetch the front of an empty tee");
12949            static if (!pipeOnPop)
12950            {
12951                if (!_frontAccessed)
12952                {
12953                    _frontAccessed = true;
12954                    put(_output, _input.front);
12955                }
12956            }
12957            return _input.front;
12958        }
12959    }
12960
12961    return Result(inputRange, outputRange);
12962}
12963
12964/// Ditto
12965auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
12966if (is(typeof(fun) == void) || isSomeFunction!fun)
12967{
12968    import std.traits : isDelegate, isFunctionPointer;
12969    /*
12970        Distinguish between function literals and template lambdas
12971        when using either as an $(LREF OutputRange). Since a template
12972        has no type, typeof(template) will always return void.
12973        If it's a template lambda, it's first necessary to instantiate
12974        it with `ElementType!R1`.
12975    */
12976    static if (is(typeof(fun) == void))
12977        alias _fun = fun!(ElementType!R1);
12978    else
12979        alias _fun = fun;
12980
12981    static if (isFunctionPointer!_fun || isDelegate!_fun)
12982    {
12983        return tee!pipeOnPop(inputRange, _fun);
12984    }
12985    else
12986    {
12987        return tee!pipeOnPop(inputRange, &_fun);
12988    }
12989}
12990
12991///
12992@safe unittest
12993{
12994    import std.algorithm.comparison : equal;
12995    import std.algorithm.iteration : filter, map;
12996
12997    // Sum values while copying
12998    int[] values = [1, 4, 9, 16, 25];
12999    int sum = 0;
13000    auto newValues = values.tee!(a => sum += a).array;
13001    assert(equal(newValues, values));
13002    assert(sum == 1 + 4 + 9 + 16 + 25);
13003
13004    // Count values that pass the first filter
13005    int count = 0;
13006    auto newValues4 = values.filter!(a => a < 10)
13007                            .tee!(a => count++)
13008                            .map!(a => a + 1)
13009                            .filter!(a => a < 10);
13010
13011    //Fine, equal also evaluates any lazy ranges passed to it.
13012    //count is not 3 until equal evaluates newValues4
13013    assert(equal(newValues4, [2, 5]));
13014    assert(count == 3);
13015}
13016
13017//
13018@safe unittest
13019{
13020    import std.algorithm.comparison : equal;
13021    import std.algorithm.iteration : filter, map;
13022
13023    int[] values = [1, 4, 9, 16, 25];
13024
13025    int count = 0;
13026    auto newValues = values.filter!(a => a < 10)
13027        .tee!(a => count++, No.pipeOnPop)
13028        .map!(a => a + 1)
13029        .filter!(a => a < 10);
13030
13031    auto val = newValues.front;
13032    assert(count == 1);
13033    //front is only evaluated once per element
13034    val = newValues.front;
13035    assert(count == 1);
13036
13037    //popFront() called, fun will be called
13038    //again on the next access to front
13039    newValues.popFront();
13040    newValues.front;
13041    assert(count == 2);
13042
13043    int[] preMap = new int[](3), postMap = [];
13044    auto mappedValues = values.filter!(a => a < 10)
13045        //Note the two different ways of using tee
13046        .tee(preMap)
13047        .map!(a => a + 1)
13048        .tee!(a => postMap ~= a)
13049        .filter!(a => a < 10);
13050    assert(equal(mappedValues, [2, 5]));
13051    assert(equal(preMap, [1, 4, 9]));
13052    assert(equal(postMap, [2, 5, 10]));
13053}
13054
13055//
13056@safe unittest
13057{
13058    import std.algorithm.comparison : equal;
13059    import std.algorithm.iteration : filter, map;
13060
13061    char[] txt = "Line one, Line 2".dup;
13062
13063    bool isVowel(dchar c)
13064    {
13065        import std.string : indexOf;
13066        return "AaEeIiOoUu".indexOf(c) != -1;
13067    }
13068
13069    int vowelCount = 0;
13070    int shiftedCount = 0;
13071    auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
13072                                .filter!(c => !isVowel(c))
13073                                .map!(c => (c == ' ') ? c : c + 1)
13074                                .tee!(c => isVowel(c) ? shiftedCount++ : 0);
13075    assert(equal(removeVowels, "Mo o- Mo 3"));
13076    assert(vowelCount == 6);
13077    assert(shiftedCount == 3);
13078}
13079
13080@safe unittest
13081{
13082    // Manually stride to test different pipe behavior.
13083    void testRange(Range)(Range r)
13084    {
13085        const int strideLen = 3;
13086        int i = 0;
13087        ElementType!Range elem1;
13088        ElementType!Range elem2;
13089        while (!r.empty)
13090        {
13091            if (i % strideLen == 0)
13092            {
13093                //Make sure front is only
13094                //evaluated once per item
13095                elem1 = r.front;
13096                elem2 = r.front;
13097                assert(elem1 == elem2);
13098            }
13099            r.popFront();
13100            i++;
13101        }
13102    }
13103
13104    string txt = "abcdefghijklmnopqrstuvwxyz";
13105
13106    int popCount = 0;
13107    auto pipeOnPop = txt.tee!(a => popCount++);
13108    testRange(pipeOnPop);
13109    assert(popCount == 26);
13110
13111    int frontCount = 0;
13112    auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13113    testRange(pipeOnFront);
13114    assert(frontCount == 9);
13115}
13116
13117@safe unittest
13118{
13119    import std.algorithm.comparison : equal;
13120    import std.meta : AliasSeq;
13121
13122    //Test diverting elements to an OutputRange
13123    string txt = "abcdefghijklmnopqrstuvwxyz";
13124
13125    dchar[] asink1 = [];
13126    auto fsink = (dchar c) { asink1 ~= c; };
13127    auto result1 = txt.tee(fsink).array;
13128    assert(equal(txt, result1) && (equal(result1, asink1)));
13129
13130    dchar[] _asink1 = [];
13131    auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13132    assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13133
13134    dchar[] asink2 = new dchar[](txt.length);
13135    void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13136    auto result2 = txt.tee(&fsink2).array;
13137    assert(equal(txt, result2) && equal(result2, asink2));
13138
13139    dchar[] asink3 = new dchar[](txt.length);
13140    auto result3 = txt.tee(asink3).array;
13141    assert(equal(txt, result3) && equal(result3, asink3));
13142
13143    static foreach (CharType; AliasSeq!(char, wchar, dchar))
13144    {{
13145        auto appSink = appender!(CharType[])();
13146        auto appResult = txt.tee(appSink).array;
13147        assert(equal(txt, appResult) && equal(appResult, appSink.data));
13148    }}
13149
13150    static foreach (StringType; AliasSeq!(string, wstring, dstring))
13151    {{
13152        auto appSink = appender!StringType();
13153        auto appResult = txt.tee(appSink).array;
13154        assert(equal(txt, appResult) && equal(appResult, appSink.data));
13155    }}
13156}
13157
13158// https://issues.dlang.org/show_bug.cgi?id=13483
13159@safe unittest
13160{
13161    static void func1(T)(T x) {}
13162    void func2(int x) {}
13163
13164    auto r = [1, 2, 3, 4].tee!func1.tee!func2;
13165}
13166
13167/**
13168Extends the length of the input range `r` by padding out the start of the
13169range with the element `e`. The element `e` must be of a common type with
13170the element type of the range `r` as defined by $(REF CommonType, std, traits).
13171If `n` is less than the length of of `r`, then `r` is returned unmodified.
13172
13173If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
13174about length for strings, which is not the number of characters, or
13175graphemes, but instead the number of encoding units. If you want to treat each
13176grapheme as only one encoding unit long, then call
13177$(REF byGrapheme, std, uni) before calling this function.
13178
13179If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
13180
13181Params:
13182    r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
13183    e = element to pad the range with
13184    n = the length to pad to
13185
13186Returns:
13187    A range containing the elements of the original range with the extra padding
13188
13189See Also:
13190    $(REF leftJustifier, std, string)
13191*/
13192auto padLeft(R, E)(R r, E e, size_t n)
13193if (
13194    ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
13195    !is(CommonType!(ElementType!R, E) == void)
13196)
13197{
13198    static if (hasLength!R)
13199        auto dataLength = r.length;
13200    else
13201        auto dataLength = r.save.walkLength(n);
13202
13203    return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
13204}
13205
13206///
13207@safe pure unittest
13208{
13209    import std.algorithm.comparison : equal;
13210
13211    assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
13212    assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
13213
13214    assert("abc".padLeft('_', 6).equal("___abc"));
13215}
13216
13217@safe pure nothrow unittest
13218{
13219    import std.algorithm.comparison : equal;
13220    import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
13221    import std.meta : AliasSeq;
13222
13223    alias DummyRanges = AliasSeq!(
13224        DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
13225        DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
13226        DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
13227        DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
13228        DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
13229        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
13230        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
13231        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
13232        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
13233        DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
13234    );
13235
13236    foreach (Range; DummyRanges)
13237    {
13238        Range r;
13239        assert(r
13240            .padLeft(0, 12)
13241            .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13242        );
13243    }
13244}
13245
13246// Test nogc inference
13247@safe @nogc pure unittest
13248{
13249    import std.algorithm.comparison : equal;
13250
13251    static immutable r1 = [1, 2, 3, 4];
13252    static immutable r2 = [0, 0, 1, 2, 3, 4];
13253    assert(r1.padLeft(0, 6).equal(r2));
13254}
13255
13256/**
13257Extend the length of the input range `r` by padding out the end of the range
13258with the element `e`. The element `e` must be of a common type with the
13259element type of the range `r` as defined by $(REF CommonType, std, traits).
13260If `n` is less than the length of of `r`, then the contents of `r` are
13261returned.
13262
13263The range primitives that the resulting range provides depends whether or not `r`
13264provides them. Except the functions `back` and `popBack`, which also require
13265the range to have a length as well as `back` and `popBack`
13266
13267Params:
13268    r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
13269    e = element to pad the range with
13270    n = the length to pad to
13271
13272Returns:
13273    A range containing the elements of the original range with the extra padding
13274
13275See Also:
13276    $(REF rightJustifier, std, string)
13277*/
13278auto padRight(R, E)(R r, E e, size_t n)
13279if (
13280    isInputRange!R &&
13281    !isInfinite!R &&
13282    !is(CommonType!(ElementType!R, E) == void))
13283{
13284    static struct Result
13285    {
13286        private:
13287        R data;
13288        E element;
13289        static if (hasLength!R)
13290        {
13291            size_t padLength;
13292        }
13293        else
13294        {
13295            size_t minLength;
13296            size_t consumed;
13297        }
13298
13299        public:
13300        bool empty() @property
13301        {
13302            static if (hasLength!R)
13303            {
13304                return data.empty && padLength == 0;
13305            }
13306            else
13307            {
13308                return data.empty && consumed >= minLength;
13309            }
13310        }
13311
13312        auto front() @property
13313        {
13314            assert(!empty, "Attempting to fetch the front of an empty padRight");
13315            return data.empty ? element : data.front;
13316        }
13317
13318        void popFront()
13319        {
13320            assert(!empty, "Attempting to popFront an empty padRight");
13321
13322            static if (hasLength!R)
13323            {
13324                if (!data.empty)
13325                {
13326                    data.popFront;
13327                }
13328                else
13329                {
13330                    --padLength;
13331                }
13332            }
13333            else
13334            {
13335                ++consumed;
13336                if (!data.empty)
13337                {
13338                    data.popFront;
13339                }
13340            }
13341        }
13342
13343        static if (hasLength!R)
13344        {
13345            size_t length() @property
13346            {
13347                return data.length + padLength;
13348            }
13349        }
13350
13351        static if (isForwardRange!R)
13352        {
13353            auto save() @property
13354            {
13355                typeof(this) result = this;
13356                data = data.save;
13357                return result;
13358            }
13359        }
13360
13361        static if (isBidirectionalRange!R && hasLength!R)
13362        {
13363            auto back() @property
13364            {
13365                assert(!empty, "Attempting to fetch the back of an empty padRight");
13366                return padLength > 0 ? element : data.back;
13367            }
13368
13369            void popBack()
13370            {
13371                assert(!empty, "Attempting to popBack an empty padRight");
13372                if (padLength > 0)
13373                {
13374                    --padLength;
13375                }
13376                else
13377                {
13378                    data.popBack;
13379                }
13380            }
13381        }
13382
13383        static if (isRandomAccessRange!R && hasLength!R)
13384        {
13385            E opIndex(size_t index)
13386            {
13387                assert(index <= this.length, "Index out of bounds");
13388                return index >= data.length ? element : data[index];
13389            }
13390        }
13391
13392        static if (hasSlicing!R && hasLength!R)
13393        {
13394            auto opSlice(size_t a, size_t b)
13395            {
13396                assert(
13397                    a <= b,
13398                    "Attempting to slice a padRight with a larger first argument than the second."
13399                );
13400                assert(
13401                    b <= length,
13402                    "Attempting to slice using an out of bounds index on a padRight"
13403                );
13404                return Result(
13405                    a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
13406                    element, b - a);
13407            }
13408
13409            alias opDollar = length;
13410        }
13411
13412        this(R r, E e, size_t n)
13413        {
13414            data = r;
13415            element = e;
13416            static if (hasLength!R)
13417            {
13418                padLength = n > data.length ? n - data.length : 0;
13419            }
13420            else
13421            {
13422                minLength = n;
13423            }
13424        }
13425
13426        @disable this();
13427    }
13428
13429    return Result(r, e, n);
13430}
13431
13432///
13433@safe pure unittest
13434{
13435    import std.algorithm.comparison : equal;
13436
13437    assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
13438    assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
13439
13440    assert("abc".padRight('_', 6).equal("abc___"));
13441}
13442
13443pure @safe unittest
13444{
13445    import std.algorithm.comparison : equal;
13446    import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
13447    import std.meta : AliasSeq;
13448
13449    auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
13450    dchar padding = '_';
13451    assert(string_input_range.padRight(padding, 6).equal("abc___"));
13452
13453    foreach (RangeType; AllDummyRanges)
13454    {
13455        RangeType r1;
13456        assert(r1
13457            .padRight(0, 12)
13458            .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13459        );
13460
13461        // test if Result properly uses random access ranges
13462        static if (isRandomAccessRange!RangeType)
13463        {
13464            RangeType r3;
13465            assert(r3.padRight(0, 12)[0] == 1);
13466            assert(r3.padRight(0, 12)[2] == 3);
13467            assert(r3.padRight(0, 12)[9] == 10);
13468            assert(r3.padRight(0, 12)[10] == 0);
13469            assert(r3.padRight(0, 12)[11] == 0);
13470        }
13471
13472        // test if Result properly uses slicing and opDollar
13473        static if (hasSlicing!RangeType)
13474        {
13475            RangeType r4;
13476            assert(r4
13477                .padRight(0, 12)[0 .. 3]
13478                .equal([1, 2, 3])
13479            );
13480            assert(r4
13481                .padRight(0, 12)[0 .. 10]
13482                .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
13483            );
13484            assert(r4
13485                .padRight(0, 12)[0 .. 11]
13486                .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
13487            );
13488            assert(r4
13489                .padRight(0, 12)[2 .. $]
13490                .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13491            );
13492            assert(r4
13493                .padRight(0, 12)[0 .. $]
13494                .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
13495            );
13496        }
13497
13498        // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
13499        RangeType r5;
13500        foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
13501    }
13502}
13503
13504// Test nogc inference
13505@safe @nogc pure unittest
13506{
13507    import std.algorithm.comparison : equal;
13508
13509    static immutable r1 = [1, 2, 3, 4];
13510    static immutable r2 = [1, 2, 3, 4, 0, 0];
13511    assert(r1.padRight(0, 6).equal(r2));
13512}
13513
13514// Test back, popBack, and save
13515@safe pure unittest
13516{
13517    import std.algorithm.comparison : equal;
13518
13519    auto r1 = [1, 2, 3, 4].padRight(0, 6);
13520    assert(r1.back == 0);
13521
13522    r1.popBack;
13523    auto r2 = r1.save;
13524    assert(r1.equal([1, 2, 3, 4, 0]));
13525    assert(r2.equal([1, 2, 3, 4, 0]));
13526
13527    r1.popBackN(2);
13528    assert(r1.back == 3);
13529    assert(r1.length == 3);
13530    assert(r2.length == 5);
13531    assert(r2.equal([1, 2, 3, 4, 0]));
13532
13533    r2.popFront;
13534    assert(r2.length == 4);
13535    assert(r2[0] == 2);
13536    assert(r2[1] == 3);
13537    assert(r2[2] == 4);
13538    assert(r2[3] == 0);
13539    assert(r2.equal([2, 3, 4, 0]));
13540
13541    r2.popBack;
13542    assert(r2.equal([2, 3, 4]));
13543
13544    auto r3 = [1, 2, 3, 4].padRight(0, 6);
13545    size_t len = 0;
13546    while (!r3.empty)
13547    {
13548        ++len;
13549        r3.popBack;
13550    }
13551    assert(len == 6);
13552}
13553
13554// https://issues.dlang.org/show_bug.cgi?id=19042
13555@safe pure unittest
13556{
13557    import std.algorithm.comparison : equal;
13558
13559    assert([2, 5, 13].padRight(42, 10).chunks(5)
13560           .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
13561
13562    assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
13563}
13564
13565/**
13566This simplifies a commonly used idiom in phobos for accepting any kind of string
13567parameter. The type `R` can for example be a simple string, chained string using
13568$(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
13569characters.
13570
13571Only finite length character ranges are allowed with this constraint.
13572
13573This template is equivalent to:
13574---
13575isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
13576---
13577
13578See_Also:
13579$(REF isInputRange, std,range,primitives),
13580$(REF isInfinite, std,range,primitives),
13581$(LREF isSomeChar),
13582$(REF ElementEncodingType, std,range,primitives)
13583*/
13584template isSomeFiniteCharInputRange(R)
13585{
13586    import std.traits : isSomeChar;
13587
13588    enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
13589        && isSomeChar!(ElementEncodingType!R);
13590}
13591
13592///
13593@safe unittest
13594{
13595    import std.path : chainPath;
13596    import std.range : chain;
13597
13598    void someLibraryMethod(R)(R argument)
13599    if (isSomeFiniteCharInputRange!R)
13600    {
13601        // implementation detail, would iterate over each character of argument
13602    }
13603
13604    someLibraryMethod("simple strings work");
13605    someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
13606    someLibraryMethod(chainPath("chained", "paths", "work"));
13607    // you can also use custom structs implementing a char range
13608}
13609
13610