1 // Written in the D programming language.
2 
3 /**
4 This module defines the notion of a range. Ranges generalize the concept of
5 arrays, lists, or anything that involves sequential access. This abstraction
6 enables the same set of algorithms (see $(MREF std, algorithm)) to be used
7 with a vast variety of different concrete types. For example,
8 a linear search algorithm such as $(REF find, std, algorithm, searching)
9 works not just for arrays, but for linked-lists, input files,
10 incoming network data, etc.
11 
12 Guides:
13 
14 There are many articles available that can bolster understanding ranges:
15 
16 $(UL
17     $(LI Ali Çehreli's $(HTTP ddili.org/ders/d.en/ranges.html, tutorial on _ranges)
18         for the basics of working with and creating range-based code.)
19     $(LI Jonathan M. Davis $(LINK2 http://dconf.org/2015/talks/davis.html, $(I Introduction to Ranges))
20         talk at DConf 2015 a vivid introduction from its core constructs to practical advice.)
21     $(LI The DLang Tour's $(LINK2 http://tour.dlang.org/tour/en/basics/ranges, chapter on ranges)
22         for an interactive introduction.)
23     $(LI H. S. Teoh's $(LINK2 http://wiki.dlang.org/Component_programming_with_ranges, tutorial on
24         component programming with ranges) for a real-world showcase of the influence
25         of _range-based programming on complex algorithms.)
26     $(LI Andrei Alexandrescu's article
27         $(LINK2 http://www.informit.com/articles/printerfriendly.aspx?p=1407357$(AMP)rll=1,
28         $(I On Iteration)) for conceptual aspect of ranges and the motivation
29     )
30 )
31 
32 Submodules:
33 
34 This module has two submodules:
35 
36 The $(MREF std, _range, primitives) submodule
37 provides basic _range functionality. It defines several templates for testing
38 whether a given object is a _range, what kind of _range it is, and provides
39 some common _range operations.
40 
41 The $(MREF std, _range, interfaces) submodule
42 provides object-based interfaces for working with ranges via runtime
43 polymorphism.
44 
45 The remainder of this module provides a rich set of _range creation and
46 composition templates that let you construct new ranges out of existing ranges:
47 
48 
49 $(SCRIPT inhibitQuickIndex = 1;)
50 $(BOOKTABLE ,
51     $(TR $(TD $(LREF chain))
52         $(TD Concatenates several ranges into a single _range.
53     ))
54     $(TR $(TD $(LREF choose))
55         $(TD Chooses one of two ranges at runtime based on a boolean condition.
56     ))
57     $(TR $(TD $(LREF chooseAmong))
58         $(TD Chooses one of several ranges at runtime based on an index.
59     ))
60     $(TR $(TD $(LREF chunks))
61         $(TD Creates a _range that returns fixed-size chunks of the original
62         _range.
63     ))
64     $(TR $(TD $(LREF cycle))
65         $(TD Creates an infinite _range that repeats the given forward _range
66         indefinitely. Good for implementing circular buffers.
67     ))
68     $(TR $(TD $(LREF drop))
69         $(TD Creates the _range that results from discarding the first $(I n)
70         elements from the given _range.
71     ))
72     $(TR $(TD $(LREF dropBack))
73         $(TD Creates the _range that results from discarding the last $(I n)
74         elements from the given _range.
75     ))
76     $(TR $(TD $(LREF dropExactly))
77         $(TD Creates the _range that results from discarding exactly $(I n)
78         of the first elements from the given _range.
79     ))
80     $(TR $(TD $(LREF dropBackExactly))
81         $(TD Creates the _range that results from discarding exactly $(I n)
82         of the last elements from the given _range.
83     ))
84     $(TR $(TD $(LREF dropOne))
85         $(TD Creates the _range that results from discarding
86         the first element from the given _range.
87     ))
88     $(TR $(TD $(D $(LREF dropBackOne)))
89         $(TD Creates the _range that results from discarding
90         the last element from the given _range.
91     ))
92     $(TR $(TD $(LREF enumerate))
93         $(TD Iterates a _range with an attached index variable.
94     ))
95     $(TR $(TD $(LREF evenChunks))
96         $(TD Creates a _range that returns a number of chunks of
97         approximately equal length from the original _range.
98     ))
99     $(TR $(TD $(LREF frontTransversal))
100         $(TD Creates a _range that iterates over the first elements of the
101         given ranges.
102     ))
103     $(TR $(TD $(LREF generate))
104         $(TD Creates a _range by successive calls to a given function. This
105         allows to create ranges as a single delegate.
106     ))
107     $(TR $(TD $(LREF indexed))
108         $(TD Creates a _range that offers a view of a given _range as though
109         its elements were reordered according to a given _range of indices.
110     ))
111     $(TR $(TD $(LREF iota))
112         $(TD Creates a _range consisting of numbers between a starting point
113         and ending point, spaced apart by a given interval.
114     ))
115     $(TR $(TD $(LREF lockstep))
116         $(TD Iterates $(I n) _ranges in lockstep, for use in a $(D foreach)
117         loop. Similar to $(D zip), except that $(D lockstep) is designed
118         especially for $(D foreach) loops.
119     ))
120     $(TR $(TD $(LREF NullSink))
121         $(TD An output _range that discards the data it receives.
122     ))
123     $(TR $(TD $(LREF only))
124         $(TD Creates a _range that iterates over the given arguments.
125     ))
126     $(TR $(TD $(LREF padLeft))
127         $(TD Pads a _range to a specified length by adding a given element to
128         the front of the _range. Is lazy if the _range has a known length.
129     ))
130     $(TR $(TD $(LREF padRight))
131         $(TD Lazily pads a _range to a specified length by adding a given element to
132         the back of the _range.
133     ))
134     $(TR $(TD $(LREF radial))
135         $(TD Given a random-access _range and a starting point, creates a
136         _range that alternately returns the next left and next right element to
137         the starting point.
138     ))
139     $(TR $(TD $(LREF recurrence))
140         $(TD Creates a forward _range whose values are defined by a
141         mathematical recurrence relation.
142     ))
143     $(TR $(TD $(LREF refRange))
144         $(TD Pass a _range by reference. Both the original _range and the RefRange
145         will always have the exact same elements.
146         Any operation done on one will affect the other.
147     ))
148     $(TR $(TD $(LREF repeat))
149         $(TD Creates a _range that consists of a single element repeated $(I n)
150         times, or an infinite _range repeating that element indefinitely.
151     ))
152     $(TR $(TD $(LREF retro))
153         $(TD Iterates a bidirectional _range backwards.
154     ))
155     $(TR $(TD $(LREF roundRobin))
156         $(TD Given $(I n) ranges, creates a new _range that return the $(I n)
157         first elements of each _range, in turn, then the second element of each
158         _range, and so on, in a round-robin fashion.
159     ))
160     $(TR $(TD $(LREF sequence))
161         $(TD Similar to $(D recurrence), except that a random-access _range is
162         created.
163     ))
164     $(COMMENT Explicitly undocumented to delay the release until 2.076
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     )
172     $(TR $(TD $(LREF stride))
173         $(TD Iterates a _range with stride $(I n).
174     ))
175     $(TR $(TD $(LREF tail))
176         $(TD Return a _range advanced to within $(D n) elements of the end of
177         the given _range.
178     ))
179     $(TR $(TD $(LREF take))
180         $(TD Creates a sub-_range consisting of only up to the first $(I n)
181         elements of the given _range.
182     ))
183     $(TR $(TD $(LREF takeExactly))
184         $(TD Like $(D take), but assumes the given _range actually has $(I n)
185         elements, and therefore also defines the $(D length) property.
186     ))
187     $(TR $(TD $(LREF takeNone))
188         $(TD Creates a random-access _range consisting of zero elements of the
189         given _range.
190     ))
191     $(TR $(TD $(LREF takeOne))
192         $(TD Creates a random-access _range consisting of exactly the first
193         element of the given _range.
194     ))
195     $(TR $(TD $(LREF tee))
196         $(TD Creates a _range that wraps a given _range, forwarding along
197         its elements while also calling a provided function with each element.
198     ))
199     $(TR $(TD $(LREF transposed))
200         $(TD Transposes a _range of ranges.
201     ))
202     $(TR $(TD $(LREF transversal))
203         $(TD Creates a _range that iterates over the $(I n)'th elements of the
204         given random-access ranges.
205     ))
206     $(TR $(TD $(LREF zip))
207         $(TD Given $(I n) _ranges, creates a _range that successively returns a
208         tuple of all the first elements, a tuple of all the second elements,
209         etc.
210     ))
211 )
212 
213 Sortedness:
214 
215 Ranges whose elements are sorted afford better efficiency with certain
216 operations. For this, the $(LREF assumeSorted) function can be used to
217 construct a $(LREF SortedRange) from a pre-sorted _range. The $(REF
218 sort, std, algorithm, sorting) function also conveniently
219 returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional
220 _range operations that take advantage of the fact that the _range is sorted.
221 
222 Source: $(PHOBOSSRC std/_range/_package.d)
223 
224 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
225 
226 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, Jonathan M Davis,
227 and Jack Stouffer. Credit for some of the ideas in building this module goes
228 to $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
229  */
230 module std.range;
231 
232 public import std.array;
233 public import std.range.interfaces;
234 public import std.range.primitives;
235 public import std.typecons : Flag, Yes, No;
236 
237 import std.meta; // allSatisfy, staticMap
238 import std.traits; // CommonType, isCallable, isFloatingPoint, isIntegral,
239     // isPointer, isSomeFunction, isStaticArray, Unqual
240 
241 
242 /**
243 Iterates a bidirectional range backwards. The original range can be
244 accessed by using the $(D source) property. Applying retro twice to
245 the same range yields the original range.
246 
247 Params:
248     r = the bidirectional range to iterate backwards
249 
250 Returns:
251     A bidirectional range with length if `r` also provides a length. Or,
252     if `r` is a random access range, then the return value will be random
253     access as well.
254 See_Also:
255     $(REF reverse, std,algorithm,mutation) for mutating the source range directly.
256  */
257 auto retro(Range)(Range r)
258 if (isBidirectionalRange!(Unqual!Range))
259 {
260     // Check for retro(retro(r)) and just return r in that case
261     static if (is(typeof(retro(r.source)) == Range))
262     {
263         return r.source;
264     }
265     else
266     {
Result()267         static struct Result()
268         {
269             private alias R = Unqual!Range;
270 
271             // User code can get and set source, too
272             R source;
273 
274             static if (hasLength!R)
275             {
276                 size_t retroIndex(size_t n)
277                 {
278                     return source.length - n - 1;
279                 }
280             }
281 
282         public:
283             alias Source = R;
284 
285             @property bool empty() { return source.empty; }
286             @property auto save()
287             {
288                 return Result(source.save);
289             }
290             @property auto ref front() { return source.back; }
291             void popFront() { source.popBack(); }
292             @property auto ref back() { return source.front; }
293             void popBack() { source.popFront(); }
294 
295             static if (is(typeof(source.moveBack())))
296             {
297                 ElementType!R moveFront()
298                 {
299                     return source.moveBack();
300                 }
301             }
302 
303             static if (is(typeof(source.moveFront())))
304             {
305                 ElementType!R moveBack()
306                 {
307                     return source.moveFront();
308                 }
309             }
310 
311             static if (hasAssignableElements!R)
312             {
313                 @property void front(ElementType!R val)
314                 {
315                     source.back = val;
316                 }
317 
318                 @property void back(ElementType!R val)
319                 {
320                     source.front = val;
321                 }
322             }
323 
324             static if (isRandomAccessRange!(R) && hasLength!(R))
325             {
326                 auto ref opIndex(size_t n) { return source[retroIndex(n)]; }
327 
328                 static if (hasAssignableElements!R)
329                 {
330                     void opIndexAssign(ElementType!R val, size_t n)
331                     {
332                         source[retroIndex(n)] = val;
333                     }
334                 }
335 
336                 static if (is(typeof(source.moveAt(0))))
337                 {
338                     ElementType!R moveAt(size_t index)
339                     {
340                         return source.moveAt(retroIndex(index));
341                     }
342                 }
343 
344                 static if (hasSlicing!R)
345                     typeof(this) opSlice(size_t a, size_t b)
346                     {
347                         return typeof(this)(source[source.length - b .. source.length - a]);
348                     }
349             }
350 
351             static if (hasLength!R)
352             {
353                 @property auto length()
354                 {
355                     return source.length;
356                 }
357 
358                 alias opDollar = length;
359             }
360         }
361 
362         return Result!()(r);
363     }
364 }
365 
366 
367 ///
368 pure @safe nothrow @nogc unittest
369 {
370     import std.algorithm.comparison : equal;
371     int[5] a = [ 1, 2, 3, 4, 5 ];
372     int[5] b = [ 5, 4, 3, 2, 1 ];
373     assert(equal(retro(a[]), b[]));
374     assert(retro(a[]).source is a[]);
375     assert(retro(retro(a[])) is a[]);
376 }
377 
378 pure @safe nothrow unittest
379 {
380     import std.algorithm.comparison : equal;
381     static assert(isBidirectionalRange!(typeof(retro("hello"))));
382     int[] a;
383     static assert(is(typeof(a) == typeof(retro(retro(a)))));
384     assert(retro(retro(a)) is a);
385     static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
test(int[]input,int[]witness)386     void test(int[] input, int[] witness)
387     {
388         auto r = retro(input);
389         assert(r.front == witness.front);
390         assert(r.back == witness.back);
391         assert(equal(r, witness));
392     }
393     test([ 1 ], [ 1 ]);
394     test([ 1, 2 ], [ 2, 1 ]);
395     test([ 1, 2, 3 ], [ 3, 2, 1 ]);
396     test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
397     test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
398     test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
399 
400     immutable foo = [1,2,3].idup;
401     auto r = retro(foo);
402     assert(equal(r, [3, 2, 1]));
403 }
404 
405 pure @safe nothrow unittest
406 {
407     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
408         ReturnBy;
409 
foreach(DummyType;AllDummyRanges)410     foreach (DummyType; AllDummyRanges)
411     {
412         static if (!isBidirectionalRange!DummyType)
413         {
414             static assert(!__traits(compiles, Retro!DummyType));
415         }
416         else
417         {
418             DummyType dummyRange;
419             dummyRange.reinit();
420 
421             auto myRetro = retro(dummyRange);
422             static assert(propagatesRangeType!(typeof(myRetro), DummyType));
423             assert(myRetro.front == 10);
424             assert(myRetro.back == 1);
425             assert(myRetro.moveFront() == 10);
426             assert(myRetro.moveBack() == 1);
427 
428             static if (isRandomAccessRange!DummyType && hasLength!DummyType)
429             {
430                 assert(myRetro[0] == myRetro.front);
431                 assert(myRetro.moveAt(2) == 8);
432 
433                 static if (DummyType.r == ReturnBy.Reference)
434                 {
435                     {
436                         myRetro[9]++;
437                         scope(exit) myRetro[9]--;
438                         assert(dummyRange[0] == 2);
439                         myRetro.front++;
440                         scope(exit) myRetro.front--;
441                         assert(myRetro.front == 11);
442                         myRetro.back++;
443                         scope(exit) myRetro.back--;
444                         assert(myRetro.back == 3);
445                     }
446 
447                     {
448                         myRetro.front = 0xFF;
449                         scope(exit) myRetro.front = 10;
450                         assert(dummyRange.back == 0xFF);
451 
452                         myRetro.back = 0xBB;
453                         scope(exit) myRetro.back = 1;
454                         assert(dummyRange.front == 0xBB);
455 
456                         myRetro[1] = 11;
457                         scope(exit) myRetro[1] = 8;
458                         assert(dummyRange[8] == 11);
459                     }
460                 }
461             }
462         }
463     }
464 }
465 
466 pure @safe nothrow @nogc unittest
467 {
468     import std.algorithm.comparison : equal;
469     auto LL = iota(1L, 4L);
470     auto r = retro(LL);
471     long[3] excepted = [3, 2, 1];
472     assert(equal(r, excepted[]));
473 }
474 
475 // Issue 12662
476 pure @safe nothrow @nogc unittest
477 {
478     int[3] src = [1,2,3];
479     int[] data = src[];
foreach_reverse(x;data)480     foreach_reverse (x; data) {}
481     foreach (x; data.retro) {}
482 }
483 
484 
485 /**
486 Iterates range $(D r) with stride $(D n). If the range is a
487 random-access range, moves by indexing into the range; otherwise,
488 moves by successive calls to $(D popFront). Applying stride twice to
489 the same range results in a stride with a step that is the
490 product of the two applications. It is an error for $(D n) to be 0.
491 
492 Params:
493     r = the input range to stride over
494     n = the number of elements to skip over
495 
496 Returns:
497     At minimum, an input range. The resulting range will adopt the
498     range primitives of the underlying range as long as
499     $(REF hasLength, std,range,primitives) is `true`.
500  */
501 auto stride(Range)(Range r, size_t n)
502 if (isInputRange!(Unqual!Range))
503 in
504 {
505     assert(n != 0, "stride cannot have step zero.");
506 }
507 body
508 {
509     import std.algorithm.comparison : min;
510 
511     static if (is(typeof(stride(r.source, n)) == Range))
512     {
513         // stride(stride(r, n1), n2) is stride(r, n1 * n2)
514         return stride(r.source, r._n * n);
515     }
516     else
517     {
518         static struct Result
519         {
520             private alias R = Unqual!Range;
521             public R source;
522             private size_t _n;
523 
524             // Chop off the slack elements at the end
525             static if (hasLength!R &&
526                     (isRandomAccessRange!R && hasSlicing!R
527                             || isBidirectionalRange!R))
eliminateSlackElementsResult528                 private void eliminateSlackElements()
529                 {
530                     auto slack = source.length % _n;
531 
532                     if (slack)
533                     {
534                         slack--;
535                     }
536                     else if (!source.empty)
537                     {
538                         slack = min(_n, source.length) - 1;
539                     }
540                     else
541                     {
542                         slack = 0;
543                     }
544                     if (!slack) return;
545                     static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
546                     {
547                         source = source[0 .. source.length - slack];
548                     }
549                     else static if (isBidirectionalRange!R)
550                     {
551                         foreach (i; 0 .. slack)
552                         {
553                             source.popBack();
554                         }
555                     }
556                 }
557 
558             static if (isForwardRange!R)
559             {
saveResult560                 @property auto save()
561                 {
562                     return Result(source.save, _n);
563                 }
564             }
565 
566             static if (isInfinite!R)
567             {
568                 enum bool empty = false;
569             }
570             else
571             {
emptyResult572                 @property bool empty()
573                 {
574                     return source.empty;
575                 }
576             }
577 
frontResult578             @property auto ref front()
579             {
580                 return source.front;
581             }
582 
583             static if (is(typeof(.moveFront(source))))
584             {
585                 ElementType!R moveFront()
586                 {
587                     return source.moveFront();
588                 }
589             }
590 
591             static if (hasAssignableElements!R)
592             {
593                 @property void front(ElementType!R val)
594                 {
595                     source.front = val;
596                 }
597             }
598 
popFrontResult599             void popFront()
600             {
601                 source.popFrontN(_n);
602             }
603 
604             static if (isBidirectionalRange!R && hasLength!R)
605             {
popBackResult606                 void popBack()
607                 {
608                     popBackN(source, _n);
609                 }
610 
backResult611                 @property auto ref back()
612                 {
613                     eliminateSlackElements();
614                     return source.back;
615                 }
616 
617                 static if (is(typeof(.moveBack(source))))
618                 {
619                     ElementType!R moveBack()
620                     {
621                         eliminateSlackElements();
622                         return source.moveBack();
623                     }
624                 }
625 
626                 static if (hasAssignableElements!R)
627                 {
628                     @property void back(ElementType!R val)
629                     {
630                         eliminateSlackElements();
631                         source.back = val;
632                     }
633                 }
634             }
635 
636             static if (isRandomAccessRange!R && hasLength!R)
637             {
opIndexResult638                 auto ref opIndex(size_t n)
639                 {
640                     return source[_n * n];
641                 }
642 
643                 /**
644                    Forwards to $(D moveAt(source, n)).
645                 */
646                 static if (is(typeof(source.moveAt(0))))
647                 {
648                     ElementType!R moveAt(size_t n)
649                     {
650                         return source.moveAt(_n * n);
651                     }
652                 }
653 
654                 static if (hasAssignableElements!R)
655                 {
656                     void opIndexAssign(ElementType!R val, size_t n)
657                     {
658                         source[_n * n] = val;
659                     }
660                 }
661             }
662 
663             static if (hasSlicing!R && hasLength!R)
opSliceResult664                 typeof(this) opSlice(size_t lower, size_t upper)
665                 {
666                     assert(upper >= lower && upper <= length);
667                     immutable translatedUpper = (upper == 0) ? 0 :
668                         (upper * _n - (_n - 1));
669                     immutable translatedLower = min(lower * _n, translatedUpper);
670 
671                     assert(translatedLower <= translatedUpper);
672 
673                     return typeof(this)(source[translatedLower .. translatedUpper], _n);
674                 }
675 
676             static if (hasLength!R)
677             {
lengthResult678                 @property auto length()
679                 {
680                     return (source.length + _n - 1) / _n;
681                 }
682 
683                 alias opDollar = length;
684             }
685         }
686         return Result(r, n);
687     }
688 }
689 
690 ///
691 pure @safe nothrow unittest
692 {
693     import std.algorithm.comparison : equal;
694 
695     int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
696     assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
697     assert(stride(stride(a, 2), 3) == stride(a, 6));
698 }
699 
700 pure @safe nothrow @nogc unittest
701 {
702     import std.algorithm.comparison : equal;
703 
704     int[4] testArr = [1,2,3,4];
705     static immutable result = [1, 3];
706     assert(equal(testArr[].stride(2), result));
707 }
708 
709 debug pure nothrow @system unittest
710 {//check the contract
711     int[4] testArr = [1,2,3,4];
712     bool passed = false;
713     scope (success) assert(passed);
714     import core.exception : AssertError;
715     //std.exception.assertThrown won't do because it can't infer nothrow
716     // @@@BUG@@@ 12647
717     try
718     {
719         auto unused = testArr[].stride(0);
720     }
catch(AssertError unused)721     catch (AssertError unused)
722     {
723         passed = true;
724     }
725 }
726 
727 pure @safe nothrow unittest
728 {
729     import std.algorithm.comparison : equal;
730     import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
731         ReturnBy;
732 
733     static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
test(size_t n,int[]input,int[]witness)734     void test(size_t n, int[] input, int[] witness)
735     {
736         assert(equal(stride(input, n), witness));
737     }
738     test(1, [], []);
739     int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
740     assert(stride(stride(arr, 2), 3) is stride(arr, 6));
741     test(1, arr, arr);
742     test(2, arr, [1, 3, 5, 7, 9]);
743     test(3, arr, [1, 4, 7, 10]);
744     test(4, arr, [1, 5, 9]);
745 
746     // Test slicing.
747     auto s1 = stride(arr, 1);
748     assert(equal(s1[1 .. 4], [2, 3, 4]));
749     assert(s1[1 .. 4].length == 3);
750     assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
751     assert(s1[1 .. 5].length == 4);
752     assert(s1[0 .. 0].empty);
753     assert(s1[3 .. 3].empty);
754     // assert(s1[$ .. $].empty);
755     assert(s1[s1.opDollar .. s1.opDollar].empty);
756 
757     auto s2 = stride(arr, 2);
758     assert(equal(s2[0 .. 2], [1,3]));
759     assert(s2[0 .. 2].length == 2);
760     assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
761     assert(s2[1 .. 5].length == 4);
762     assert(s2[0 .. 0].empty);
763     assert(s2[3 .. 3].empty);
764     // assert(s2[$ .. $].empty);
765     assert(s2[s2.opDollar .. s2.opDollar].empty);
766 
767     // Test fix for Bug 5035
768     auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
769     auto col = stride(m, 4);
770     assert(equal(col, [1, 1, 1]));
771     assert(equal(retro(col), [1, 1, 1]));
772 
773     immutable int[] immi = [ 1, 2, 3 ];
774     static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
775 
776     // Check for infiniteness propagation.
777     static assert(isInfinite!(typeof(stride(repeat(1), 3))));
778 
foreach(DummyType;AllDummyRanges)779     foreach (DummyType; AllDummyRanges)
780     {
781         DummyType dummyRange;
782         dummyRange.reinit();
783 
784         auto myStride = stride(dummyRange, 4);
785 
786         // Should fail if no length and bidirectional b/c there's no way
787         // to know how much slack we have.
788         static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
789         {
790             static assert(propagatesRangeType!(typeof(myStride), DummyType));
791         }
792         assert(myStride.front == 1);
793         assert(myStride.moveFront() == 1);
794         assert(equal(myStride, [1, 5, 9]));
795 
796         static if (hasLength!DummyType)
797         {
798             assert(myStride.length == 3);
799         }
800 
801         static if (isBidirectionalRange!DummyType && hasLength!DummyType)
802         {
803             assert(myStride.back == 9);
804             assert(myStride.moveBack() == 9);
805         }
806 
807         static if (isRandomAccessRange!DummyType && hasLength!DummyType)
808         {
809             assert(myStride[0] == 1);
810             assert(myStride[1] == 5);
811             assert(myStride.moveAt(1) == 5);
812             assert(myStride[2] == 9);
813 
814             static assert(hasSlicing!(typeof(myStride)));
815         }
816 
817         static if (DummyType.r == ReturnBy.Reference)
818         {
819             // Make sure reference is propagated.
820 
821             {
822                 myStride.front++;
823                 scope(exit) myStride.front--;
824                 assert(dummyRange.front == 2);
825             }
826             {
827                 myStride.front = 4;
828                 scope(exit) myStride.front = 1;
829                 assert(dummyRange.front == 4);
830             }
831 
832             static if (isBidirectionalRange!DummyType && hasLength!DummyType)
833             {
834                 {
835                     myStride.back++;
836                     scope(exit) myStride.back--;
837                     assert(myStride.back == 10);
838                 }
839                 {
840                     myStride.back = 111;
841                     scope(exit) myStride.back = 9;
842                     assert(myStride.back == 111);
843                 }
844 
845                 static if (isRandomAccessRange!DummyType)
846                 {
847                     {
848                         myStride[1]++;
849                         scope(exit) myStride[1]--;
850                         assert(dummyRange[4] == 6);
851                     }
852                     {
853                         myStride[1] = 55;
854                         scope(exit) myStride[1] = 5;
855                         assert(dummyRange[4] == 55);
856                     }
857                 }
858             }
859         }
860     }
861 }
862 
863 pure @safe nothrow unittest
864 {
865     import std.algorithm.comparison : equal;
866 
867     auto LL = iota(1L, 10L);
868     auto s = stride(LL, 3);
869     assert(equal(s, [1L, 4L, 7L]));
870 }
871 
872 /**
873 Spans multiple ranges in sequence. The function $(D chain) takes any
874 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
875 ranges may be different, but they must have the same element type. The
876 result is a range that offers the $(D front), $(D popFront), and $(D
877 empty) primitives. If all input ranges offer random access and $(D
878 length), $(D Chain) offers them as well.
879 
880 If only one range is offered to $(D Chain) or $(D chain), the $(D
881 Chain) type exits the picture by aliasing itself directly to that
882 range's type.
883 
884 Params:
885     rs = the input ranges to chain together
886 
887 Returns:
888     An input range at minimum. If all of the ranges in `rs` provide
889     a range primitive, the returned range will also provide that range
890     primitive.
891 
892 See_Also: $(LREF only) to chain values to a range
893  */
894 auto chain(Ranges...)(Ranges rs)
895 if (Ranges.length > 0 &&
896     allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
897     !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
898 {
899     static if (Ranges.length == 1)
900     {
901         return rs[0];
902     }
903     else
904     {
905         static struct Result
906         {
907         private:
908             alias R = staticMap!(Unqual, Ranges);
909             alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
sameETResult910             private template sameET(A)
911             {
912                 enum sameET = is(.ElementType!A == RvalueElementType);
913             }
914 
915             enum bool allSameType = allSatisfy!(sameET, R);
916 
917             // This doesn't work yet
918             static if (allSameType)
919             {
920                 alias ElementType = ref RvalueElementType;
921             }
922             else
923             {
924                 alias ElementType = RvalueElementType;
925             }
926             static if (allSameType && allSatisfy!(hasLvalueElements, R))
927             {
fixRefResult928                 static ref RvalueElementType fixRef(ref RvalueElementType val)
929                 {
930                     return val;
931                 }
932             }
933             else
934             {
fixRefResult935                 static RvalueElementType fixRef(RvalueElementType val)
936                 {
937                     return val;
938                 }
939             }
940 
941             // This is the entire state
942             R source;
943             // TODO: use a vtable (or more) instead of linear iteration
944 
945         public:
thisResult946             this(R input)
947             {
948                 foreach (i, v; input)
949                 {
950                     source[i] = v;
951                 }
952             }
953 
954             import std.meta : anySatisfy;
955 
956             static if (anySatisfy!(isInfinite, R))
957             {
958                 // Propagate infiniteness.
959                 enum bool empty = false;
960             }
961             else
962             {
emptyResult963                 @property bool empty()
964                 {
965                     foreach (i, Unused; R)
966                     {
967                         if (!source[i].empty) return false;
968                     }
969                     return true;
970                 }
971             }
972 
973             static if (allSatisfy!(isForwardRange, R))
saveResult974                 @property auto save()
975                 {
976                     typeof(this) result = this;
977                     foreach (i, Unused; R)
978                     {
979                         result.source[i] = result.source[i].save;
980                     }
981                     return result;
982                 }
983 
popFrontResult984             void popFront()
985             {
986                 foreach (i, Unused; R)
987                 {
988                     if (source[i].empty) continue;
989                     source[i].popFront();
990                     return;
991                 }
992             }
993 
frontResult994             @property auto ref front()
995             {
996                 foreach (i, Unused; R)
997                 {
998                     if (source[i].empty) continue;
999                     return fixRef(source[i].front);
1000                 }
1001                 assert(false);
1002             }
1003 
1004             static if (allSameType && allSatisfy!(hasAssignableElements, R))
1005             {
1006                 // @@@BUG@@@
1007                 //@property void front(T)(T v) if (is(T : RvalueElementType))
1008 
frontResult1009                 @property void front(RvalueElementType v)
1010                 {
1011                     foreach (i, Unused; R)
1012                     {
1013                         if (source[i].empty) continue;
1014                         source[i].front = v;
1015                         return;
1016                     }
1017                     assert(false);
1018                 }
1019             }
1020 
1021             static if (allSatisfy!(hasMobileElements, R))
1022             {
moveFrontResult1023                 RvalueElementType moveFront()
1024                 {
1025                     foreach (i, Unused; R)
1026                     {
1027                         if (source[i].empty) continue;
1028                         return source[i].moveFront();
1029                     }
1030                     assert(false);
1031                 }
1032             }
1033 
1034             static if (allSatisfy!(isBidirectionalRange, R))
1035             {
backResult1036                 @property auto ref back()
1037                 {
1038                     foreach_reverse (i, Unused; R)
1039                     {
1040                         if (source[i].empty) continue;
1041                         return fixRef(source[i].back);
1042                     }
1043                     assert(false);
1044                 }
1045 
popBackResult1046                 void popBack()
1047                 {
1048                     foreach_reverse (i, Unused; R)
1049                     {
1050                         if (source[i].empty) continue;
1051                         source[i].popBack();
1052                         return;
1053                     }
1054                 }
1055 
1056                 static if (allSatisfy!(hasMobileElements, R))
1057                 {
moveBackResult1058                     RvalueElementType moveBack()
1059                     {
1060                         foreach_reverse (i, Unused; R)
1061                         {
1062                             if (source[i].empty) continue;
1063                             return source[i].moveBack();
1064                         }
1065                         assert(false);
1066                     }
1067                 }
1068 
1069                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1070                 {
backResult1071                     @property void back(RvalueElementType v)
1072                     {
1073                         foreach_reverse (i, Unused; R)
1074                         {
1075                             if (source[i].empty) continue;
1076                             source[i].back = v;
1077                             return;
1078                         }
1079                         assert(false);
1080                     }
1081                 }
1082             }
1083 
1084             static if (allSatisfy!(hasLength, R))
1085             {
lengthResult1086                 @property size_t length()
1087                 {
1088                     size_t result;
1089                     foreach (i, Unused; R)
1090                     {
1091                         result += source[i].length;
1092                     }
1093                     return result;
1094                 }
1095 
1096                 alias opDollar = length;
1097             }
1098 
1099             static if (allSatisfy!(isRandomAccessRange, R))
1100             {
opIndexResult1101                 auto ref opIndex(size_t index)
1102                 {
1103                     foreach (i, Range; R)
1104                     {
1105                         static if (isInfinite!(Range))
1106                         {
1107                             return source[i][index];
1108                         }
1109                         else
1110                         {
1111                             immutable length = source[i].length;
1112                             if (index < length) return fixRef(source[i][index]);
1113                             index -= length;
1114                         }
1115                     }
1116                     assert(false);
1117                 }
1118 
1119                 static if (allSatisfy!(hasMobileElements, R))
1120                 {
moveAtResult1121                     RvalueElementType moveAt(size_t index)
1122                     {
1123                         foreach (i, Range; R)
1124                         {
1125                             static if (isInfinite!(Range))
1126                             {
1127                                 return source[i].moveAt(index);
1128                             }
1129                             else
1130                             {
1131                                 immutable length = source[i].length;
1132                                 if (index < length) return source[i].moveAt(index);
1133                                 index -= length;
1134                             }
1135                         }
1136                         assert(false);
1137                     }
1138                 }
1139 
1140                 static if (allSameType && allSatisfy!(hasAssignableElements, R))
opIndexAssignResult1141                     void opIndexAssign(ElementType v, size_t index)
1142                     {
1143                         foreach (i, Range; R)
1144                         {
1145                             static if (isInfinite!(Range))
1146                             {
1147                                 source[i][index] = v;
1148                             }
1149                             else
1150                             {
1151                                 immutable length = source[i].length;
1152                                 if (index < length)
1153                                 {
1154                                     source[i][index] = v;
1155                                     return;
1156                                 }
1157                                 index -= length;
1158                             }
1159                         }
1160                         assert(false);
1161                     }
1162             }
1163 
1164             static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
opSliceResult1165                 auto opSlice(size_t begin, size_t end)
1166                 {
1167                     auto result = this;
1168                     foreach (i, Unused; R)
1169                     {
1170                         immutable len = result.source[i].length;
1171                         if (len < begin)
1172                         {
1173                             result.source[i] = result.source[i]
1174                                 [len .. len];
1175                             begin -= len;
1176                         }
1177                         else
1178                         {
1179                             result.source[i] = result.source[i]
1180                                 [begin .. len];
1181                             break;
1182                         }
1183                     }
1184                     auto cut = length;
1185                     cut = cut <= end ? 0 : cut - end;
1186                     foreach_reverse (i, Unused; R)
1187                     {
1188                         immutable len = result.source[i].length;
1189                         if (cut > len)
1190                         {
1191                             result.source[i] = result.source[i]
1192                                 [0 .. 0];
1193                             cut -= len;
1194                         }
1195                         else
1196                         {
1197                             result.source[i] = result.source[i]
1198                                 [0 .. len - cut];
1199                             break;
1200                         }
1201                     }
1202                     return result;
1203                 }
1204         }
1205         return Result(rs);
1206     }
1207 }
1208 
1209 ///
1210 pure @safe nothrow unittest
1211 {
1212     import std.algorithm.comparison : equal;
1213 
1214     int[] arr1 = [ 1, 2, 3, 4 ];
1215     int[] arr2 = [ 5, 6 ];
1216     int[] arr3 = [ 7 ];
1217     auto s = chain(arr1, arr2, arr3);
1218     assert(s.length == 7);
1219     assert(s[5] == 6);
1220     assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1221 }
1222 
1223 /**
1224  * Range primitives are carried over to the returned range if
1225  * all of the ranges provide them
1226  */
1227 pure @safe nothrow unittest
1228 {
1229     import std.algorithm.comparison : equal;
1230     import std.algorithm.sorting : sort;
1231 
1232     int[] arr1 = [5, 2, 8];
1233     int[] arr2 = [3, 7, 9];
1234     int[] arr3 = [1, 4, 6];
1235 
1236     // in-place sorting across all of the arrays
1237     auto s = arr1.chain(arr2, arr3).sort;
1238 
1239     assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1240     assert(arr1.equal([1, 2, 3]));
1241     assert(arr2.equal([4, 5, 6]));
1242     assert(arr3.equal([7, 8, 9]));
1243 }
1244 
1245 pure @safe nothrow unittest
1246 {
1247     import std.algorithm.comparison : equal;
1248     import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1249                                           propagatesRangeType;
1250 
1251     {
1252         int[] arr1 = [ 1, 2, 3, 4 ];
1253         int[] arr2 = [ 5, 6 ];
1254         int[] arr3 = [ 7 ];
1255         int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1256         auto s1 = chain(arr1);
1257         static assert(isRandomAccessRange!(typeof(s1)));
1258         auto s2 = chain(arr1, arr2);
1259         static assert(isBidirectionalRange!(typeof(s2)));
1260         static assert(isRandomAccessRange!(typeof(s2)));
1261         s2.front = 1;
1262         auto s = chain(arr1, arr2, arr3);
1263         assert(s[5] == 6);
1264         assert(equal(s, witness));
1265         assert(s[5] == 6);
1266     }
1267     {
1268         int[] arr1 = [ 1, 2, 3, 4 ];
1269         int[] witness = [ 1, 2, 3, 4 ];
1270         assert(equal(chain(arr1), witness));
1271     }
1272     {
1273         uint[] foo = [1,2,3,4,5];
1274         uint[] bar = [1,2,3,4,5];
1275         auto c = chain(foo, bar);
1276         c[3] = 42;
1277         assert(c[3] == 42);
1278         assert(c.moveFront() == 1);
1279         assert(c.moveBack() == 5);
1280         assert(c.moveAt(4) == 5);
1281         assert(c.moveAt(5) == 1);
1282     }
1283 
1284     // Make sure bug 3311 is fixed.  ChainImpl should compile even if not all
1285     // elements are mutable.
1286     assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1287 
1288     // Test the case where infinite ranges are present.
1289     auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1290     assert(inf[0] == 0);
1291     assert(inf[3] == 4);
1292     assert(inf[6] == 4);
1293     assert(inf[7] == 5);
1294     static assert(isInfinite!(typeof(inf)));
1295 
1296     immutable int[] immi = [ 1, 2, 3 ];
1297     immutable float[] immf = [ 1, 2, 3 ];
1298     static assert(is(typeof(chain(immi, immf))));
1299 
1300     // Check that chain at least instantiates and compiles with every possible
1301     // pair of DummyRange types, in either order.
1302 
foreach(DummyType1;AllDummyRanges)1303     foreach (DummyType1; AllDummyRanges)
1304     {
1305         DummyType1 dummy1;
1306         foreach (DummyType2; AllDummyRanges)
1307         {
1308             DummyType2 dummy2;
1309             auto myChain = chain(dummy1, dummy2);
1310 
1311             static assert(
1312                 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1313             );
1314 
1315             assert(myChain.front == 1);
1316             foreach (i; 0 .. dummyLength)
1317             {
1318                 myChain.popFront();
1319             }
1320             assert(myChain.front == 1);
1321 
1322             static if (isBidirectionalRange!DummyType1 &&
1323                       isBidirectionalRange!DummyType2) {
1324                 assert(myChain.back == 10);
1325             }
1326 
1327             static if (isRandomAccessRange!DummyType1 &&
1328                       isRandomAccessRange!DummyType2) {
1329                 assert(myChain[0] == 1);
1330             }
1331 
1332             static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1333             {
1334                 static assert(hasLvalueElements!(typeof(myChain)));
1335             }
1336             else
1337             {
1338                 static assert(!hasLvalueElements!(typeof(myChain)));
1339             }
1340         }
1341     }
1342 }
1343 
1344 pure @safe nothrow @nogc unittest
1345 {
1346     class Foo{}
1347     immutable(Foo)[] a;
1348     immutable(Foo)[] b;
1349     assert(chain(a, b).empty);
1350 }
1351 
1352 /**
1353 Choose one of two ranges at runtime depending on a Boolean condition.
1354 
1355 The ranges may be different, but they must have compatible element types (i.e.
1356 $(D CommonType) must exist for the two element types). The result is a range
1357 that offers the weakest capabilities of the two (e.g. $(D ForwardRange) if $(D
1358 R1) is a random-access range and $(D R2) is a forward range).
1359 
1360 Params:
1361     condition = which range to choose: $(D r1) if $(D true), $(D r2) otherwise
1362     r1 = the "true" range
1363     r2 = the "false" range
1364 
1365 Returns:
1366     A range type dependent on $(D R1) and $(D R2).
1367 
1368 Bugs:
1369     $(BUGZILLA 14660)
1370  */
1371 auto choose(R1, R2)(bool condition, R1 r1, R2 r2)
1372 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1373     !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1374 {
1375     static struct Result
1376     {
1377         import std.algorithm.comparison : max;
1378         import std.algorithm.internal : addressOf;
1379         import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor;
1380 
1381         private union
1382         {
1383             void[max(R1.sizeof, R2.sizeof)] buffer = void;
1384             void* forAlignmentOnly = void;
1385         }
1386         private bool condition;
r1Result1387         private @property ref R1 r1()
1388         {
1389             assert(condition);
1390             return *cast(R1*) buffer.ptr;
1391         }
r2Result1392         private @property ref R2 r2()
1393         {
1394             assert(!condition);
1395             return *cast(R2*) buffer.ptr;
1396         }
1397 
thisResult1398         this(bool condition, R1 r1, R2 r2)
1399         {
1400             this.condition = condition;
1401             import std.conv : emplace;
1402             if (condition) emplace(addressOf(this.r1), r1);
1403             else emplace(addressOf(this.r2), r2);
1404         }
1405 
1406         // Carefully defined postblit to postblit the appropriate range
1407         static if (hasElaborateCopyConstructor!R1
1408             || hasElaborateCopyConstructor!R2)
thisResult1409         this(this)
1410         {
1411             if (condition)
1412             {
1413                 static if (hasElaborateCopyConstructor!R1) r1.__postblit();
1414             }
1415             else
1416             {
1417                 static if (hasElaborateCopyConstructor!R2) r2.__postblit();
1418             }
1419         }
1420 
1421         static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2)
~thisResult1422         ~this()
1423         {
1424             if (condition) destroy(r1);
1425             else destroy(r2);
1426         }
1427 
1428         static if (isInfinite!R1 && isInfinite!R2)
1429             // Propagate infiniteness.
1430             enum bool empty = false;
1431         else
emptyResult1432             @property bool empty()
1433             {
1434                 return condition ? r1.empty : r2.empty;
1435             }
1436 
frontResult1437         @property auto ref front()
1438         {
1439             return condition ? r1.front : r2.front;
1440         }
1441 
popFrontResult1442         void popFront()
1443         {
1444             return condition ? r1.popFront : r2.popFront;
1445         }
1446 
1447         static if (isForwardRange!R1 && isForwardRange!R2)
saveResult1448             @property auto save()
1449             {
1450                 auto result = this;
1451                 if (condition) r1 = r1.save;
1452                 else r2 = r2.save;
1453                 return result;
1454             }
1455 
1456         @property void front(T)(T v)
1457         if (is(typeof({ r1.front = v; r2.front = v; })))
1458         {
1459             if (condition) r1.front = v; else r2.front = v;
1460         }
1461 
1462         static if (hasMobileElements!R1 && hasMobileElements!R2)
moveFrontResult1463             auto moveFront()
1464             {
1465                 return condition ? r1.moveFront : r2.moveFront;
1466             }
1467 
1468         static if (isBidirectionalRange!R1 && isBidirectionalRange!R2)
1469         {
backResult1470             @property auto ref back()
1471             {
1472                 return condition ? r1.back : r2.back;
1473             }
1474 
popBackResult1475             void popBack()
1476             {
1477                 return condition ? r1.popBack : r2.popBack;
1478             }
1479 
1480             static if (hasMobileElements!R1 && hasMobileElements!R2)
moveBackResult1481                 auto moveBack()
1482                 {
1483                     return condition ? r1.moveBack : r2.moveBack;
1484                 }
1485 
1486             @property void back(T)(T v)
1487             if (is(typeof({ r1.back = v; r2.back = v; })))
1488             {
1489                 if (condition) r1.back = v; else r2.back = v;
1490             }
1491         }
1492 
1493         static if (hasLength!R1 && hasLength!R2)
1494         {
lengthResult1495             @property size_t length()
1496             {
1497                 return condition ? r1.length : r2.length;
1498             }
1499             alias opDollar = length;
1500         }
1501 
1502         static if (isRandomAccessRange!R1 && isRandomAccessRange!R2)
1503         {
opIndexResult1504             auto ref opIndex(size_t index)
1505             {
1506                 return condition ? r1[index] : r2[index];
1507             }
1508 
1509             static if (hasMobileElements!R1 && hasMobileElements!R2)
moveAtResult1510                 auto moveAt(size_t index)
1511                 {
1512                     return condition ? r1.moveAt(index) : r2.moveAt(index);
1513                 }
1514 
1515             void opIndexAssign(T)(T v, size_t index)
1516             if (is(typeof({ r1[1] = v; r2[1] = v; })))
1517             {
1518                 if (condition) r1[index] = v; else r2[index] = v;
1519             }
1520         }
1521 
1522         // BUG: this should work for infinite ranges, too
1523         static if (hasSlicing!R1 && hasSlicing!R2 &&
1524                 !isInfinite!R2 && !isInfinite!R2)
opSliceResult1525             auto opSlice(size_t begin, size_t end)
1526             {
1527                 auto result = this;
1528                 if (condition) result.r1 = result.r1[begin .. end];
1529                 else result.r2 = result.r2[begin .. end];
1530                 return result;
1531             }
1532     }
1533     return Result(condition, r1, r2);
1534 }
1535 
1536 ///
1537 @system unittest
1538 {
1539     import std.algorithm.comparison : equal;
1540     import std.algorithm.iteration : filter, map;
1541 
1542     auto data1 = [ 1, 2, 3, 4 ].filter!(a => a != 3);
1543     auto data2 = [ 5, 6, 7, 8 ].map!(a => a + 1);
1544 
1545     // choose() is primarily useful when you need to select one of two ranges
1546     // with different types at runtime.
1547     static assert(!is(typeof(data1) == typeof(data2)));
1548 
chooseRange(bool pickFirst)1549     auto chooseRange(bool pickFirst)
1550     {
1551         // The returned range is a common wrapper type that can be used for
1552         // returning or storing either range without running into a type error.
1553         return choose(pickFirst, data1, data2);
1554 
1555         // Simply returning the chosen range without using choose() does not
1556         // work, because map() and filter() return different types.
1557         //return pickFirst ? data1 : data2; // does not compile
1558     }
1559 
1560     auto result = chooseRange(true);
1561     assert(result.equal([ 1, 2, 4 ]));
1562 
1563     result = chooseRange(false);
1564     assert(result.equal([ 6, 7, 8, 9 ]));
1565 }
1566 
1567 /**
1568 Choose one of multiple ranges at runtime.
1569 
1570 The ranges may be different, but they must have compatible element types. The
1571 result is a range that offers the weakest capabilities of all $(D Ranges).
1572 
1573 Params:
1574     index = which range to choose, must be less than the number of ranges
1575     rs = two or more ranges
1576 
1577 Returns:
1578     The indexed range. If rs consists of only one range, the return type is an
1579     alias of that range's type.
1580  */
1581 auto chooseAmong(Ranges...)(size_t index, Ranges rs)
1582 if (Ranges.length >= 2
1583         && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
1584         && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
1585 {
1586     static if (Ranges.length == 2)
1587         return choose(index == 0, rs[0], rs[1]);
1588     else
1589         return choose(index == 0, rs[0], chooseAmong(index - 1, rs[1 .. $]));
1590 }
1591 
1592 ///
1593 @system unittest
1594 {
1595     import std.algorithm.comparison : equal;
1596 
1597     int[] arr1 = [ 1, 2, 3, 4 ];
1598     int[] arr2 = [ 5, 6 ];
1599     int[] arr3 = [ 7 ];
1600 
1601     {
1602         auto s = chooseAmong(0, arr1, arr2, arr3);
1603         auto t = s.save;
1604         assert(s.length == 4);
1605         assert(s[2] == 3);
1606         s.popFront();
1607         assert(equal(t, [1, 2, 3, 4][]));
1608     }
1609     {
1610         auto s = chooseAmong(1, arr1, arr2, arr3);
1611         assert(s.length == 2);
1612         s.front = 8;
1613         assert(equal(s, [8, 6][]));
1614     }
1615     {
1616         auto s = chooseAmong(1, arr1, arr2, arr3);
1617         assert(s.length == 2);
1618         s[1] = 9;
1619         assert(equal(s, [8, 9][]));
1620     }
1621     {
1622         auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
1623         assert(s.length == 2);
1624         assert(equal(s, [2, 3][]));
1625     }
1626     {
1627         auto s = chooseAmong(0, arr1, arr2, arr3);
1628         assert(s.length == 4);
1629         assert(s.back == 4);
1630         s.popBack();
1631         s.back = 5;
1632         assert(equal(s, [1, 2, 5][]));
1633         s.back = 3;
1634         assert(equal(s, [1, 2, 3][]));
1635     }
1636     {
1637         uint[] foo = [1,2,3,4,5];
1638         uint[] bar = [6,7,8,9,10];
1639         auto c = chooseAmong(1,foo, bar);
1640         assert(c[3] == 9);
1641         c[3] = 42;
1642         assert(c[3] == 42);
1643         assert(c.moveFront() == 6);
1644         assert(c.moveBack() == 10);
1645         assert(c.moveAt(4) == 10);
1646     }
1647     {
1648         import std.range : cycle;
1649         auto s = chooseAmong(1, cycle(arr2), cycle(arr3));
1650         assert(isInfinite!(typeof(s)));
1651         assert(!s.empty);
1652         assert(s[100] == 7);
1653     }
1654 }
1655 
1656 @system unittest
1657 {
1658     int[] a = [1, 2, 3];
1659     long[] b = [4, 5, 6];
1660     auto c = chooseAmong(0, a, b);
1661     c[0] = 42;
1662     assert(c[0] == 42);
1663 }
1664 
1665 
1666 /**
1667 $(D roundRobin(r1, r2, r3)) yields $(D r1.front), then $(D r2.front),
1668 then $(D r3.front), after which it pops off one element from each and
1669 continues again from $(D r1). For example, if two ranges are involved,
1670 it alternately yields elements off the two ranges. $(D roundRobin)
1671 stops after it has consumed all ranges (skipping over the ones that
1672 finish early).
1673  */
1674 auto roundRobin(Rs...)(Rs rs)
1675 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
1676 {
1677     struct Result
1678     {
1679         import std.conv : to;
1680 
1681         public Rs source;
1682         private size_t _current = size_t.max;
1683 
emptyResult1684         @property bool empty()
1685         {
1686             foreach (i, Unused; Rs)
1687             {
1688                 if (!source[i].empty) return false;
1689             }
1690             return true;
1691         }
1692 
frontResult1693         @property auto ref front()
1694         {
1695             final switch (_current)
1696             {
1697                 foreach (i, R; Rs)
1698                 {
1699                     case i:
1700                         assert(
1701                             !source[i].empty,
1702                             "Attempting to fetch the front of an empty roundRobin"
1703                         );
1704                         return source[i].front;
1705                 }
1706             }
1707             assert(0);
1708         }
1709 
popFrontResult1710         void popFront()
1711         {
1712             final switch (_current)
1713             {
1714                 foreach (i, R; Rs)
1715                 {
1716                     case i:
1717                         source[i].popFront();
1718                         break;
1719                 }
1720             }
1721 
1722             auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
1723             final switch (next)
1724             {
1725                 foreach (i, R; Rs)
1726                 {
1727                     case i:
1728                         if (!source[i].empty)
1729                         {
1730                             _current = i;
1731                             return;
1732                         }
1733                         if (i == _current)
1734                         {
1735                             _current = _current.max;
1736                             return;
1737                         }
1738                         goto case (i + 1) % Rs.length;
1739                 }
1740             }
1741         }
1742 
1743         static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
saveResult1744             @property auto save()
1745             {
1746                 Result result = this;
1747                 foreach (i, Unused; Rs)
1748                 {
1749                     result.source[i] = result.source[i].save;
1750                 }
1751                 return result;
1752             }
1753 
1754         static if (allSatisfy!(hasLength, Rs))
1755         {
lengthResult1756             @property size_t length()
1757             {
1758                 size_t result;
1759                 foreach (i, R; Rs)
1760                 {
1761                     result += source[i].length;
1762                 }
1763                 return result;
1764             }
1765 
1766             alias opDollar = length;
1767         }
1768     }
1769 
1770     return Result(rs, 0);
1771 }
1772 
1773 ///
1774 @safe unittest
1775 {
1776     import std.algorithm.comparison : equal;
1777 
1778     int[] a = [ 1, 2, 3 ];
1779     int[] b = [ 10, 20, 30, 40 ];
1780     auto r = roundRobin(a, b);
1781     assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
1782 }
1783 
1784 /**
1785  * roundRobin can be used to create "interleave" functionality which inserts
1786  * an element between each element in a range.
1787  */
1788 @safe unittest
1789 {
1790     import std.algorithm.comparison : equal;
1791 
1792     auto interleave(R, E)(R range, E element)
1793     if ((isInputRange!R && hasLength!R) || isForwardRange!R)
1794     {
1795         static if (hasLength!R)
1796             immutable len = range.length;
1797         else
1798             immutable len = range.save.walkLength;
1799 
1800         return roundRobin(
1801             range,
1802             element.repeat(len - 1)
1803         );
1804     }
1805 
1806     assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
1807 }
1808 
1809 /**
1810 Iterates a random-access range starting from a given point and
1811 progressively extending left and right from that point. If no initial
1812 point is given, iteration starts from the middle of the
1813 range. Iteration spans the entire range.
1814 
1815 When `startingIndex` is 0 the range will be fully iterated in order
1816 and in reverse order when `r.length` is given.
1817 
1818 Params:
1819     r = a random access range with length and slicing
1820     startingIndex = the index to begin iteration from
1821 
1822 Returns:
1823     A forward range with length
1824  */
1825 auto radial(Range, I)(Range r, I startingIndex)
1826 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
1827 {
1828     if (startingIndex != r.length) ++startingIndex;
1829     return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
1830 }
1831 
1832 /// Ditto
1833 auto radial(R)(R r)
1834 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
1835 {
1836     return .radial(r, (r.length - !r.empty) / 2);
1837 }
1838 
1839 ///
1840 @safe unittest
1841 {
1842     import std.algorithm.comparison : equal;
1843     int[] a = [ 1, 2, 3, 4, 5 ];
1844     assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
1845     a = [ 1, 2, 3, 4 ];
1846     assert(equal(radial(a), [ 2, 3, 1, 4 ]));
1847 
1848     // If the left end is reached first, the remaining elements on the right
1849     // are concatenated in order:
1850     a = [ 0, 1, 2, 3, 4, 5 ];
1851     assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
1852 
1853     // If the right end is reached first, the remaining elements on the left
1854     // are concatenated in reverse order:
1855     assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
1856 }
1857 
1858 @safe unittest
1859 {
1860     import std.algorithm.comparison : equal;
1861     import std.conv : text;
1862     import std.exception : enforce;
1863     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
1864 
test(int[]input,int[]witness)1865     void test(int[] input, int[] witness)
1866     {
1867         enforce(equal(radial(input), witness),
1868                 text(radial(input), " vs. ", witness));
1869     }
1870     test([], []);
1871     test([ 1 ], [ 1 ]);
1872     test([ 1, 2 ], [ 1, 2 ]);
1873     test([ 1, 2, 3 ], [ 2, 3, 1 ]);
1874     test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
1875     test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
1876     test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
1877 
1878     int[] a = [ 1, 2, 3, 4, 5 ];
1879     assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
1880     assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
1881     assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
1882     static assert(isForwardRange!(typeof(radial(a, 1))));
1883 
1884     auto r = radial([1,2,3,4,5]);
1885     for (auto rr = r.save; !rr.empty; rr.popFront())
1886     {
1887         assert(rr.front == moveFront(rr));
1888     }
1889     r.front = 5;
1890     assert(r.front == 5);
1891 
1892     // Test instantiation without lvalue elements.
1893     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
1894     assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
1895 
1896     // immutable int[] immi = [ 1, 2 ];
1897     // static assert(is(typeof(radial(immi))));
1898 }
1899 
1900 @safe unittest
1901 {
1902     import std.algorithm.comparison : equal;
1903 
1904     auto LL = iota(1L, 6L);
1905     auto r = radial(LL);
1906     assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
1907 }
1908 
1909 /**
1910 Lazily takes only up to `n` elements of a range. This is
1911 particularly useful when using with infinite ranges.
1912 
1913 Unlike $(LREF takeExactly), `take` does not require that there
1914 are `n` or more elements in `input`. As a consequence, length
1915 information is not applied to the result unless `input` also has
1916 length information.
1917 
1918 Params:
1919     input = an input range to iterate over up to `n` times
1920     n = the number of elements to take
1921 
1922 Returns:
1923     At minimum, an input range. If the range offers random access
1924     and `length`, `take` offers them as well.
1925  */
1926 Take!R take(R)(R input, size_t n)
1927 if (isInputRange!(Unqual!R))
1928 {
1929     alias U = Unqual!R;
1930     static if (is(R T == Take!T))
1931     {
1932         import std.algorithm.comparison : min;
1933         return R(input.source, min(n, input._maxAvailable));
1934     }
1935     else static if (!isInfinite!U && hasSlicing!U)
1936     {
1937         import std.algorithm.comparison : min;
1938         return input[0 .. min(n, input.length)];
1939     }
1940     else
1941     {
1942         return Take!R(input, n);
1943     }
1944 }
1945 
1946 /// ditto
1947 struct Take(Range)
1948 if (isInputRange!(Unqual!Range) &&
1949     //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
1950     //take for slicing infinite ranges.
1951     !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
1952 {
1953     private alias R = Unqual!Range;
1954 
1955     /// User accessible in read and write
1956     public R source;
1957 
1958     private size_t _maxAvailable;
1959 
1960     alias Source = R;
1961 
1962     /// Range primitives
empty()1963     @property bool empty()
1964     {
1965         return _maxAvailable == 0 || source.empty;
1966     }
1967 
1968     /// ditto
front()1969     @property auto ref front()
1970     {
1971         assert(!empty,
1972             "Attempting to fetch the front of an empty "
1973             ~ Take.stringof);
1974         return source.front;
1975     }
1976 
1977     /// ditto
popFront()1978     void popFront()
1979     {
1980         assert(!empty,
1981             "Attempting to popFront() past the end of a "
1982             ~ Take.stringof);
1983         source.popFront();
1984         --_maxAvailable;
1985     }
1986 
1987     static if (isForwardRange!R)
1988         /// ditto
save()1989         @property Take save()
1990         {
1991             return Take(source.save, _maxAvailable);
1992         }
1993 
1994     static if (hasAssignableElements!R)
1995         /// ditto
1996         @property void front(ElementType!R v)
1997         {
1998             assert(!empty,
1999                 "Attempting to assign to the front of an empty "
2000                 ~ Take.stringof);
2001             // This has to return auto instead of void because of Bug 4706.
2002             source.front = v;
2003         }
2004 
2005     static if (hasMobileElements!R)
2006     {
2007         /// ditto
moveFront()2008         auto moveFront()
2009         {
2010             assert(!empty,
2011                 "Attempting to move the front of an empty "
2012                 ~ Take.stringof);
2013             return source.moveFront();
2014         }
2015     }
2016 
2017     static if (isInfinite!R)
2018     {
2019         /// ditto
length()2020         @property size_t length() const
2021         {
2022             return _maxAvailable;
2023         }
2024 
2025         /// ditto
2026         alias opDollar = length;
2027 
2028         //Note: Due to Take/hasSlicing circular dependency,
2029         //This needs to be a restrained template.
2030         /// ditto
2031         auto opSlice()(size_t i, size_t j)
2032         if (hasSlicing!R)
2033         {
2034             assert(i <= j, "Invalid slice bounds");
2035             assert(j <= length, "Attempting to slice past the end of a "
2036                 ~ Take.stringof);
2037             return source[i .. j];
2038         }
2039     }
2040     else static if (hasLength!R)
2041     {
2042         /// ditto
length()2043         @property size_t length()
2044         {
2045             import std.algorithm.comparison : min;
2046             return min(_maxAvailable, source.length);
2047         }
2048 
2049         alias opDollar = length;
2050     }
2051 
2052     static if (isRandomAccessRange!R)
2053     {
2054         /// ditto
popBack()2055         void popBack()
2056         {
2057             assert(!empty,
2058                 "Attempting to popBack() past the beginning of a "
2059                 ~ Take.stringof);
2060             --_maxAvailable;
2061         }
2062 
2063         /// ditto
back()2064         @property auto ref back()
2065         {
2066             assert(!empty,
2067                 "Attempting to fetch the back of an empty "
2068                 ~ Take.stringof);
2069             return source[this.length - 1];
2070         }
2071 
2072         /// ditto
opIndex(size_t index)2073         auto ref opIndex(size_t index)
2074         {
2075             assert(index < length,
2076                 "Attempting to index out of the bounds of a "
2077                 ~ Take.stringof);
2078             return source[index];
2079         }
2080 
2081         static if (hasAssignableElements!R)
2082         {
2083             /// ditto
2084             @property void back(ElementType!R v)
2085             {
2086                 // This has to return auto instead of void because of Bug 4706.
2087                 assert(!empty,
2088                     "Attempting to assign to the back of an empty "
2089                     ~ Take.stringof);
2090                 source[this.length - 1] = v;
2091             }
2092 
2093             /// ditto
2094             void opIndexAssign(ElementType!R v, size_t index)
2095             {
2096                 assert(index < length,
2097                     "Attempting to index out of the bounds of a "
2098                     ~ Take.stringof);
2099                 source[index] = v;
2100             }
2101         }
2102 
2103         static if (hasMobileElements!R)
2104         {
2105             /// ditto
moveBack()2106             auto moveBack()
2107             {
2108                 assert(!empty,
2109                     "Attempting to move the back of an empty "
2110                     ~ Take.stringof);
2111                 return source.moveAt(this.length - 1);
2112             }
2113 
2114             /// ditto
moveAt(size_t index)2115             auto moveAt(size_t index)
2116             {
2117                 assert(index < length,
2118                     "Attempting to index out of the bounds of a "
2119                     ~ Take.stringof);
2120                 return source.moveAt(index);
2121             }
2122         }
2123     }
2124 
2125     /**
2126     Access to maximal length of the range.
2127     Note: the actual length of the range depends on the underlying range.
2128     If it has fewer elements, it will stop before maxLength is reached.
2129     */
maxLength()2130     @property size_t maxLength() const
2131     {
2132         return _maxAvailable;
2133     }
2134 }
2135 
2136 /**
2137 This template simply aliases itself to R and is useful for consistency in
2138 generic code.
2139 */
2140 template Take(R)
2141 if (isInputRange!(Unqual!R) &&
2142     ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2143 {
2144     alias Take = R;
2145 }
2146 
2147 ///
2148 pure @safe nothrow unittest
2149 {
2150     import std.algorithm.comparison : equal;
2151 
2152     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2153     auto s = take(arr1, 5);
2154     assert(s.length == 5);
2155     assert(s[4] == 5);
2156     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2157 }
2158 
2159 /**
2160  * If the range runs out before `n` elements, `take` simply returns the entire
2161  * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2162  * the range ends prematurely):
2163  */
2164 pure @safe nothrow unittest
2165 {
2166     import std.algorithm.comparison : equal;
2167 
2168     int[] arr2 = [ 1, 2, 3 ];
2169     auto t = take(arr2, 5);
2170     assert(t.length == 3);
2171     assert(equal(t, [ 1, 2, 3 ]));
2172 }
2173 
2174 pure @safe nothrow unittest
2175 {
2176     import std.algorithm.comparison : equal;
2177     import std.internal.test.dummyrange : AllDummyRanges;
2178 
2179     int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2180     auto s = take(arr1, 5);
2181     assert(s.length == 5);
2182     assert(s[4] == 5);
2183     assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2184     assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2185 
2186     // Test fix for bug 4464.
2187     static assert(is(typeof(s) == Take!(int[])));
2188     static assert(is(typeof(s) == int[]));
2189 
2190     // Test using narrow strings.
2191     import std.exception : assumeWontThrow;
2192 
2193     auto myStr = "This is a string.";
2194     auto takeMyStr = take(myStr, 7);
2195     assert(assumeWontThrow(equal(takeMyStr, "This is")));
2196     // Test fix for bug 5052.
2197     auto takeMyStrAgain = take(takeMyStr, 4);
2198     assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2199     static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
2200     takeMyStrAgain = take(takeMyStr, 10);
2201     assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
2202 
foreach(DummyType;AllDummyRanges)2203     foreach (DummyType; AllDummyRanges)
2204     {
2205         DummyType dummy;
2206         auto t = take(dummy, 5);
2207         alias T = typeof(t);
2208 
2209         static if (isRandomAccessRange!DummyType)
2210         {
2211             static assert(isRandomAccessRange!T);
2212             assert(t[4] == 5);
2213 
2214             assert(moveAt(t, 1) == t[1]);
2215             assert(t.back == moveBack(t));
2216         }
2217         else static if (isForwardRange!DummyType)
2218         {
2219             static assert(isForwardRange!T);
2220         }
2221 
2222         for (auto tt = t; !tt.empty; tt.popFront())
2223         {
2224             assert(tt.front == moveFront(tt));
2225         }
2226 
2227         // Bidirectional ranges can't be propagated properly if they don't
2228         // also have random access.
2229 
2230         assert(equal(t, [1,2,3,4,5]));
2231 
2232         //Test that take doesn't wrap the result of take.
2233         assert(take(t, 4) == take(dummy, 4));
2234     }
2235 
2236     immutable myRepeat = repeat(1);
2237     static assert(is(Take!(typeof(myRepeat))));
2238 }
2239 
2240 pure @safe nothrow @nogc unittest
2241 {
2242     //check for correct slicing of Take on an infinite range
2243     import std.algorithm.comparison : equal;
2244     foreach (start; 0 .. 4)
2245         foreach (stop; start .. 4)
2246             assert(iota(4).cycle.take(4)[start .. stop]
2247                 .equal(iota(start, stop)));
2248 }
2249 
2250 pure @safe nothrow @nogc unittest
2251 {
2252     // Check that one can declare variables of all Take types,
2253     // and that they match the return type of the corresponding
2254     // take().  (See issue 4464.)
2255     int[] r1;
2256     Take!(int[]) t1;
2257     t1 = take(r1, 1);
2258     assert(t1.empty);
2259 
2260     string r2;
2261     Take!string t2;
2262     t2 = take(r2, 1);
2263     assert(t2.empty);
2264 
2265     Take!(Take!string) t3;
2266     t3 = take(t2, 1);
2267     assert(t3.empty);
2268 }
2269 
2270 pure @safe nothrow @nogc unittest
2271 {
2272     alias R1 = typeof(repeat(1));
2273     alias R2 = typeof(cycle([1]));
2274     alias TR1 = Take!R1;
2275     alias TR2 = Take!R2;
2276     static assert(isBidirectionalRange!TR1);
2277     static assert(isBidirectionalRange!TR2);
2278 }
2279 
2280 pure @safe nothrow @nogc unittest //12731
2281 {
2282     auto a = repeat(1);
2283     auto s = a[1 .. 5];
2284     s = s[1 .. 3];
2285     assert(s.length == 2);
2286     assert(s[0] == 1);
2287     assert(s[1] == 1);
2288 }
2289 
2290 pure @safe nothrow @nogc unittest //13151
2291 {
2292     import std.algorithm.comparison : equal;
2293 
2294     auto r = take(repeat(1, 4), 3);
2295     assert(r.take(2).equal(repeat(1, 2)));
2296 }
2297 
2298 
2299 /**
2300 Similar to $(LREF take), but assumes that $(D range) has at least $(D
2301 n) elements. Consequently, the result of $(D takeExactly(range, n))
2302 always defines the $(D length) property (and initializes it to $(D n))
2303 even when $(D range) itself does not define $(D length).
2304 
2305 The result of $(D takeExactly) is identical to that of $(LREF take) in
2306 cases where the original range defines $(D length) or is infinite.
2307 
2308 Unlike $(LREF take), however, it is illegal to pass a range with less than
2309 $(D n) elements to $(D takeExactly); this will cause an assertion failure.
2310  */
2311 auto takeExactly(R)(R range, size_t n)
2312 if (isInputRange!R)
2313 {
2314     static if (is(typeof(takeExactly(range._input, n)) == R))
2315     {
2316         assert(n <= range._n,
2317                "Attempted to take more than the length of the range with takeExactly.");
2318         // takeExactly(takeExactly(r, n1), n2) has the same type as
2319         // takeExactly(r, n1) and simply returns takeExactly(r, n2)
2320         range._n = n;
2321         return range;
2322     }
2323     //Also covers hasSlicing!R for finite ranges.
2324     else static if (hasLength!R)
2325     {
2326         assert(n <= range.length,
2327                "Attempted to take more than the length of the range with takeExactly.");
2328         return take(range, n);
2329     }
2330     else static if (isInfinite!R)
2331         return Take!R(range, n);
2332     else
2333     {
2334         static struct Result
2335         {
2336             R _input;
2337             private size_t _n;
2338 
emptyResult2339             @property bool empty() const { return !_n; }
frontResult2340             @property auto ref front()
2341             {
2342                 assert(_n > 0, "front() on an empty " ~ Result.stringof);
2343                 return _input.front;
2344             }
popFrontResult2345             void popFront() { _input.popFront(); --_n; }
lengthResult2346             @property size_t length() const { return _n; }
2347             alias opDollar = length;
2348 
2349             @property Take!R _takeExactly_Result_asTake()
2350             {
2351                 return typeof(return)(_input, _n);
2352             }
2353 
2354             alias _takeExactly_Result_asTake this;
2355 
2356             static if (isForwardRange!R)
saveResult2357                 @property auto save()
2358                 {
2359                     return Result(_input.save, _n);
2360                 }
2361 
2362             static if (hasMobileElements!R)
2363             {
moveFrontResult2364                 auto moveFront()
2365                 {
2366                     assert(!empty,
2367                         "Attempting to move the front of an empty "
2368                         ~ typeof(this).stringof);
2369                     return _input.moveFront();
2370                 }
2371             }
2372 
2373             static if (hasAssignableElements!R)
2374             {
2375                 @property auto ref front(ElementType!R v)
2376                 {
2377                     assert(!empty,
2378                         "Attempting to assign to the front of an empty "
2379                         ~ typeof(this).stringof);
2380                     return _input.front = v;
2381                 }
2382             }
2383         }
2384 
2385         return Result(range, n);
2386     }
2387 }
2388 
2389 ///
2390 pure @safe nothrow unittest
2391 {
2392     import std.algorithm.comparison : equal;
2393 
2394     auto a = [ 1, 2, 3, 4, 5 ];
2395 
2396     auto b = takeExactly(a, 3);
2397     assert(equal(b, [1, 2, 3]));
2398     static assert(is(typeof(b.length) == size_t));
2399     assert(b.length == 3);
2400     assert(b.front == 1);
2401     assert(b.back == 3);
2402 }
2403 
2404 pure @safe nothrow unittest
2405 {
2406     import std.algorithm.comparison : equal;
2407     import std.algorithm.iteration : filter;
2408 
2409     auto a = [ 1, 2, 3, 4, 5 ];
2410     auto b = takeExactly(a, 3);
2411     assert(equal(b, [1, 2, 3]));
2412     auto c = takeExactly(b, 2);
2413     assert(equal(c, [1, 2]));
2414 
2415 
2416 
2417     auto d = filter!"a > 2"(a);
2418     auto e = takeExactly(d, 3);
2419     assert(equal(e, [3, 4, 5]));
2420     static assert(is(typeof(e.length) == size_t));
2421     assert(e.length == 3);
2422     assert(e.front == 3);
2423 
2424     assert(equal(takeExactly(e, 3), [3, 4, 5]));
2425 }
2426 
2427 pure @safe nothrow unittest
2428 {
2429     import std.algorithm.comparison : equal;
2430     import std.internal.test.dummyrange : AllDummyRanges;
2431 
2432     auto a = [ 1, 2, 3, 4, 5 ];
2433     //Test that take and takeExactly are the same for ranges which define length
2434     //but aren't sliceable.
2435     struct L
2436     {
frontL2437         @property auto front() { return _arr[0]; }
emptyL2438         @property bool empty() { return _arr.empty; }
popFrontL2439         void popFront() { _arr.popFront(); }
lengthL2440         @property size_t length() { return _arr.length; }
2441         int[] _arr;
2442     }
2443     static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
2444     assert(take(L(a), 3) == takeExactly(L(a), 3));
2445 
2446     //Test that take and takeExactly are the same for ranges which are sliceable.
2447     static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
2448     assert(take(a, 3) == takeExactly(a, 3));
2449 
2450     //Test that take and takeExactly are the same for infinite ranges.
2451     auto inf = repeat(1);
2452     static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
2453     assert(take(inf, 5) == takeExactly(inf, 5));
2454 
2455     //Test that take and takeExactly are _not_ the same for ranges which don't
2456     //define length.
2457     static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
2458 
foreach(DummyType;AllDummyRanges)2459     foreach (DummyType; AllDummyRanges)
2460     {
2461         {
2462             DummyType dummy;
2463             auto t = takeExactly(dummy, 5);
2464 
2465             //Test that takeExactly doesn't wrap the result of takeExactly.
2466             assert(takeExactly(t, 4) == takeExactly(dummy, 4));
2467         }
2468 
2469         static if (hasMobileElements!DummyType)
2470         {
2471             {
2472                 auto t = takeExactly(DummyType.init, 4);
2473                 assert(t.moveFront() == 1);
2474                 assert(equal(t, [1, 2, 3, 4]));
2475             }
2476         }
2477 
2478         static if (hasAssignableElements!DummyType)
2479         {
2480             {
2481                 auto t = takeExactly(DummyType.init, 4);
2482                 t.front = 9;
2483                 assert(equal(t, [9, 2, 3, 4]));
2484             }
2485         }
2486     }
2487 }
2488 
2489 pure @safe nothrow unittest
2490 {
2491     import std.algorithm.comparison : equal;
2492     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2493 
2494     alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
2495     auto te = takeExactly(DummyType(), 5);
2496     Take!DummyType t = te;
2497     assert(equal(t, [1, 2, 3, 4, 5]));
2498     assert(equal(t, te));
2499 }
2500 
2501 /**
2502 Returns a range with at most one element; for example, $(D
2503 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
2504 42). Calling $(D popFront()) off that range renders it empty.
2505 
2506 In effect $(D takeOne(r)) is somewhat equivalent to $(D take(r, 1)) but in
2507 certain interfaces it is important to know statically that the range may only
2508 have at most one element.
2509 
2510 The type returned by $(D takeOne) is a random-access range with length
2511 regardless of $(D R)'s capabilities, as long as it is a forward range.
2512 (another feature that distinguishes $(D takeOne) from $(D take)). If
2513 (D R) is an input range but not a forward range, return type is an input
2514 range with all random-access capabilities except save.
2515  */
2516 auto takeOne(R)(R source)
2517 if (isInputRange!R)
2518 {
2519     static if (hasSlicing!R)
2520     {
2521         return source[0 .. !source.empty];
2522     }
2523     else
2524     {
2525         static struct Result
2526         {
2527             private R _source;
2528             private bool _empty = true;
emptyResult2529             @property bool empty() const { return _empty; }
frontResult2530             @property auto ref front()
2531             {
2532                 assert(!empty, "Attempting to fetch the front of an empty takeOne");
2533                 return _source.front;
2534             }
popFrontResult2535             void popFront()
2536             {
2537                 assert(!empty, "Attempting to popFront an empty takeOne");
2538                 _source.popFront();
2539                 _empty = true;
2540             }
popBackResult2541             void popBack()
2542             {
2543                 assert(!empty, "Attempting to popBack an empty takeOne");
2544                 _source.popFront();
2545                 _empty = true;
2546             }
2547             static if (isForwardRange!(Unqual!R))
2548             {
saveResult2549                 @property auto save() { return Result(_source.save, empty); }
2550             }
backResult2551             @property auto ref back()
2552             {
2553                 assert(!empty, "Attempting to fetch the back of an empty takeOne");
2554                 return _source.front;
2555             }
lengthResult2556             @property size_t length() const { return !empty; }
2557             alias opDollar = length;
opIndexResult2558             auto ref opIndex(size_t n)
2559             {
2560                 assert(n < length, "Attempting to index a takeOne out of bounds");
2561                 return _source.front;
2562             }
opSliceResult2563             auto opSlice(size_t m, size_t n)
2564             {
2565                 assert(m <= n && n < length, "Attempting to index a takeOne out of bounds");
2566                 return n > m ? this : Result(_source, false);
2567             }
2568             // Non-standard property
sourceResult2569             @property R source() { return _source; }
2570         }
2571 
2572         return Result(source, source.empty);
2573     }
2574 }
2575 
2576 ///
2577 pure @safe nothrow unittest
2578 {
2579     auto s = takeOne([42, 43, 44]);
2580     static assert(isRandomAccessRange!(typeof(s)));
2581     assert(s.length == 1);
2582     assert(!s.empty);
2583     assert(s.front == 42);
2584     s.front = 43;
2585     assert(s.front == 43);
2586     assert(s.back == 43);
2587     assert(s[0] == 43);
2588     s.popFront();
2589     assert(s.length == 0);
2590     assert(s.empty);
2591 }
2592 
2593 pure @safe nothrow @nogc unittest
2594 {
2595     struct NonForwardRange
2596     {
2597         enum empty = false;
frontNonForwardRange2598         int front() { return 42; }
popFrontNonForwardRange2599         void popFront() {}
2600     }
2601 
2602     static assert(!isForwardRange!NonForwardRange);
2603 
2604     auto s = takeOne(NonForwardRange());
2605     assert(s.front == 42);
2606 }
2607 
2608 //guards against issue 16999
2609 pure @safe unittest
2610 {
2611     auto myIota = new class
2612     {
2613         int front = 0;
popFront()2614         @safe void popFront(){front++;}
2615         enum empty = false;
2616     };
2617     auto iotaPart = myIota.takeOne;
2618     int sum;
foreach(var;chain (iotaPart,iotaPart,iotaPart))2619     foreach (var; chain(iotaPart, iotaPart, iotaPart))
2620     {
2621         sum += var;
2622     }
2623     assert(sum == 3);
2624     assert(iotaPart.front == 3);
2625 }
2626 
2627 /++
2628     Returns an empty range which is statically known to be empty and is
2629     guaranteed to have $(D length) and be random access regardless of $(D R)'s
2630     capabilities.
2631   +/
2632 auto takeNone(R)()
2633 if (isInputRange!R)
2634 {
2635     return typeof(takeOne(R.init)).init;
2636 }
2637 
2638 ///
2639 pure @safe nothrow @nogc unittest
2640 {
2641     auto range = takeNone!(int[])();
2642     assert(range.length == 0);
2643     assert(range.empty);
2644 }
2645 
2646 pure @safe nothrow @nogc unittest
2647 {
2648     enum ctfe = takeNone!(int[])();
2649     static assert(ctfe.length == 0);
2650     static assert(ctfe.empty);
2651 }
2652 
2653 
2654 /++
2655     Creates an empty range from the given range in $(BIGOH 1). If it can, it
2656     will return the same range type. If not, it will return
2657     $(D takeExactly(range, 0)).
2658   +/
2659 auto takeNone(R)(R range)
2660 if (isInputRange!R)
2661 {
2662     import std.traits : isDynamicArray;
2663     //Makes it so that calls to takeNone which don't use UFCS still work with a
2664     //member version if it's defined.
2665     static if (is(typeof(R.takeNone)))
2666         auto retval = range.takeNone();
2667     //@@@BUG@@@ 8339
2668     else static if (isDynamicArray!R)/+ ||
2669                    (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
2670     {
2671         auto retval = R.init;
2672     }
2673     //An infinite range sliced at [0 .. 0] would likely still not be empty...
2674     else static if (hasSlicing!R && !isInfinite!R)
2675         auto retval = range[0 .. 0];
2676     else
2677         auto retval = takeExactly(range, 0);
2678 
2679     //@@@BUG@@@ 7892 prevents this from being done in an out block.
2680     assert(retval.empty);
2681     return retval;
2682 }
2683 
2684 ///
2685 pure @safe nothrow unittest
2686 {
2687     import std.algorithm.iteration : filter;
2688     assert(takeNone([42, 27, 19]).empty);
2689     assert(takeNone("dlang.org").empty);
2690     assert(takeNone(filter!"true"([42, 27, 19])).empty);
2691 }
2692 
2693 @safe unittest
2694 {
2695     import std.algorithm.iteration : filter;
2696     import std.meta : AliasSeq;
2697 
2698     struct Dummy
2699     {
genInputDummy2700         mixin template genInput()
2701         {
2702         @safe:
2703             @property bool empty() { return _arr.empty; }
2704             @property auto front() { return _arr.front; }
2705             void popFront() { _arr.popFront(); }
2706             static assert(isInputRange!(typeof(this)));
2707         }
2708     }
2709     alias genInput = Dummy.genInput;
2710 
2711     static struct NormalStruct
2712     {
2713         //Disabled to make sure that the takeExactly version is used.
2714         @disable this();
thisNormalStruct2715         this(int[] arr) { _arr = arr; }
2716         mixin genInput;
2717         int[] _arr;
2718     }
2719 
2720     static struct SliceStruct
2721     {
2722         @disable this();
this(int[]arr)2723         this(int[] arr) { _arr = arr; }
2724         mixin genInput;
save()2725         @property auto save() { return this; }
opSlice(size_t i,size_t j)2726         auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
length()2727         @property size_t length() { return _arr.length; }
2728         int[] _arr;
2729     }
2730 
2731     static struct InitStruct
2732     {
2733         mixin genInput;
2734         int[] _arr;
2735     }
2736 
2737     static struct TakeNoneStruct
2738     {
this(int[]arr)2739         this(int[] arr) { _arr = arr; }
2740         @disable this();
2741         mixin genInput;
takeNone()2742         auto takeNone() { return typeof(this)(null); }
2743         int[] _arr;
2744     }
2745 
2746     static class NormalClass
2747     {
this(int[]arr)2748         this(int[] arr) {_arr = arr;}
2749         mixin genInput;
2750         int[] _arr;
2751     }
2752 
2753     static class SliceClass
2754     {
2755     @safe:
this(int[]arr)2756         this(int[] arr) { _arr = arr; }
2757         mixin genInput;
save()2758         @property auto save() { return new typeof(this)(_arr); }
opSlice(size_t i,size_t j)2759         auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
length()2760         @property size_t length() { return _arr.length; }
2761         int[] _arr;
2762     }
2763 
2764     static class TakeNoneClass
2765     {
2766     @safe:
this(int[]arr)2767         this(int[] arr) { _arr = arr; }
2768         mixin genInput;
takeNone()2769         auto takeNone() { return new typeof(this)(null); }
2770         int[] _arr;
2771     }
2772 
2773     import std.format : format;
2774 
2775     foreach (range; AliasSeq!([1, 2, 3, 4, 5],
2776                              "hello world",
2777                              "hello world"w,
2778                              "hello world"d,
2779                              SliceStruct([1, 2, 3]),
2780                              //@@@BUG@@@ 8339 forces this to be takeExactly
2781                              //`InitStruct([1, 2, 3]),
2782                              TakeNoneStruct([1, 2, 3])))
2783     {
2784         static assert(takeNone(range).empty, typeof(range).stringof);
2785         assert(takeNone(range).empty);
2786         static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
2787     }
2788 
2789     foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
2790                              InitStruct([1, 2, 3])))
2791     {
2792         static assert(takeNone(range).empty, typeof(range).stringof);
2793         assert(takeNone(range).empty);
2794         static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
2795     }
2796 
2797     //Don't work in CTFE.
2798     auto normal = new NormalClass([1, 2, 3]);
2799     assert(takeNone(normal).empty);
2800     static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
2801 
2802     auto slice = new SliceClass([1, 2, 3]);
2803     assert(takeNone(slice).empty);
2804     static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
2805 
2806     auto taken = new TakeNoneClass([1, 2, 3]);
2807     assert(takeNone(taken).empty);
2808     static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
2809 
2810     auto filtered = filter!"true"([1, 2, 3, 4, 5]);
2811     assert(takeNone(filtered).empty);
2812     //@@@BUG@@@ 8339 and 5941 force this to be takeExactly
2813     //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
2814 }
2815 
2816 /++
2817  + Return a _range advanced to within $(D _n) elements of the end of
2818  + $(D _range).
2819  +
2820  + Intended as the _range equivalent of the Unix
2821  + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
2822  + of $(D _range) is less than or equal to $(D _n), $(D _range) is returned
2823  + as-is.
2824  +
2825  + Completes in $(BIGOH 1) steps for ranges that support slicing and have
2826  + length. Completes in $(BIGOH _range.length) time for all other ranges.
2827  +
2828  + Params:
2829  +    range = _range to get _tail of
2830  +    n = maximum number of elements to include in _tail
2831  +
2832  + Returns:
2833  +    Returns the _tail of $(D _range) augmented with length information
2834  +/
2835 auto tail(Range)(Range range, size_t n)
2836 if (isInputRange!Range && !isInfinite!Range &&
2837     (hasLength!Range || isForwardRange!Range))
2838 {
2839     static if (hasLength!Range)
2840     {
2841         immutable length = range.length;
2842         if (n >= length)
2843             return range.takeExactly(length);
2844         else
2845             return range.drop(length - n).takeExactly(n);
2846     }
2847     else
2848     {
2849         Range scout = range.save;
2850         foreach (immutable i; 0 .. n)
2851         {
2852             if (scout.empty)
2853                 return range.takeExactly(i);
2854             scout.popFront();
2855         }
2856 
2857         auto tail = range.save;
2858         while (!scout.empty)
2859         {
2860             assert(!tail.empty);
2861             scout.popFront();
2862             tail.popFront();
2863         }
2864 
2865         return tail.takeExactly(n);
2866     }
2867 }
2868 
2869 ///
2870 pure @safe nothrow unittest
2871 {
2872     // tail -c n
2873     assert([1, 2, 3].tail(1) == [3]);
2874     assert([1, 2, 3].tail(2) == [2, 3]);
2875     assert([1, 2, 3].tail(3) == [1, 2, 3]);
2876     assert([1, 2, 3].tail(4) == [1, 2, 3]);
2877     assert([1, 2, 3].tail(0).length == 0);
2878 
2879     // tail --lines=n
2880     import std.algorithm.comparison : equal;
2881     import std.algorithm.iteration : joiner;
2882     import std.exception : assumeWontThrow;
2883     import std.string : lineSplitter;
2884     assert("one\ntwo\nthree"
2885         .lineSplitter
2886         .tail(2)
2887         .joiner("\n")
2888         .equal("two\nthree")
2889         .assumeWontThrow);
2890 }
2891 
2892 // @nogc prevented by @@@BUG@@@ 15408
2893 pure nothrow @safe /+@nogc+/ unittest
2894 {
2895     import std.algorithm.comparison : equal;
2896     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
2897         RangeType, ReturnBy;
2898 
2899     static immutable cheatsheet = [6, 7, 8, 9, 10];
2900 
foreach(R;AllDummyRanges)2901     foreach (R; AllDummyRanges)
2902     {
2903         static if (isInputRange!R && !isInfinite!R &&
2904                    (hasLength!R || isForwardRange!R))
2905         {
2906             assert(R.init.tail(5).equal(cheatsheet));
2907             static assert(R.init.tail(5).equal(cheatsheet));
2908 
2909             assert(R.init.tail(0).length == 0);
2910             assert(R.init.tail(10).equal(R.init));
2911             assert(R.init.tail(11).equal(R.init));
2912         }
2913     }
2914 
2915     // Infinite ranges are not supported
2916     static assert(!__traits(compiles, repeat(0).tail(0)));
2917 
2918     // Neither are non-forward ranges without length
2919     static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
2920         RangeType.Input).init.tail(5)));
2921 }
2922 
2923 pure @safe nothrow @nogc unittest
2924 {
2925     static immutable input = [1, 2, 3];
2926     static immutable expectedOutput = [2, 3];
2927     assert(input.tail(2) == expectedOutput);
2928 }
2929 
2930 /++
2931     Convenience function which calls
2932     $(REF popFrontN, std, _range, primitives)`(range, n)` and returns `range`.
2933     `drop` makes it easier to pop elements from a range
2934     and then pass it to another function within a single expression,
2935     whereas `popFrontN` would require multiple statements.
2936 
2937     `dropBack` provides the same functionality but instead calls
2938     $(REF popBackN, std, _range, primitives)`(range, n)`
2939 
2940     Note: `drop` and `dropBack` will only pop $(I up to)
2941     `n` elements but will stop if the range is empty first.
2942     In other languages this is sometimes called `skip`.
2943 
2944     Params:
2945         range = the input range to drop from
2946         n = the number of elements to drop
2947 
2948     Returns:
2949         `range` with up to `n` elements dropped
2950 
2951     See_Also:
2952         $(REF popFront, std, _range, primitives), $(REF popBackN, std, _range, primitives)
2953   +/
2954 R drop(R)(R range, size_t n)
2955 if (isInputRange!R)
2956 {
2957     range.popFrontN(n);
2958     return range;
2959 }
2960 /// ditto
2961 R dropBack(R)(R range, size_t n)
2962 if (isBidirectionalRange!R)
2963 {
2964     range.popBackN(n);
2965     return range;
2966 }
2967 
2968 ///
2969 @safe unittest
2970 {
2971     import std.algorithm.comparison : equal;
2972 
2973     assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
2974     assert("hello world".drop(6) == "world");
2975     assert("hello world".drop(50).empty);
2976     assert("hello world".take(6).drop(3).equal("lo "));
2977 }
2978 
2979 @safe unittest
2980 {
2981     import std.algorithm.comparison : equal;
2982 
2983     assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
2984     assert("hello world".dropBack(6) == "hello");
2985     assert("hello world".dropBack(50).empty);
2986     assert("hello world".drop(4).dropBack(4).equal("o w"));
2987 }
2988 
2989 @safe unittest
2990 {
2991     import std.algorithm.comparison : equal;
2992     import std.container.dlist : DList;
2993 
2994     //Remove all but the first two elements
2995     auto a = DList!int(0, 1, 9, 9, 9, 9);
2996     a.remove(a[].drop(2));
2997     assert(a[].equal(a[].take(2)));
2998 }
2999 
3000 @safe unittest
3001 {
3002     import std.algorithm.comparison : equal;
3003     import std.algorithm.iteration : filter;
3004 
3005     assert(drop("", 5).empty);
3006     assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3007 }
3008 
3009 @safe unittest
3010 {
3011     import std.algorithm.comparison : equal;
3012     import std.container.dlist : DList;
3013 
3014     //insert before the last two elements
3015     auto a = DList!int(0, 1, 2, 5, 6);
3016     a.insertAfter(a[].dropBack(2), [3, 4]);
3017     assert(a[].equal(iota(0, 7)));
3018 }
3019 
3020 /++
3021     Similar to $(LREF drop) and $(D dropBack) but they call
3022     $(D range.$(LREF popFrontExactly)(n)) and $(D range.popBackExactly(n))
3023     instead.
3024 
3025     Note: Unlike $(D drop), $(D dropExactly) will assume that the
3026     range holds at least $(D n) elements. This makes $(D dropExactly)
3027     faster than $(D drop), but it also means that if $(D range) does
3028     not contain at least $(D n) elements, it will attempt to call $(D popFront)
3029     on an empty range, which is undefined behavior. So, only use
3030     $(D popFrontExactly) when it is guaranteed that $(D range) holds at least
3031     $(D n) elements.
3032 
3033     Params:
3034         range = the input range to drop from
3035         n = the number of elements to drop
3036 
3037     Returns:
3038         `range` with `n` elements dropped
3039 
3040     See_Also:
3041         $(REF popFrontExcatly, std, _range, primitives),
3042         $(REF popBackExcatly, std, _range, primitives)
3043 +/
3044 R dropExactly(R)(R range, size_t n)
3045 if (isInputRange!R)
3046 {
3047     popFrontExactly(range, n);
3048     return range;
3049 }
3050 /// ditto
3051 R dropBackExactly(R)(R range, size_t n)
3052 if (isBidirectionalRange!R)
3053 {
3054     popBackExactly(range, n);
3055     return range;
3056 }
3057 
3058 ///
3059 @safe unittest
3060 {
3061     import std.algorithm.comparison : equal;
3062     import std.algorithm.iteration : filterBidirectional;
3063 
3064     auto a = [1, 2, 3];
3065     assert(a.dropExactly(2) == [3]);
3066     assert(a.dropBackExactly(2) == [1]);
3067 
3068     string s = "日本語";
3069     assert(s.dropExactly(2) == "語");
3070     assert(s.dropBackExactly(2) == "日");
3071 
3072     auto bd = filterBidirectional!"true"([1, 2, 3]);
3073     assert(bd.dropExactly(2).equal([3]));
3074     assert(bd.dropBackExactly(2).equal([1]));
3075 }
3076 
3077 /++
3078     Convenience function which calls
3079     $(D range.popFront()) and returns $(D range). $(D dropOne)
3080     makes it easier to pop an element from a range
3081     and then pass it to another function within a single expression,
3082     whereas $(D popFront) would require multiple statements.
3083 
3084     $(D dropBackOne) provides the same functionality but instead calls
3085     $(D range.popBack()).
3086 +/
3087 R dropOne(R)(R range)
3088 if (isInputRange!R)
3089 {
3090     range.popFront();
3091     return range;
3092 }
3093 /// ditto
3094 R dropBackOne(R)(R range)
3095 if (isBidirectionalRange!R)
3096 {
3097     range.popBack();
3098     return range;
3099 }
3100 
3101 ///
3102 pure @safe nothrow unittest
3103 {
3104     import std.algorithm.comparison : equal;
3105     import std.algorithm.iteration : filterBidirectional;
3106     import std.container.dlist : DList;
3107 
3108     auto dl = DList!int(9, 1, 2, 3, 9);
3109     assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
3110 
3111     auto a = [1, 2, 3];
3112     assert(a.dropOne() == [2, 3]);
3113     assert(a.dropBackOne() == [1, 2]);
3114 
3115     string s = "日本語";
3116     import std.exception : assumeWontThrow;
3117     assert(assumeWontThrow(s.dropOne() == "本語"));
3118     assert(assumeWontThrow(s.dropBackOne() == "日本"));
3119 
3120     auto bd = filterBidirectional!"true"([1, 2, 3]);
3121     assert(bd.dropOne().equal([2, 3]));
3122     assert(bd.dropBackOne().equal([1, 2]));
3123 }
3124 
3125 /**
3126 Create a range which repeats one value forever.
3127 
3128 Params:
3129     value = the value to repeat
3130 
3131 Returns:
3132     An infinite random access range with slicing.
3133 */
Repeat(T)3134 struct Repeat(T)
3135 {
3136 private:
3137     //Store a non-qualified T when possible: This is to make Repeat assignable
3138     static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable)))
3139     {
3140         import std.typecons : Rebindable;
3141         alias UT = Rebindable!T;
3142     }
3143     else static if (is(T : Unqual!T) && is(Unqual!T : T))
3144         alias UT = Unqual!T;
3145     else
3146         alias UT = T;
3147     UT _value;
3148 
3149 public:
3150     /// Range primitives
3151     @property inout(T) front() inout { return _value; }
3152 
3153     /// ditto
3154     @property inout(T) back() inout { return _value; }
3155 
3156     /// ditto
3157     enum bool empty = false;
3158 
3159     /// ditto
3160     void popFront() {}
3161 
3162     /// ditto
3163     void popBack() {}
3164 
3165     /// ditto
3166     @property auto save() inout { return this; }
3167 
3168     /// ditto
3169     inout(T) opIndex(size_t) inout { return _value; }
3170 
3171     /// ditto
3172     auto opSlice(size_t i, size_t j)
3173     in
3174     {
3175         assert(
3176             i <= j,
3177             "Attempting to slice a Repeat with a larger first argument than the second."
3178         );
3179     }
3180     body
3181     {
3182         return this.takeExactly(j - i);
3183     }
3184     private static struct DollarToken {}
3185 
3186     /// ditto
3187     enum opDollar = DollarToken.init;
3188 
3189     /// ditto
3190     auto opSlice(size_t, DollarToken) inout { return this; }
3191 }
3192 
3193 /// Ditto
3194 Repeat!T repeat(T)(T value) { return Repeat!T(value); }
3195 
3196 ///
3197 pure @safe nothrow unittest
3198 {
3199     import std.algorithm.comparison : equal;
3200 
3201     assert(equal(5.repeat().take(4), [ 5, 5, 5, 5 ]));
3202 }
3203 
3204 pure @safe nothrow unittest
3205 {
3206     import std.algorithm.comparison : equal;
3207 
3208     auto  r = repeat(5);
3209     alias R = typeof(r);
3210     static assert(isBidirectionalRange!R);
3211     static assert(isForwardRange!R);
3212     static assert(isInfinite!R);
3213     static assert(hasSlicing!R);
3214 
3215     assert(r.back == 5);
3216     assert(r.front == 5);
3217     assert(r.take(4).equal([ 5, 5, 5, 5 ]));
3218     assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
3219 
3220     R r2 = r[5 .. $];
3221     assert(r2.back == 5);
3222     assert(r2.front == 5);
3223 }
3224 
3225 /**
3226    Repeats $(D value) exactly $(D n) times. Equivalent to $(D
3227    take(repeat(value), n)).
3228 */
3229 Take!(Repeat!T) repeat(T)(T value, size_t n)
3230 {
3231     return take(repeat(value), n);
3232 }
3233 
3234 ///
3235 pure @safe nothrow @nogc unittest
3236 {
3237     import std.algorithm.comparison : equal;
3238 
3239     assert(equal(5.repeat(4), 5.repeat().take(4)));
3240 }
3241 
3242 pure @safe nothrow unittest //12007
3243 {
3244     static class C{}
3245     Repeat!(immutable int) ri;
3246     ri = ri.save;
3247     Repeat!(immutable C) rc;
3248     rc = rc.save;
3249 
3250     import std.algorithm.setops : cartesianProduct;
3251     import std.algorithm.comparison : equal;
3252     import std.typecons : tuple;
3253     immutable int[] A = [1,2,3];
3254     immutable int[] B = [4,5,6];
3255 
3256     assert(equal(cartesianProduct(A,B),
3257         [
3258             tuple(1, 4), tuple(1, 5), tuple(1, 6),
3259             tuple(2, 4), tuple(2, 5), tuple(2, 6),
3260             tuple(3, 4), tuple(3, 5), tuple(3, 6),
3261         ]));
3262 }
3263 
3264 /**
3265 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
3266 whose front is defined by successive calls to `fun()`.
3267 This is especially useful to call function with global side effects (random
3268 functions), or to create ranges expressed as a single delegate, rather than
3269 an entire `front`/`popFront`/`empty` structure.
3270 `fun` maybe be passed either a template alias parameter (existing
3271 function, delegate, struct type defining `static opCall`) or
3272 a run-time value argument (delegate, function object).
3273 The result range models an InputRange
3274 ($(REF isInputRange, std,range,primitives)).
3275 The resulting range will call `fun()` on construction, and every call to
3276 `popFront`, and the cached value will be returned when `front` is called.
3277 
3278 Returns: an `inputRange` where each element represents another call to fun.
3279 */
3280 auto generate(Fun)(Fun fun)
3281 if (isCallable!fun)
3282 {
3283     auto gen = Generator!(Fun)(fun);
3284     gen.popFront(); // prime the first element
3285     return gen;
3286 }
3287 
3288 /// ditto
3289 auto generate(alias fun)()
3290 if (isCallable!fun)
3291 {
3292     auto gen = Generator!(fun)();
3293     gen.popFront(); // prime the first element
3294     return gen;
3295 }
3296 
3297 ///
3298 @safe pure unittest
3299 {
3300     import std.algorithm.comparison : equal;
3301     import std.algorithm.iteration : map;
3302 
3303     int i = 1;
3304     auto powersOfTwo = generate!(() => i *= 2)().take(10);
3305     assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
3306 }
3307 
3308 ///
3309 @safe pure unittest
3310 {
3311     import std.algorithm.comparison : equal;
3312 
3313     //Returns a run-time delegate
infiniteIota(T)3314     auto infiniteIota(T)(T low, T high)
3315     {
3316         T i = high;
3317         return (){if (i == high) i = low; return i++;};
3318     }
3319     //adapted as a range.
3320     assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
3321 }
3322 
3323 ///
3324 @safe unittest
3325 {
3326     import std.format : format;
3327     import std.random : uniform;
3328 
3329     auto r = generate!(() => uniform(0, 6)).take(10);
3330     format("%(%s %)", r);
3331 }
3332 
Generator(Fun...)3333 private struct Generator(Fun...)
3334 {
3335     static assert(Fun.length == 1);
3336     static assert(isInputRange!Generator);
3337 
3338 private:
3339     static if (is(Fun[0]))
3340         Fun[0] fun;
3341     else
3342         alias fun = Fun[0];
3343 
3344     enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
3345     static if (returnByRef_)
3346         ReturnType!fun *elem_;
3347     else
3348         ReturnType!fun elem_;
3349 public:
3350     /// Range primitives
3351     enum empty = false;
3352 
3353     static if (returnByRef_)
3354     {
3355         /// ditto
3356         ref front() @property
3357         {
3358             return *elem_;
3359         }
3360         /// ditto
3361         void popFront()
3362         {
3363             elem_ = &fun();
3364         }
3365     }
3366     else
3367     {
3368         /// ditto
3369         auto front() @property
3370         {
3371             return elem_;
3372         }
3373         /// ditto
3374         void popFront()
3375         {
3376             elem_ = fun();
3377         }
3378     }
3379 }
3380 
3381 @safe unittest
3382 {
3383     import std.algorithm.comparison : equal;
3384 
3385     struct StaticOpCall
3386     {
opCallStaticOpCall3387         static ubyte opCall() { return 5 ; }
3388     }
3389 
3390     assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
3391 }
3392 
3393 @safe pure unittest
3394 {
3395     import std.algorithm.comparison : equal;
3396 
3397     struct OpCall
3398     {
opCallOpCall3399         ubyte opCall() @safe pure { return 5 ; }
3400     }
3401 
3402     OpCall op;
3403     assert(equal(generate(op).take(10), repeat(5).take(10)));
3404 }
3405 
3406 // verify ref mechanism works
3407 @system unittest
3408 {
3409     int[10] arr;
3410     int idx;
3411 
fun()3412     ref int fun() {
3413         auto x = idx++;
3414         idx %= arr.length;
3415         return arr[x];
3416     }
3417     int y = 1;
3418     foreach (ref x; generate!(fun).take(20))
3419     {
3420         x += y++;
3421     }
3422     import std.algorithm.comparison : equal;
3423     assert(equal(arr[], iota(12, 32, 2)));
3424 }
3425 
3426 // assure front isn't the mechanism to make generate go to the next element.
3427 @safe unittest
3428 {
3429     int i;
3430     auto g = generate!(() => ++i);
3431     auto f = g.front;
3432     assert(f == g.front);
3433     g = g.drop(5); // reassign because generate caches
3434     assert(g.front == f + 5);
3435 }
3436 
3437 /**
3438 Repeats the given forward range ad infinitum. If the original range is
3439 infinite (fact that would make $(D Cycle) the identity application),
3440 $(D Cycle) detects that and aliases itself to the range type
3441 itself. That works for non-forward ranges too.
3442 If the original range has random access, $(D Cycle) offers
3443 random access and also offers a constructor taking an initial position
3444 $(D index). $(D Cycle) works with static arrays in addition to ranges,
3445 mostly for performance reasons.
3446 
3447 Note: The input range must not be empty.
3448 
3449 Tip: This is a great way to implement simple circular buffers.
3450 */
3451 struct Cycle(R)
3452 if (isForwardRange!R && !isInfinite!R)
3453 {
3454     static if (isRandomAccessRange!R && hasLength!R)
3455     {
3456         private R _original;
3457         private size_t _index;
3458 
3459         /// Range primitives
3460         this(R input, size_t index = 0)
3461         {
3462             _original = input;
3463             _index = index % _original.length;
3464         }
3465 
3466         /// ditto
front()3467         @property auto ref front()
3468         {
3469             return _original[_index];
3470         }
3471 
3472         static if (is(typeof((cast(const R)_original)[_index])))
3473         {
3474             /// ditto
front()3475             @property auto ref front() const
3476             {
3477                 return _original[_index];
3478             }
3479         }
3480 
3481         static if (hasAssignableElements!R)
3482         {
3483             /// ditto
3484             @property void front(ElementType!R val)
3485             {
3486                 _original[_index] = val;
3487             }
3488         }
3489 
3490         /// ditto
3491         enum bool empty = false;
3492 
3493         /// ditto
popFront()3494         void popFront()
3495         {
3496             ++_index;
3497             if (_index >= _original.length)
3498                 _index = 0;
3499         }
3500 
3501         /// ditto
opIndex(size_t n)3502         auto ref opIndex(size_t n)
3503         {
3504             return _original[(n + _index) % _original.length];
3505         }
3506 
3507         static if (is(typeof((cast(const R)_original)[_index])) &&
3508                    is(typeof((cast(const R)_original).length)))
3509         {
3510             /// ditto
opIndex(size_t n)3511             auto ref opIndex(size_t n) const
3512             {
3513                 return _original[(n + _index) % _original.length];
3514             }
3515         }
3516 
3517         static if (hasAssignableElements!R)
3518         {
3519             /// ditto
3520             void opIndexAssign(ElementType!R val, size_t n)
3521             {
3522                 _original[(n + _index) % _original.length] = val;
3523             }
3524         }
3525 
3526         /// ditto
save()3527         @property Cycle save()
3528         {
3529             //No need to call _original.save, because Cycle never actually modifies _original
3530             return Cycle(_original, _index);
3531         }
3532 
3533         private static struct DollarToken {}
3534 
3535         /// ditto
3536         enum opDollar = DollarToken.init;
3537 
3538         static if (hasSlicing!R)
3539         {
3540             /// ditto
opSlice(size_t i,size_t j)3541             auto opSlice(size_t i, size_t j)
3542             in
3543             {
3544                 assert(i <= j);
3545             }
3546             body
3547             {
3548                 return this[i .. $].takeExactly(j - i);
3549             }
3550 
3551             /// ditto
opSlice(size_t i,DollarToken)3552             auto opSlice(size_t i, DollarToken)
3553             {
3554                 return typeof(this)(_original, _index + i);
3555             }
3556         }
3557     }
3558     else
3559     {
3560         private R _original;
3561         private R _current;
3562 
3563         /// ditto
this(R input)3564         this(R input)
3565         {
3566             _original = input;
3567             _current = input.save;
3568         }
3569 
3570         /// ditto
front()3571         @property auto ref front()
3572         {
3573             return _current.front;
3574         }
3575 
3576         static if (is(typeof((cast(const R)_current).front)))
3577         {
3578             /// ditto
front()3579             @property auto ref front() const
3580             {
3581                 return _current.front;
3582             }
3583         }
3584 
3585         static if (hasAssignableElements!R)
3586         {
3587             /// ditto
3588             @property auto front(ElementType!R val)
3589             {
3590                 return _current.front = val;
3591             }
3592         }
3593 
3594         /// ditto
3595         enum bool empty = false;
3596 
3597         /// ditto
popFront()3598         void popFront()
3599         {
3600             _current.popFront();
3601             if (_current.empty)
3602                 _current = _original.save;
3603         }
3604 
3605         /// ditto
save()3606         @property Cycle save()
3607         {
3608             //No need to call _original.save, because Cycle never actually modifies _original
3609             Cycle ret = this;
3610             ret._original = _original;
3611             ret._current =  _current.save;
3612             return ret;
3613         }
3614     }
3615 }
3616 
3617 /// ditto
3618 template Cycle(R)
3619 if (isInfinite!R)
3620 {
3621     alias Cycle = R;
3622 }
3623 
3624 ///
3625 struct Cycle(R)
3626 if (isStaticArray!R)
3627 {
3628     private alias ElementType = typeof(R.init[0]);
3629     private ElementType* _ptr;
3630     private size_t _index;
3631 
3632 nothrow:
3633 
3634     /// Range primitives
3635     this(ref R input, size_t index = 0) @system
3636     {
3637         _ptr = input.ptr;
3638         _index = index % R.length;
3639     }
3640 
3641     /// ditto
inout(ElementType)3642     @property ref inout(ElementType) front() inout @safe
3643     {
3644         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
3645         {
3646             return p[idx];
3647         }
3648         return trustedPtrIdx(_ptr, _index);
3649     }
3650 
3651     /// ditto
3652     enum bool empty = false;
3653 
3654     /// ditto
popFront()3655     void popFront() @safe
3656     {
3657         ++_index;
3658         if (_index >= R.length)
3659             _index = 0;
3660     }
3661 
3662     /// ditto
inout(ElementType)3663     ref inout(ElementType) opIndex(size_t n) inout @safe
3664     {
3665         static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
3666         {
3667             return p[idx % R.length];
3668         }
3669         return trustedPtrIdx(_ptr, n + _index);
3670     }
3671 
3672     /// ditto
inout(Cycle)3673     @property inout(Cycle) save() inout @safe
3674     {
3675         return this;
3676     }
3677 
3678     private static struct DollarToken {}
3679     /// ditto
3680     enum opDollar = DollarToken.init;
3681 
3682     /// ditto
opSlice(size_t i,size_t j)3683     auto opSlice(size_t i, size_t j) @safe
3684     in
3685     {
3686         assert(
3687             i <= j,
3688             "Attempting to slice a Repeat with a larger first argument than the second."
3689         );
3690     }
3691     body
3692     {
3693         return this[i .. $].takeExactly(j - i);
3694     }
3695 
3696     /// ditto
opSlice(size_t i,DollarToken)3697     inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
3698     {
3699         static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
3700         {
3701             return cast(inout) Cycle(*cast(R*)(p), idx);
3702         }
3703         return trustedCtor(_ptr, _index + i);
3704     }
3705 }
3706 
3707 /// Ditto
3708 auto cycle(R)(R input)
3709 if (isInputRange!R)
3710 {
3711     static assert(isForwardRange!R || isInfinite!R,
3712         "Cycle requires a forward range argument unless it's statically known"
3713          ~ " to be infinite");
3714     assert(!input.empty, "Attempting to pass an empty input to cycle");
3715     static if (isInfinite!R) return input;
3716     else return Cycle!R(input);
3717 }
3718 
3719 ///
3720 @safe unittest
3721 {
3722     import std.algorithm.comparison : equal;
3723     import std.range : cycle, take;
3724 
3725     // Here we create an infinitive cyclic sequence from [1, 2]
3726     // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
3727     // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
3728     // and compare them with the expected values for equality.
3729     assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
3730 }
3731 
3732 /// Ditto
3733 Cycle!R cycle(R)(R input, size_t index = 0)
3734 if (isRandomAccessRange!R && !isInfinite!R)
3735 {
3736     assert(!input.empty, "Attempting to pass an empty input to cycle");
3737     return Cycle!R(input, index);
3738 }
3739 
3740 /// Ditto
3741 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
3742 if (isStaticArray!R)
3743 {
3744     return Cycle!R(input, index);
3745 }
3746 
3747 @safe unittest
3748 {
3749     import std.algorithm.comparison : equal;
3750     import std.internal.test.dummyrange : AllDummyRanges;
3751 
3752     static assert(isForwardRange!(Cycle!(uint[])));
3753 
3754     // Make sure ref is getting propagated properly.
3755     int[] nums = [1,2,3];
3756     auto c2 = cycle(nums);
3757     c2[3]++;
3758     assert(nums[0] == 2);
3759 
3760     immutable int[] immarr = [1, 2, 3];
3761 
foreach(DummyType;AllDummyRanges)3762     foreach (DummyType; AllDummyRanges)
3763     {
3764         static if (isForwardRange!DummyType)
3765         {
3766             DummyType dummy;
3767             auto cy = cycle(dummy);
3768             static assert(isForwardRange!(typeof(cy)));
3769             auto t = take(cy, 20);
3770             assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
3771 
3772             const cRange = cy;
3773             assert(cRange.front == 1);
3774 
3775             static if (hasAssignableElements!DummyType)
3776             {
3777                 {
3778                     cy.front = 66;
3779                     scope(exit) cy.front = 1;
3780                     assert(dummy.front == 66);
3781                 }
3782 
3783                 static if (isRandomAccessRange!DummyType)
3784                 {
3785                     {
3786                         cy[10] = 66;
3787                         scope(exit) cy[10] = 1;
3788                         assert(dummy.front == 66);
3789                     }
3790 
3791                     assert(cRange[10] == 1);
3792                 }
3793             }
3794 
3795             static if (hasSlicing!DummyType)
3796             {
3797                 auto slice = cy[5 .. 15];
3798                 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
3799                 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
3800 
3801                 auto infSlice = cy[7 .. $];
3802                 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
3803                 static assert(isInfinite!(typeof(infSlice)));
3804             }
3805         }
3806     }
3807 }
3808 
3809 @system unittest // For static arrays.
3810 {
3811     import std.algorithm.comparison : equal;
3812 
3813     int[3] a = [ 1, 2, 3 ];
3814     static assert(isStaticArray!(typeof(a)));
3815     auto c = cycle(a);
3816     assert(a.ptr == c._ptr);
3817     assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
3818     static assert(isForwardRange!(typeof(c)));
3819 
3820     // Test qualifiers on slicing.
3821     alias C = typeof(c);
3822     static assert(is(typeof(c[1 .. $]) == C));
3823     const cConst = c;
3824     static assert(is(typeof(cConst[1 .. $]) == const(C)));
3825 }
3826 
3827 @safe unittest // For infinite ranges
3828 {
3829     struct InfRange
3830     {
popFrontInfRange3831         void popFront() { }
frontInfRange3832         @property int front() { return 0; }
3833         enum empty = false;
saveInfRange3834         auto save() { return this; }
3835     }
3836     struct NonForwardInfRange
3837     {
popFront()3838         void popFront() { }
front()3839         @property int front() { return 0; }
3840         enum empty = false;
3841     }
3842 
3843     InfRange i;
3844     NonForwardInfRange j;
3845     auto c = cycle(i);
3846     assert(c == i);
3847     //make sure it can alias out even non-forward infinite ranges
3848     static assert(is(typeof(j.cycle) == typeof(j)));
3849 }
3850 
3851 @safe unittest
3852 {
3853     import std.algorithm.comparison : equal;
3854 
3855     int[5] arr = [0, 1, 2, 3, 4];
3856     auto cleD = cycle(arr[]); //Dynamic
3857     assert(equal(cleD[5 .. 10], arr[]));
3858 
3859     //n is a multiple of 5 worth about 3/4 of size_t.max
3860     auto n = size_t.max/4 + size_t.max/2;
3861     n -= n % 5;
3862 
3863     //Test index overflow
3864     foreach (_ ; 0 .. 10)
3865     {
3866         cleD = cleD[n .. $];
3867         assert(equal(cleD[5 .. 10], arr[]));
3868     }
3869 }
3870 
3871 @system unittest
3872 {
3873     import std.algorithm.comparison : equal;
3874 
3875     int[5] arr = [0, 1, 2, 3, 4];
3876     auto cleS = cycle(arr);   //Static
3877     assert(equal(cleS[5 .. 10], arr[]));
3878 
3879     //n is a multiple of 5 worth about 3/4 of size_t.max
3880     auto n = size_t.max/4 + size_t.max/2;
3881     n -= n % 5;
3882 
3883     //Test index overflow
3884     foreach (_ ; 0 .. 10)
3885     {
3886         cleS = cleS[n .. $];
3887         assert(equal(cleS[5 .. 10], arr[]));
3888     }
3889 }
3890 
3891 @system unittest
3892 {
3893     import std.algorithm.comparison : equal;
3894 
3895     int[1] arr = [0];
3896     auto cleS = cycle(arr);
3897     cleS = cleS[10 .. $];
3898     assert(equal(cleS[5 .. 10], 0.repeat(5)));
3899     assert(cleS.front == 0);
3900 }
3901 
3902 @system unittest //10845
3903 {
3904     import std.algorithm.comparison : equal;
3905     import std.algorithm.iteration : filter;
3906 
3907     auto a = inputRangeObject(iota(3).filter!"true");
3908     assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
3909 }
3910 
3911 @safe unittest // 12177
3912 {
3913     static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
3914 }
3915 
3916 // Issue 13390
3917 @system unittest
3918 {
3919     import core.exception : AssertError;
3920     import std.exception : assertThrown;
3921     assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
3922 }
3923 
3924 private alias lengthType(R) = typeof(R.init.length.init);
3925 
3926 /**
3927    Iterate several ranges in lockstep. The element type is a proxy tuple
3928    that allows accessing the current element in the $(D n)th range by
3929    using $(D e[n]).
3930 
3931    `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
3932    bundle its elements and uses the `opApply` protocol.
3933    `lockstep` allows reference access to the elements in
3934    `foreach` iterations.
3935 
3936     Params:
3937         sp = controls what `zip` will do if the _ranges are different lengths
3938         ranges = the ranges to zip together
3939     Returns:
3940         At minimum, an input range. `Zip` offers the lowest range facilities
3941         of all components, e.g. it offers random access iff all ranges offer
3942         random access, and also offers mutation and swapping if all ranges offer
3943         it. Due to this, `Zip` is extremely powerful because it allows manipulating
3944         several ranges in lockstep.
3945     Throws:
3946         An `Exception` if all of the _ranges are not the same length and
3947         `sp` is set to `StoppingPolicy.requireSameLength`.
3948 */
3949 struct Zip(Ranges...)
3950 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
3951 {
3952     import std.format : format; //for generic mixins
3953     import std.typecons : Tuple;
3954 
3955     alias R = Ranges;
3956     private R ranges;
3957     alias ElementType = Tuple!(staticMap!(.ElementType, R));
3958     private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
3959 
3960 /**
3961    Builds an object. Usually this is invoked indirectly by using the
3962    $(LREF zip) function.
3963  */
3964     this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
3965     {
3966         ranges[] = rs[];
3967         stoppingPolicy = s;
3968     }
3969 
3970 /**
3971    Returns $(D true) if the range is at end. The test depends on the
3972    stopping policy.
3973 */
3974     static if (allSatisfy!(isInfinite, R))
3975     {
3976         // BUG:  Doesn't propagate infiniteness if only some ranges are infinite
3977         //       and s == StoppingPolicy.longest.  This isn't fixable in the
3978         //       current design since StoppingPolicy is known only at runtime.
3979         enum bool empty = false;
3980     }
3981     else
3982     {
3983         ///
empty()3984         @property bool empty()
3985         {
3986             import std.exception : enforce;
3987             import std.meta : anySatisfy;
3988 
3989             final switch (stoppingPolicy)
3990             {
3991             case StoppingPolicy.shortest:
3992                 foreach (i, Unused; R)
3993                 {
3994                     if (ranges[i].empty) return true;
3995                 }
3996                 return false;
3997             case StoppingPolicy.longest:
3998                 static if (anySatisfy!(isInfinite, R))
3999                 {
4000                     return false;
4001                 }
4002                 else
4003                 {
4004                     foreach (i, Unused; R)
4005                     {
4006                         if (!ranges[i].empty) return false;
4007                     }
4008                     return true;
4009                 }
4010             case StoppingPolicy.requireSameLength:
4011                 foreach (i, Unused; R[1 .. $])
4012                 {
4013                     enforce(ranges[0].empty ==
4014                             ranges[i + 1].empty,
4015                             "Inequal-length ranges passed to Zip");
4016                 }
4017                 return ranges[0].empty;
4018             }
4019             assert(false);
4020         }
4021     }
4022 
4023     static if (allSatisfy!(isForwardRange, R))
4024     {
4025         ///
save()4026         @property Zip save()
4027         {
4028             //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
4029             return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4030         }
4031     }
4032 
4033     private .ElementType!(R[i]) tryGetInit(size_t i)()
4034     {
4035         alias E = .ElementType!(R[i]);
4036         static if (!is(typeof({static E i;})))
4037             throw new Exception("Range with non-default constructable elements exhausted.");
4038         else
4039             return E.init;
4040     }
4041 
4042 /**
4043    Returns the current iterated element.
4044 */
front()4045     @property ElementType front()
4046     {
4047         @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
4048         //ElementType(tryGetFront!0, tryGetFront!1, ...)
4049         return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
4050     }
4051 
4052 /**
4053    Sets the front of all iterated ranges.
4054 */
4055     static if (allSatisfy!(hasAssignableElements, R))
4056     {
front(ElementType v)4057         @property void front(ElementType v)
4058         {
4059             foreach (i, Unused; R)
4060             {
4061                 if (!ranges[i].empty)
4062                 {
4063                     ranges[i].front = v[i];
4064                 }
4065             }
4066         }
4067     }
4068 
4069 /**
4070    Moves out the front.
4071 */
4072     static if (allSatisfy!(hasMobileElements, R))
4073     {
moveFront()4074         ElementType moveFront()
4075         {
4076             @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4077             //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
4078             return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
4079         }
4080     }
4081 
4082 /**
4083    Returns the rightmost element.
4084 */
4085     static if (allSatisfy!(isBidirectionalRange, R))
4086     {
back()4087         @property ElementType back()
4088         {
4089             //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4090 
4091             @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
4092             //ElementType(tryGetBack!0, tryGetBack!1, ...)
4093             return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
4094         }
4095 
4096 /**
4097    Moves out the back.
4098 */
4099         static if (allSatisfy!(hasMobileElements, R))
4100         {
moveBack()4101             ElementType moveBack()
4102             {
4103                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4104 
4105                 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4106                 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
4107                 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
4108             }
4109         }
4110 
4111 /**
4112    Returns the current iterated element.
4113 */
4114         static if (allSatisfy!(hasAssignableElements, R))
4115         {
back(ElementType v)4116             @property void back(ElementType v)
4117             {
4118                 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
4119                 //Not sure the call is even legal for StoppingPolicy.longest
4120 
4121                 foreach (i, Unused; R)
4122                 {
4123                     if (!ranges[i].empty)
4124                     {
4125                         ranges[i].back = v[i];
4126                     }
4127                 }
4128             }
4129         }
4130     }
4131 
4132 /**
4133    Advances to the next element in all controlled ranges.
4134 */
popFront()4135     void popFront()
4136     {
4137         import std.exception : enforce;
4138 
4139         final switch (stoppingPolicy)
4140         {
4141         case StoppingPolicy.shortest:
4142             foreach (i, Unused; R)
4143             {
4144                 assert(!ranges[i].empty);
4145                 ranges[i].popFront();
4146             }
4147             break;
4148         case StoppingPolicy.longest:
4149             foreach (i, Unused; R)
4150             {
4151                 if (!ranges[i].empty) ranges[i].popFront();
4152             }
4153             break;
4154         case StoppingPolicy.requireSameLength:
4155             foreach (i, Unused; R)
4156             {
4157                 enforce(!ranges[i].empty, "Invalid Zip object");
4158                 ranges[i].popFront();
4159             }
4160             break;
4161         }
4162     }
4163 
4164 /**
4165    Calls $(D popBack) for all controlled ranges.
4166 */
4167     static if (allSatisfy!(isBidirectionalRange, R))
4168     {
popBack()4169         void popBack()
4170         {
4171             //TODO: Fixme! In case of jaggedness, this is wrong.
4172             import std.exception : enforce;
4173 
4174             final switch (stoppingPolicy)
4175             {
4176             case StoppingPolicy.shortest:
4177                 foreach (i, Unused; R)
4178                 {
4179                     assert(!ranges[i].empty);
4180                     ranges[i].popBack();
4181                 }
4182                 break;
4183             case StoppingPolicy.longest:
4184                 foreach (i, Unused; R)
4185                 {
4186                     if (!ranges[i].empty) ranges[i].popBack();
4187                 }
4188                 break;
4189             case StoppingPolicy.requireSameLength:
4190                 foreach (i, Unused; R)
4191                 {
4192                     enforce(!ranges[i].empty, "Invalid Zip object");
4193                     ranges[i].popBack();
4194                 }
4195                 break;
4196             }
4197         }
4198     }
4199 
4200 /**
4201    Returns the length of this range. Defined only if all ranges define
4202    $(D length).
4203 */
4204     static if (allSatisfy!(hasLength, R))
4205     {
length()4206         @property auto length()
4207         {
4208             static if (Ranges.length == 1)
4209                 return ranges[0].length;
4210             else
4211             {
4212                 if (stoppingPolicy == StoppingPolicy.requireSameLength)
4213                     return ranges[0].length;
4214 
4215                 //[min|max](ranges[0].length, ranges[1].length, ...)
4216                 import std.algorithm.comparison : min, max;
4217                 if (stoppingPolicy == StoppingPolicy.shortest)
4218                     return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4219                 else
4220                     return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4221             }
4222         }
4223 
4224         alias opDollar = length;
4225     }
4226 
4227 /**
4228    Returns a slice of the range. Defined only if all range define
4229    slicing.
4230 */
4231     static if (allSatisfy!(hasSlicing, R))
4232     {
opSlice(size_t from,size_t to)4233         auto opSlice(size_t from, size_t to)
4234         {
4235             //Slicing an infinite range yields the type Take!R
4236             //For finite ranges, the type Take!R aliases to R
4237             alias ZipResult = Zip!(staticMap!(Take, R));
4238 
4239             //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
4240             return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4241         }
4242     }
4243 
4244 /**
4245    Returns the $(D n)th element in the composite range. Defined if all
4246    ranges offer random access.
4247 */
4248     static if (allSatisfy!(isRandomAccessRange, R))
4249     {
opIndex(size_t n)4250         ElementType opIndex(size_t n)
4251         {
4252             //TODO: Fixme! This may create an out of bounds access
4253             //for StoppingPolicy.longest
4254 
4255             //ElementType(ranges[0][n], ranges[1][n], ...)
4256             return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
4257         }
4258 
4259 /**
4260    Assigns to the $(D n)th element in the composite range. Defined if
4261    all ranges offer random access.
4262 */
4263         static if (allSatisfy!(hasAssignableElements, R))
4264         {
opIndexAssign(ElementType v,size_t n)4265             void opIndexAssign(ElementType v, size_t n)
4266             {
4267                 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
4268                 foreach (i, Range; R)
4269                 {
4270                     ranges[i][n] = v[i];
4271                 }
4272             }
4273         }
4274 
4275 /**
4276    Destructively reads the $(D n)th element in the composite
4277    range. Defined if all ranges offer random access.
4278 */
4279         static if (allSatisfy!(hasMobileElements, R))
4280         {
moveAt(size_t n)4281             ElementType moveAt(size_t n)
4282             {
4283                 //TODO: Fixme! This may create an out of bounds access
4284                 //for StoppingPolicy.longest
4285 
4286                 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
4287                 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
4288             }
4289         }
4290     }
4291 }
4292 
4293 /// Ditto
4294 auto zip(Ranges...)(Ranges ranges)
4295 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4296 {
4297     return Zip!Ranges(ranges);
4298 }
4299 
4300 ///
4301 pure @safe unittest
4302 {
4303     import std.algorithm.comparison : equal;
4304     import std.algorithm.iteration : map;
4305 
4306     // pairwise sum
4307     auto arr = [0, 1, 2];
4308     assert(zip(arr, arr.dropOne).map!"a[0] + a[1]".equal([1, 3]));
4309 }
4310 
4311 ///
4312 pure @safe unittest
4313 {
4314     import std.conv : to;
4315 
4316     int[] a = [ 1, 2, 3 ];
4317     string[] b = [ "a", "b", "c" ];
4318     string[] result;
4319 
foreach(tup;zip (a,b))4320     foreach (tup; zip(a, b))
4321     {
4322         result ~= tup[0].to!string ~ tup[1];
4323     }
4324 
4325     assert(result == [ "1a", "2b", "3c" ]);
4326 
4327     size_t idx = 0;
4328     // unpacking tuple elements with foreach
foreach(e1,e2;zip (a,b))4329     foreach (e1, e2; zip(a, b))
4330     {
4331         assert(e1 == a[idx]);
4332         assert(e2 == b[idx]);
4333         ++idx;
4334     }
4335 }
4336 
4337 /// $(D zip) is powerful - the following code sorts two arrays in parallel:
4338 pure @safe unittest
4339 {
4340     import std.algorithm.sorting : sort;
4341 
4342     int[] a = [ 1, 2, 3 ];
4343     string[] b = [ "a", "c", "b" ];
4344     zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
4345 
4346     assert(a == [ 3, 2, 1 ]);
4347     // b is sorted according to a's sorting
4348     assert(b == [ "b", "c", "a" ]);
4349 }
4350 
4351 /// Ditto
4352 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
4353 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4354 {
4355     return Zip!Ranges(ranges, sp);
4356 }
4357 
4358 /**
4359    Dictates how iteration in a $(D Zip) should stop. By default stop at
4360    the end of the shortest of all ranges.
4361 */
4362 enum StoppingPolicy
4363 {
4364     /// Stop when the shortest range is exhausted
4365     shortest,
4366     /// Stop when the longest range is exhausted
4367     longest,
4368     /// Require that all ranges are equal
4369     requireSameLength,
4370 }
4371 
4372 @system unittest
4373 {
4374     import std.algorithm.comparison : equal;
4375     import std.algorithm.iteration : filter, map;
4376     import std.algorithm.mutation : swap;
4377     import std.algorithm.sorting : sort;
4378 
4379     import std.exception : assertThrown, assertNotThrown;
4380     import std.typecons : tuple;
4381 
4382     int[] a = [ 1, 2, 3 ];
4383     float[] b = [ 1.0, 2.0, 3.0 ];
foreach(e;zip (a,b))4384     foreach (e; zip(a, b))
4385     {
4386         assert(e[0] == e[1]);
4387     }
4388 
4389     swap(a[0], a[1]);
4390     auto z = zip(a, b);
4391     //swap(z.front(), z.back());
4392     sort!("a[0] < b[0]")(zip(a, b));
4393     assert(a == [1, 2, 3]);
4394     assert(b == [2.0, 1.0, 3.0]);
4395 
4396     z = zip(StoppingPolicy.requireSameLength, a, b);
4397     assertNotThrown(z.popBack());
4398     assertNotThrown(z.popBack());
4399     assertNotThrown(z.popBack());
4400     assert(z.empty);
4401     assertThrown(z.popBack());
4402 
4403     a = [ 1, 2, 3 ];
4404     b = [ 1.0, 2.0, 3.0 ];
4405     sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
4406     assert(a == [3, 2, 1]);
4407     assert(b == [3.0, 2.0, 1.0]);
4408 
4409     a = [];
4410     b = [];
4411     assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
4412 
4413     // Test infiniteness propagation.
4414     static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
4415 
4416     // Test stopping policies with both value and reference.
4417     auto a1 = [1, 2];
4418     auto a2 = [1, 2, 3];
4419     auto stuff = tuple(tuple(a1, a2),
4420             tuple(filter!"a"(a1), filter!"a"(a2)));
4421 
4422     alias FOO = Zip!(immutable(int)[], immutable(float)[]);
4423 
4424     foreach (t; stuff.expand)
4425     {
4426         auto arr1 = t[0];
4427         auto arr2 = t[1];
4428         auto zShortest = zip(arr1, arr2);
4429         assert(equal(map!"a[0]"(zShortest), [1, 2]));
4430         assert(equal(map!"a[1]"(zShortest), [1, 2]));
4431 
4432         try {
4433             auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
foreach(elem;zSame)4434             foreach (elem; zSame) {}
4435             assert(0);
catch(Throwable)4436         } catch (Throwable) { /* It's supposed to throw.*/ }
4437 
4438         auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
4439         assert(!zLongest.ranges[0].empty);
4440         assert(!zLongest.ranges[1].empty);
4441 
4442         zLongest.popFront();
4443         zLongest.popFront();
4444         assert(!zLongest.empty);
4445         assert(zLongest.ranges[0].empty);
4446         assert(!zLongest.ranges[1].empty);
4447 
4448         zLongest.popFront();
4449         assert(zLongest.empty);
4450     }
4451 
4452     // BUG 8900
4453     assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
4454     assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
4455 
4456     // Doesn't work yet.  Issues w/ emplace.
4457     // static assert(is(Zip!(immutable int[], immutable float[])));
4458 
4459 
4460     // These unittests pass, but make the compiler consume an absurd amount
4461     // of RAM and time.  Therefore, they should only be run if explicitly
4462     // uncommented when making changes to Zip.  Also, running them using
4463     // make -fwin32.mak unittest makes the compiler completely run out of RAM.
4464     // You need to test just this module.
4465     /+
4466      foreach (DummyType1; AllDummyRanges)
4467      {
4468          DummyType1 d1;
4469          foreach (DummyType2; AllDummyRanges)
4470          {
4471              DummyType2 d2;
4472              auto r = zip(d1, d2);
4473              assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
4474              assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
4475 
4476              static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
4477              {
4478                  static assert(isForwardRange!(typeof(r)));
4479              }
4480 
4481              static if (isBidirectionalRange!DummyType1 &&
4482                      isBidirectionalRange!DummyType2) {
4483                  static assert(isBidirectionalRange!(typeof(r)));
4484              }
4485              static if (isRandomAccessRange!DummyType1 &&
4486                      isRandomAccessRange!DummyType2) {
4487                  static assert(isRandomAccessRange!(typeof(r)));
4488              }
4489          }
4490      }
4491     +/
4492 }
4493 
4494 pure @safe unittest
4495 {
4496     import std.algorithm.sorting : sort;
4497 
4498     auto a = [5,4,3,2,1];
4499     auto b = [3,1,2,5,6];
4500     auto z = zip(a, b);
4501 
4502     sort!"a[0] < b[0]"(z);
4503 
4504     assert(a == [1, 2, 3, 4, 5]);
4505     assert(b == [6, 5, 2, 1, 3]);
4506 }
4507 
4508 @safe pure unittest
4509 {
4510     import std.algorithm.comparison : equal;
4511     import std.typecons : tuple;
4512 
4513     auto LL = iota(1L, 1000L);
4514     auto z = zip(LL, [4]);
4515 
4516     assert(equal(z, [tuple(1L,4)]));
4517 
4518     auto LL2 = iota(0L, 500L);
4519     auto z2 = zip([7], LL2);
4520     assert(equal(z2, [tuple(7, 0L)]));
4521 }
4522 
4523 // Text for Issue 11196
4524 @safe pure unittest
4525 {
4526     import std.exception : assertThrown;
4527 
4528     static struct S { @disable this(); }
4529     assert(zip((S[5]).init[]).length == 5);
4530     assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
4531     assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
4532 }
4533 
4534 @safe pure unittest //12007
4535 {
4536     static struct R
4537     {
4538         enum empty = false;
popFrontR4539         void popFront(){}
frontR4540         int front(){return 1;} @property
saveR4541         R save(){return this;} @property
4542         void opAssign(R) @disable;
4543     }
4544     R r;
4545     auto z = zip(r, r);
4546     assert(z.save == z);
4547 }
4548 
4549 pure @system unittest
4550 {
4551     import std.typecons : tuple;
4552 
4553     auto r1 = [0,1,2];
4554     auto r2 = [1,2,3];
4555     auto z1 = zip(refRange(&r1), refRange(&r2));
4556     auto z2 = z1.save;
4557     z1.popFront();
4558     assert(z1.front == tuple(1,2));
4559     assert(z2.front == tuple(0,1));
4560 }
4561 
4562 /*
4563     Generate lockstep's opApply function as a mixin string.
4564     If withIndex is true prepend a size_t index to the delegate.
4565 */
lockstepMixin(Ranges...)4566 private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
4567 {
4568     import std.format : format;
4569 
4570     string[] params;
4571     string[] emptyChecks;
4572     string[] dgArgs;
4573     string[] popFronts;
4574     string indexDef;
4575     string indexInc;
4576 
4577     if (withIndex)
4578     {
4579         params ~= "size_t";
4580         dgArgs ~= "index";
4581         if (reverse)
4582         {
4583             indexDef = q{
4584                 size_t index = ranges[0].length-1;
4585                 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
4586                         "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
4587 
4588                 foreach (range; ranges[1..$])
4589                     enforce(range.length == ranges[0].length);
4590                 };
4591             indexInc = "--index;";
4592         }
4593         else
4594         {
4595             indexDef = "size_t index = 0;";
4596             indexInc = "++index;";
4597         }
4598     }
4599 
4600     foreach (idx, Range; Ranges)
4601     {
4602         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
4603         emptyChecks ~= format("!ranges[%s].empty", idx);
4604         if (reverse)
4605         {
4606             dgArgs ~= format("ranges[%s].back", idx);
4607             popFronts ~= format("ranges[%s].popBack();", idx);
4608         }
4609         else
4610         {
4611             dgArgs ~= format("ranges[%s].front", idx);
4612             popFronts ~= format("ranges[%s].popFront();", idx);
4613         }
4614     }
4615 
4616     string name = reverse ? "opApplyReverse" : "opApply";
4617 
4618     return format(
4619     q{
4620         int %s(scope int delegate(%s) dg)
4621         {
4622             import std.exception : enforce;
4623 
4624             auto ranges = _ranges;
4625             int res;
4626             %s
4627 
4628             while (%s)
4629             {
4630                 res = dg(%s);
4631                 if (res) break;
4632                 %s
4633                 %s
4634             }
4635 
4636             if (_stoppingPolicy == StoppingPolicy.requireSameLength)
4637             {
4638                 foreach (range; ranges)
4639                     enforce(range.empty);
4640             }
4641             return res;
4642         }
4643     }, name, params.join(", "), indexDef,
4644        emptyChecks.join(" && "), dgArgs.join(", "),
4645        popFronts.join("\n                "),
4646        indexInc);
4647 }
4648 
4649 /**
4650    Iterate multiple ranges in lockstep using a $(D foreach) loop. In contrast to
4651    $(LREF zip) it allows reference access to its elements. If only a single
4652    range is passed in, the $(D Lockstep) aliases itself away.  If the
4653    ranges are of different lengths and $(D s) == $(D StoppingPolicy.shortest)
4654    stop after the shortest range is empty.  If the ranges are of different
4655    lengths and $(D s) == $(D StoppingPolicy.requireSameLength), throw an
4656    exception.  $(D s) may not be $(D StoppingPolicy.longest), and passing this
4657    will throw an exception.
4658 
4659    Iterating over $(D Lockstep) in reverse and with an index is only possible
4660    when $(D s) == $(D StoppingPolicy.requireSameLength), in order to preserve
4661    indexes. If an attempt is made at iterating in reverse when $(D s) ==
4662    $(D StoppingPolicy.shortest), an exception will be thrown.
4663 
4664    By default $(D StoppingPolicy) is set to $(D StoppingPolicy.shortest).
4665 
4666    See_Also: $(LREF zip)
4667 
4668        `lockstep` is similar to $(LREF zip), but `zip` bundles its
4669        elements and returns a range.
4670        `lockstep` also supports reference access.
4671        Use `zip` if you want to pass the result to a range function.
4672 */
4673 struct Lockstep(Ranges...)
4674 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
4675 {
4676     ///
4677     this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
4678     {
4679         import std.exception : enforce;
4680 
4681         _ranges = ranges;
4682         enforce(sp != StoppingPolicy.longest,
4683                 "Can't use StoppingPolicy.Longest on Lockstep.");
4684         _stoppingPolicy = sp;
4685     }
4686 
4687     mixin(lockstepMixin!Ranges(false, false));
4688     mixin(lockstepMixin!Ranges(true, false));
4689     static if (allSatisfy!(isBidirectionalRange, Ranges))
4690     {
4691         mixin(lockstepMixin!Ranges(false, true));
4692         static if (allSatisfy!(hasLength, Ranges))
4693         {
4694             mixin(lockstepMixin!Ranges(true, true));
4695         }
4696         else
4697         {
4698             mixin(lockstepReverseFailMixin!Ranges(true));
4699         }
4700     }
4701     else
4702     {
4703         mixin(lockstepReverseFailMixin!Ranges(false));
4704         mixin(lockstepReverseFailMixin!Ranges(true));
4705     }
4706 
4707 private:
4708     alias R = Ranges;
4709     R _ranges;
4710     StoppingPolicy _stoppingPolicy;
4711 }
4712 
lockstepReverseFailMixin(Ranges...)4713 string lockstepReverseFailMixin(Ranges...)(bool withIndex)
4714 {
4715     import std.format : format;
4716     string[] params;
4717     string message;
4718 
4719     if (withIndex)
4720     {
4721         message = "Indexed reverse iteration with lockstep is only supported"
4722         ~"if all ranges are bidirectional and have a length.\n";
4723     }
4724     else
4725     {
4726         message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
4727     }
4728 
4729     if (withIndex)
4730     {
4731         params ~= "size_t";
4732     }
4733 
4734     foreach (idx, Range; Ranges)
4735     {
4736         params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
4737     }
4738 
4739     return format(
4740     q{
4741         int opApplyReverse()(scope int delegate(%s) dg)
4742         {
4743             static assert(false, "%s");
4744         }
4745     }, params.join(", "), message);
4746 }
4747 
4748 // For generic programming, make sure Lockstep!(Range) is well defined for a
4749 // single range.
Lockstep(Range)4750 template Lockstep(Range)
4751 {
4752     alias Lockstep = Range;
4753 }
4754 
4755 /// Ditto
4756 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
4757 if (allSatisfy!(isInputRange, Ranges))
4758 {
4759     return Lockstep!(Ranges)(ranges);
4760 }
4761 /// Ditto
4762 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
4763 if (allSatisfy!(isInputRange, Ranges))
4764 {
4765     static if (Ranges.length > 1)
4766         return Lockstep!Ranges(ranges, s);
4767     else
4768         return ranges[0];
4769 }
4770 
4771 ///
4772 @system unittest
4773 {
4774    auto arr1 = [1,2,3,4,5,100];
4775    auto arr2 = [6,7,8,9,10];
4776 
foreach(ref a,b;lockstep (arr1,arr2))4777    foreach (ref a, b; lockstep(arr1, arr2))
4778    {
4779        a += b;
4780    }
4781 
4782    assert(arr1 == [7,9,11,13,15,100]);
4783 
4784    /// Lockstep also supports iterating with an index variable:
foreach(index,a,b;lockstep (arr1,arr2))4785    foreach (index, a, b; lockstep(arr1, arr2))
4786    {
4787        assert(arr1[index] == a);
4788        assert(arr2[index] == b);
4789    }
4790 }
4791 
4792 @system unittest // Bugzilla 15860: foreach_reverse on lockstep
4793 {
4794     auto arr1 = [0, 1, 2, 3];
4795     auto arr2 = [4, 5, 6, 7];
4796 
4797     size_t n = arr1.length -1;
4798     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
4799     {
4800         assert(n == index);
4801         assert(index == a);
4802         assert(arr1[index] == a);
4803         assert(arr2[index] == b);
4804         n--;
4805     }
4806 
4807     auto arr3 = [4, 5];
4808     n = 1;
foreach_reverse(a,b;lockstep (arr1,arr3))4809     foreach_reverse (a, b; lockstep(arr1, arr3))
4810     {
4811         assert(a == arr1[$-n] && b == arr3[$-n]);
4812         n++;
4813     }
4814 }
4815 
4816 @system unittest
4817 {
4818     import std.algorithm.iteration : filter;
4819     import std.conv : to;
4820 
4821     // The filters are to make these the lowest common forward denominator ranges,
4822     // i.e. w/o ref return, random access, length, etc.
4823     auto foo = filter!"a"([1,2,3,4,5]);
4824     immutable bar = [6f,7f,8f,9f,10f].idup;
4825     auto l = lockstep(foo, bar);
4826 
4827     // Should work twice.  These are forward ranges with implicit save.
4828     foreach (i; 0 .. 2)
4829     {
4830         uint[] res1;
4831         float[] res2;
4832 
foreach(a,ref b;l)4833         foreach (a, ref b; l)
4834         {
4835             res1 ~= a;
4836             res2 ~= b;
4837         }
4838 
4839         assert(res1 == [1,2,3,4,5]);
4840         assert(res2 == [6,7,8,9,10]);
4841         assert(bar == [6f,7f,8f,9f,10f]);
4842     }
4843 
4844     // Doc example.
4845     auto arr1 = [1,2,3,4,5];
4846     auto arr2 = [6,7,8,9,10];
4847 
foreach(ref a,ref b;lockstep (arr1,arr2))4848     foreach (ref a, ref b; lockstep(arr1, arr2))
4849     {
4850         a += b;
4851     }
4852 
4853     assert(arr1 == [7,9,11,13,15]);
4854 
4855     // Make sure StoppingPolicy.requireSameLength doesn't throw.
4856     auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
4857 
4858     int k = 1;
foreach(a,b;ls)4859     foreach (a, b; ls)
4860     {
4861         assert(a - b == k);
4862         ++k;
4863     }
4864 
4865     // Make sure StoppingPolicy.requireSameLength throws.
4866     arr2.popBack();
4867     ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
4868 
4869     try {
foreach(a,b;ls)4870         foreach (a, b; ls) {}
4871         assert(0);
catch(Exception)4872     } catch (Exception) {}
4873 
4874     // Just make sure 1-range case instantiates.  This hangs the compiler
4875     // when no explicit stopping policy is specified due to Bug 4652.
4876     auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
foreach(int i,a;stuff)4877     foreach (int i, a; stuff)
4878     {
4879         assert(stuff[i] == a);
4880     }
4881 
4882     // Test with indexing.
4883     uint[] res1;
4884     float[] res2;
4885     size_t[] indices;
foreach(i,a,b;lockstep (foo,bar))4886     foreach (i, a, b; lockstep(foo, bar))
4887     {
4888         indices ~= i;
4889         res1 ~= a;
4890         res2 ~= b;
4891     }
4892 
4893     assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
4894     assert(res1 == [1,2,3,4,5]);
4895     assert(res2 == [6f,7f,8f,9f,10f]);
4896 
4897     // Make sure we've worked around the relevant compiler bugs and this at least
4898     // compiles w/ >2 ranges.
4899     lockstep(foo, foo, foo);
4900 
4901     // Make sure it works with const.
4902     const(int[])[] foo2 = [[1, 2, 3]];
4903     const(int[])[] bar2 = [[4, 5, 6]];
4904     auto c = chain(foo2, bar2);
4905 
foreach(f,b;lockstep (c,c))4906     foreach (f, b; lockstep(c, c)) {}
4907 
4908     // Regression 10468
4909     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
4910 }
4911 
4912 @system unittest
4913 {
4914     struct RvalueRange
4915     {
4916         int[] impl;
emptyRvalueRange4917         @property bool empty() { return impl.empty; }
frontRvalueRange4918         @property int front() { return impl[0]; } // N.B. non-ref
popFrontRvalueRange4919         void popFront() { impl.popFront(); }
4920     }
4921     auto data1 = [ 1, 2, 3, 4 ];
4922     auto data2 = [ 5, 6, 7, 8 ];
4923     auto r1 = RvalueRange(data1);
4924     auto r2 = data2;
foreach(a,ref b;lockstep (r1,r2))4925     foreach (a, ref b; lockstep(r1, r2))
4926     {
4927         a++;
4928         b++;
4929     }
4930     assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
4931     assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
4932 
4933     // Since r1 is by-value only, the compiler should reject attempts to
4934     // foreach over it with ref.
4935     static assert(!__traits(compiles, {
4936         foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
4937     }));
4938 }
4939 
4940 /**
4941 Creates a mathematical sequence given the initial values and a
4942 recurrence function that computes the next value from the existing
4943 values. The sequence comes in the form of an infinite forward
4944 range. The type $(D Recurrence) itself is seldom used directly; most
4945 often, recurrences are obtained by calling the function $(D
4946 recurrence).
4947 
4948 When calling $(D recurrence), the function that computes the next
4949 value is specified as a template argument, and the initial values in
4950 the recurrence are passed as regular arguments. For example, in a
4951 Fibonacci sequence, there are two initial values (and therefore a
4952 state size of 2) because computing the next Fibonacci value needs the
4953 past two values.
4954 
4955 The signature of this function should be:
4956 ----
4957 auto fun(R)(R state, size_t n)
4958 ----
4959 where $(D n) will be the index of the current value, and $(D state) will be an
4960 opaque state vector that can be indexed with array-indexing notation
4961 $(D state[i]), where valid values of $(D i) range from $(D (n - 1)) to
4962 $(D (n - State.length)).
4963 
4964 If the function is passed in string form, the state has name $(D "a")
4965 and the zero-based index in the recurrence has name $(D "n"). The
4966 given string must return the desired value for $(D a[n]) given $(D a[n
4967 - 1]), $(D a[n - 2]), $(D a[n - 3]),..., $(D a[n - stateSize]). The
4968 state size is dictated by the number of arguments passed to the call
4969 to $(D recurrence). The $(D Recurrence) struct itself takes care of
4970 managing the recurrence's state and shifting it appropriately.
4971  */
Recurrence(alias fun,StateType,size_t stateSize)4972 struct Recurrence(alias fun, StateType, size_t stateSize)
4973 {
4974     import std.functional : binaryFun;
4975 
4976     StateType[stateSize] _state;
4977     size_t _n;
4978 
4979     this(StateType[stateSize] initial) { _state = initial; }
4980 
4981     void popFront()
4982     {
4983         static auto trustedCycle(ref typeof(_state) s) @trusted
4984         {
4985             return cycle(s);
4986         }
4987         // The cast here is reasonable because fun may cause integer
4988         // promotion, but needs to return a StateType to make its operation
4989         // closed.  Therefore, we have no other choice.
4990         _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
4991             trustedCycle(_state), _n + stateSize);
4992         ++_n;
4993     }
4994 
4995     @property StateType front()
4996     {
4997         return _state[_n % stateSize];
4998     }
4999 
5000     @property typeof(this) save()
5001     {
5002         return this;
5003     }
5004 
5005     enum bool empty = false;
5006 }
5007 
5008 ///
5009 @safe unittest
5010 {
5011     import std.algorithm.comparison : equal;
5012 
5013     // The Fibonacci numbers, using function in string form:
5014     // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
5015     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5016     assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
5017 
5018     // The factorials, using function in lambda form:
5019     auto fac = recurrence!((a,n) => a[n-1] * n)(1);
5020     assert(take(fac, 10).equal([
5021         1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
5022     ]));
5023 
5024     // The triangular numbers, using function in explicit form:
genTriangular(R)5025     static size_t genTriangular(R)(R state, size_t n)
5026     {
5027         return state[n-1] + n;
5028     }
5029     auto tri = recurrence!genTriangular(0);
5030     assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
5031 }
5032 
5033 /// Ditto
5034 Recurrence!(fun, CommonType!(State), State.length)
5035 recurrence(alias fun, State...)(State initial)
5036 {
5037     CommonType!(State)[State.length] state;
foreach(i,Unused;State)5038     foreach (i, Unused; State)
5039     {
5040         state[i] = initial[i];
5041     }
5042     return typeof(return)(state);
5043 }
5044 
5045 @safe unittest
5046 {
5047     import std.algorithm.comparison : equal;
5048 
5049     auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5050     static assert(isForwardRange!(typeof(fib)));
5051 
5052     int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
5053     assert(equal(take(fib, 10), witness));
5054     foreach (e; take(fib, 10)) {}
5055     auto fact = recurrence!("n * a[n-1]")(1);
5056     assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
5057                             2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
5058     auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
5059     foreach (e; take(piapprox, 20)) {}
5060     // Thanks to yebblies for this test and the associated fix
5061     auto r = recurrence!"a[n-2]"(1, 2);
5062     witness = [1, 2, 1, 2, 1];
5063     assert(equal(take(r, 5), witness));
5064 }
5065 
5066 /**
5067    $(D Sequence) is similar to $(D Recurrence) except that iteration is
5068    presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
5069    closed form). This means that the $(D n)th element in the series is
5070    computable directly from the initial values and $(D n) itself. This
5071    implies that the interface offered by $(D Sequence) is a random-access
5072    range, as opposed to the regular $(D Recurrence), which only offers
5073    forward iteration.
5074 
5075    The state of the sequence is stored as a $(D Tuple) so it can be
5076    heterogeneous.
5077 */
Sequence(alias fun,State)5078 struct Sequence(alias fun, State)
5079 {
5080 private:
5081     import std.functional : binaryFun;
5082 
5083     alias compute = binaryFun!(fun, "a", "n");
5084     alias ElementType = typeof(compute(State.init, cast(size_t) 1));
5085     State _state;
5086     size_t _n;
5087 
5088     static struct DollarToken{}
5089 
5090 public:
5091     this(State initial, size_t n = 0)
5092     {
5093         _state = initial;
5094         _n = n;
5095     }
5096 
5097     @property ElementType front()
5098     {
5099         return compute(_state, _n);
5100     }
5101 
5102     void popFront()
5103     {
5104         ++_n;
5105     }
5106 
5107     enum opDollar = DollarToken();
5108 
5109     auto opSlice(size_t lower, size_t upper)
5110     in
5111     {
5112         assert(
5113             upper >= lower,
5114             "Attempting to slice a Sequence with a larger first argument than the second."
5115         );
5116     }
5117     body
5118     {
5119         return typeof(this)(_state, _n + lower).take(upper - lower);
5120     }
5121 
5122     auto opSlice(size_t lower, DollarToken)
5123     {
5124         return typeof(this)(_state, _n + lower);
5125     }
5126 
5127     ElementType opIndex(size_t n)
5128     {
5129         return compute(_state, n + _n);
5130     }
5131 
5132     enum bool empty = false;
5133 
5134     @property Sequence save() { return this; }
5135 }
5136 
5137 /// Ditto
sequence(alias fun,State...)5138 auto sequence(alias fun, State...)(State args)
5139 {
5140     import std.typecons : Tuple, tuple;
5141     alias Return = Sequence!(fun, Tuple!State);
5142     return Return(tuple(args));
5143 }
5144 
5145 /// Odd numbers, using function in string form:
5146 @safe unittest
5147 {
5148     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
5149     assert(odds.front == 1);
5150     odds.popFront();
5151     assert(odds.front == 3);
5152     odds.popFront();
5153     assert(odds.front == 5);
5154 }
5155 
5156 /// Triangular numbers, using function in lambda form:
5157 @safe unittest
5158 {
5159     auto tri = sequence!((a,n) => n*(n+1)/2)();
5160 
5161     // Note random access
5162     assert(tri[0] == 0);
5163     assert(tri[3] == 6);
5164     assert(tri[1] == 1);
5165     assert(tri[4] == 10);
5166     assert(tri[2] == 3);
5167 }
5168 
5169 /// Fibonacci numbers, using function in explicit form:
5170 @safe unittest
5171 {
5172     import std.math : pow, round, sqrt;
computeFib(S)5173     static ulong computeFib(S)(S state, size_t n)
5174     {
5175         // Binet's formula
5176         return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
5177                                  state[2]));
5178     }
5179     auto fib = sequence!computeFib(
5180         (1.0 + sqrt(5.0)) / 2.0,    // Golden Ratio
5181         (1.0 - sqrt(5.0)) / 2.0,    // Conjugate of Golden Ratio
5182         sqrt(5.0));
5183 
5184     // Note random access with [] operator
5185     assert(fib[1] == 1);
5186     assert(fib[4] == 5);
5187     assert(fib[3] == 3);
5188     assert(fib[2] == 2);
5189     assert(fib[9] == 55);
5190 }
5191 
5192 @safe unittest
5193 {
5194     import std.typecons : Tuple, tuple;
5195     auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
5196     static assert(isForwardRange!(typeof(y)));
5197 
5198     //@@BUG
5199     //auto y = sequence!("a[0] + n * a[1]")(0, 4);
5200     //foreach (e; take(y, 15))
5201     {}                                 //writeln(e);
5202 
5203     auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
5204         tuple(1, 2));
5205     for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
5206     {
5207         assert(odds.front == odds[0]);
5208         assert(odds[0] == currentOdd);
5209         odds.popFront();
5210     }
5211 }
5212 
5213 @safe unittest
5214 {
5215     import std.algorithm.comparison : equal;
5216 
5217     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
5218     static assert(hasSlicing!(typeof(odds)));
5219 
5220     //Note: don't use drop or take as the target of an equal,
5221     //since they'll both just forward to opSlice, making the tests irrelevant
5222 
5223     // static slicing tests
5224     assert(equal(odds[0 .. 5], [1,  3,  5,  7,  9]));
5225     assert(equal(odds[3 .. 7], [7,  9, 11, 13]));
5226 
5227     // relative slicing test, testing slicing is NOT agnostic of state
5228     auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
5229     assert(equal(odds_less5[0 ..  3], [11, 13, 15]));
5230     assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
5231 
5232     //Infinite slicing tests
5233     odds = odds[10 .. $];
5234     assert(equal(odds.take(3), [21, 23, 25]));
5235 }
5236 
5237 // Issue 5036
5238 @safe unittest
5239 {
5240     auto s = sequence!((a, n) => new int)(0);
5241     assert(s.front != s.front);  // no caching
5242 }
5243 
5244 // iota
5245 /**
5246    Creates a range of values that span the given starting and stopping
5247    values.
5248 
5249    Params:
5250    begin = The starting value.
5251    end = The value that serves as the stopping criterion. This value is not
5252         included in the range.
5253    step = The value to add to the current value at each iteration.
5254 
5255    Returns:
5256    A range that goes through the numbers $(D begin), $(D begin + step),
5257    $(D begin + 2 * step), $(D ...), up to and excluding $(D end).
5258 
5259    The two-argument overloads have $(D step = 1). If $(D begin < end && step <
5260    0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
5261    is returned. If $(D step == 0) then $(D begin == end) is an error.
5262 
5263    For built-in types, the range returned is a random access range. For
5264    user-defined types that support $(D ++), the range is an input
5265    range.
5266 
5267    An integral iota also supports $(D in) operator from the right. It takes
5268    the stepping into account, the integral won't be considered
5269    contained if it falls between two consecutive values of the range.
5270    $(D contains) does the same as in, but from lefthand side.
5271 
5272     Example:
5273     ---
5274     void main()
5275     {
5276         import std.stdio;
5277 
5278         // The following groups all produce the same output of:
5279         // 0 1 2 3 4
5280 
5281         foreach (i; 0 .. 5)
5282             writef("%s ", i);
5283         writeln();
5284 
5285         import std.range : iota;
5286         foreach (i; iota(0, 5))
5287             writef("%s ", i);
5288         writeln();
5289 
5290         writefln("%(%s %|%)", iota(0, 5));
5291 
5292         import std.algorithm.iteration : map;
5293         import std.algorithm.mutation : copy;
5294         import std.format;
5295         iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
5296         writeln();
5297     }
5298     ---
5299 */
5300 auto iota(B, E, S)(B begin, E end, S step)
5301 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
5302         && isIntegral!S)
5303 {
5304     import std.conv : unsigned;
5305 
5306     alias Value = CommonType!(Unqual!B, Unqual!E);
5307     alias StepType = Unqual!S;
5308 
5309     assert(step != 0 || begin == end);
5310 
5311     static struct Result
5312     {
5313         private Value current, last;
5314         private StepType step; // by convention, 0 if range is empty
5315 
thisResult5316         this(Value current, Value pastLast, StepType step)
5317         {
5318             if (current < pastLast && step > 0)
5319             {
5320                 // Iterating upward
5321                 assert(unsigned((pastLast - current) / step) <= size_t.max);
5322                 // Cast below can't fail because current < pastLast
5323                 this.last = cast(Value) (pastLast - 1);
5324                 this.last -= unsigned(this.last - current) % step;
5325             }
5326             else if (current > pastLast && step < 0)
5327             {
5328                 // Iterating downward
5329                 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
5330                 // Cast below can't fail because current > pastLast
5331                 this.last = cast(Value) (pastLast + 1);
5332                 this.last += unsigned(current - this.last) % (0 - step);
5333             }
5334             else
5335             {
5336                 // Initialize an empty range
5337                 this.step = 0;
5338                 return;
5339             }
5340             this.step = step;
5341             this.current = current;
5342         }
5343 
emptyResult5344         @property bool empty() const { return step == 0; }
inoutResult5345         @property inout(Value) front() inout { assert(!empty); return current; }
popFrontResult5346         void popFront()
5347         {
5348             assert(!empty);
5349             if (current == last) step = 0;
5350             else current += step;
5351         }
5352 
inoutResult5353         @property inout(Value) back() inout
5354         {
5355             assert(!empty);
5356             return last;
5357         }
popBackResult5358         void popBack()
5359         {
5360             assert(!empty);
5361             if (current == last) step = 0;
5362             else last -= step;
5363         }
5364 
saveResult5365         @property auto save() { return this; }
5366 
opIndexResult5367         inout(Value) opIndex(ulong n) inout
5368         {
5369             assert(n < this.length);
5370 
5371             // Just cast to Value here because doing so gives overflow behavior
5372             // consistent with calling popFront() n times.
5373             return cast(inout Value) (current + step * n);
5374         }
5375         auto opBinaryRight(string op)(Value val) const
5376         if (op == "in")
5377         {
5378             if (empty) return false;
5379             //cast to avoid becoming unsigned
5380             auto supposedIndex = cast(StepType)(val - current) / step;
5381             return supposedIndex < length && supposedIndex * step + current == val;
5382         }
containsResult5383         auto contains(Value x){return x in this;}
opSliceResult5384         inout(Result) opSlice() inout { return this; }
opSliceResult5385         inout(Result) opSlice(ulong lower, ulong upper) inout
5386         {
5387             assert(upper >= lower && upper <= this.length);
5388 
5389             return cast(inout Result) Result(
5390                 cast(Value)(current + lower * step),
5391                 cast(Value)(current + upper * step),
5392                 step);
5393         }
lengthResult5394         @property size_t length() const
5395         {
5396             if (step > 0)
5397                 return 1 + cast(size_t) (unsigned(last - current) / step);
5398             if (step < 0)
5399                 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
5400             return 0;
5401         }
5402 
5403         alias opDollar = length;
5404     }
5405 
5406     return Result(begin, end, step);
5407 }
5408 
5409 /// Ditto
5410 auto iota(B, E)(B begin, E end)
5411 if (isFloatingPoint!(CommonType!(B, E)))
5412 {
5413     return iota(begin, end, CommonType!(B, E)(1));
5414 }
5415 
5416 /// Ditto
5417 auto iota(B, E)(B begin, E end)
5418 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
5419 {
5420     import std.conv : unsigned;
5421 
5422     alias Value = CommonType!(Unqual!B, Unqual!E);
5423 
5424     static struct Result
5425     {
5426         private Value current, pastLast;
5427 
thisResult5428         this(Value current, Value pastLast)
5429         {
5430             if (current < pastLast)
5431             {
5432                 assert(unsigned(pastLast - current) <= size_t.max);
5433 
5434                 this.current = current;
5435                 this.pastLast = pastLast;
5436             }
5437             else
5438             {
5439                 // Initialize an empty range
5440                 this.current = this.pastLast = current;
5441             }
5442         }
5443 
emptyResult5444         @property bool empty() const { return current == pastLast; }
inoutResult5445         @property inout(Value) front() inout { assert(!empty); return current; }
popFrontResult5446         void popFront() { assert(!empty); ++current; }
5447 
inoutResult5448         @property inout(Value) back() inout { assert(!empty); return cast(inout(Value))(pastLast - 1); }
popBackResult5449         void popBack() { assert(!empty); --pastLast; }
5450 
saveResult5451         @property auto save() { return this; }
5452 
opIndexResult5453         inout(Value) opIndex(size_t n) inout
5454         {
5455             assert(n < this.length);
5456 
5457             // Just cast to Value here because doing so gives overflow behavior
5458             // consistent with calling popFront() n times.
5459             return cast(inout Value) (current + n);
5460         }
5461         auto opBinaryRight(string op)(Value val) const
5462         if (op == "in")
5463         {
5464             return current <= val && val < pastLast;
5465         }
containsResult5466         auto contains(Value x){return x in this;}
opSliceResult5467         inout(Result) opSlice() inout { return this; }
opSliceResult5468         inout(Result) opSlice(ulong lower, ulong upper) inout
5469         {
5470             assert(upper >= lower && upper <= this.length);
5471 
5472             return cast(inout Result) Result(cast(Value)(current + lower),
5473                                             cast(Value)(pastLast - (length - upper)));
5474         }
lengthResult5475         @property size_t length() const
5476         {
5477             return cast(size_t)(pastLast - current);
5478         }
5479 
5480         alias opDollar = length;
5481     }
5482 
5483     return Result(begin, end);
5484 }
5485 
5486 /// Ditto
5487 auto iota(E)(E end)
5488 if (is(typeof(iota(E(0), end))))
5489 {
5490     E begin = E(0);
5491     return iota(begin, end);
5492 }
5493 
5494 /// Ditto
5495 // Specialization for floating-point types
5496 auto iota(B, E, S)(B begin, E end, S step)
5497 if (isFloatingPoint!(CommonType!(B, E, S)))
5498 in
5499 {
5500     assert(step != 0, "iota: step must not be 0");
5501     assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
5502 }
5503 body
5504 {
5505     alias Value = Unqual!(CommonType!(B, E, S));
5506     static struct Result
5507     {
5508         private Value start, step;
5509         private size_t index, count;
5510 
thisResult5511         this(Value start, Value end, Value step)
5512         {
5513             import std.conv : to;
5514 
5515             this.start = start;
5516             this.step = step;
5517             immutable fcount = (end - start) / step;
5518             count = to!size_t(fcount);
5519             auto pastEnd = start + count * step;
5520             if (step > 0)
5521             {
5522                 if (pastEnd < end) ++count;
5523                 assert(start + count * step >= end);
5524             }
5525             else
5526             {
5527                 if (pastEnd > end) ++count;
5528                 assert(start + count * step <= end);
5529             }
5530         }
5531 
emptyResult5532         @property bool empty() const { return index == count; }
frontResult5533         @property Value front() const { assert(!empty); return start + step * index; }
popFrontResult5534         void popFront()
5535         {
5536             assert(!empty);
5537             ++index;
5538         }
backResult5539         @property Value back() const
5540         {
5541             assert(!empty);
5542             return start + step * (count - 1);
5543         }
popBackResult5544         void popBack()
5545         {
5546             assert(!empty);
5547             --count;
5548         }
5549 
saveResult5550         @property auto save() { return this; }
5551 
opIndexResult5552         Value opIndex(size_t n) const
5553         {
5554             assert(n < count);
5555             return start + step * (n + index);
5556         }
opSliceResult5557         inout(Result) opSlice() inout
5558         {
5559             return this;
5560         }
opSliceResult5561         inout(Result) opSlice(size_t lower, size_t upper) inout
5562         {
5563             assert(upper >= lower && upper <= count);
5564 
5565             Result ret = this;
5566             ret.index += lower;
5567             ret.count = upper - lower + ret.index;
5568             return cast(inout Result) ret;
5569         }
lengthResult5570         @property size_t length() const
5571         {
5572             return count - index;
5573         }
5574 
5575         alias opDollar = length;
5576     }
5577 
5578     return Result(begin, end, step);
5579 }
5580 
5581 ///
5582 @safe unittest
5583 {
5584     import std.algorithm.comparison : equal;
5585     import std.math : approxEqual;
5586 
5587     auto r = iota(0, 10, 1);
5588     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
5589     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
5590     assert(3 in r);
5591     assert(r.contains(3)); //Same as above
5592     assert(!(10 in r));
5593     assert(!(-8 in r));
5594     r = iota(0, 11, 3);
5595     assert(equal(r, [0, 3, 6, 9]));
5596     assert(r[2] == 6);
5597     assert(!(2 in r));
5598     auto rf = iota(0.0, 0.5, 0.1);
5599     assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
5600 }
5601 
5602 nothrow @nogc @safe unittest
5603 {
5604    //float overloads use std.conv.to so can't be @nogc or nothrow
5605     alias ssize_t = Signed!size_t;
5606     assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
5607     assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
5608     assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
5609     assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
5610     assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
5611 }
5612 
5613 debug @system unittest
5614 {//check the contracts
5615     import core.exception : AssertError;
5616     import std.exception : assertThrown;
5617     assertThrown!AssertError(iota(1,2,0));
5618     assertThrown!AssertError(iota(0f,1f,0f));
5619     assertThrown!AssertError(iota(1f,0f,0.1f));
5620     assertThrown!AssertError(iota(0f,1f,-0.1f));
5621 }
5622 
5623 @system unittest
5624 {
5625     int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
5626     auto r1 = iota(a.ptr, a.ptr + a.length, 1);
5627     assert(r1.front == a.ptr);
5628     assert(r1.back == a.ptr + a.length - 1);
5629     assert(&a[4] in r1);
5630 }
5631 
5632 @safe unittest
5633 {
5634     assert(iota(1UL, 0UL).length == 0);
5635     assert(iota(1UL, 0UL, 1).length == 0);
5636     assert(iota(0, 1, 1).length == 1);
5637     assert(iota(1, 0, -1).length == 1);
5638     assert(iota(0, 1, -1).length == 0);
5639     assert(iota(ulong.max, 0).length == 0);
5640 }
5641 
5642 @safe unittest
5643 {
5644     import std.algorithm.comparison : equal;
5645     import std.algorithm.searching : count;
5646     import std.math : approxEqual, nextUp, nextDown;
5647     import std.meta : AliasSeq;
5648 
5649     static assert(is(ElementType!(typeof(iota(0f))) == float));
5650 
5651     static assert(hasLength!(typeof(iota(0, 2))));
5652     auto r = iota(0, 10, 1);
5653     assert(r[$ - 1] == 9);
5654     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
5655 
5656     auto rSlice = r[2 .. 8];
5657     assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
5658 
5659     rSlice.popFront();
5660     assert(rSlice[0] == rSlice.front);
5661     assert(rSlice.front == 3);
5662 
5663     rSlice.popBack();
5664     assert(rSlice[rSlice.length - 1] == rSlice.back);
5665     assert(rSlice.back == 6);
5666 
5667     rSlice = r[0 .. 4];
5668     assert(equal(rSlice, [0, 1, 2, 3]));
5669     assert(3 in rSlice);
5670     assert(!(4 in rSlice));
5671 
5672     auto rr = iota(10);
5673     assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
5674 
5675     r = iota(0, -10, -1);
5676     assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
5677     rSlice = r[3 .. 9];
5678     assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
5679 
5680     r = iota(0, -6, -3);
5681     assert(equal(r, [0, -3][]));
5682     rSlice = r[1 .. 2];
5683     assert(equal(rSlice, [-3]));
5684 
5685     r = iota(0, -7, -3);
5686     assert(equal(r, [0, -3, -6][]));
5687     assert(0 in r);
5688     assert(-6 in r);
5689     rSlice = r[1 .. 3];
5690     assert(equal(rSlice, [-3, -6]));
5691     assert(!(0 in rSlice));
5692     assert(!(-2 in rSlice));
5693     assert(!(-5 in rSlice));
5694     assert(!(3 in rSlice));
5695     assert(!(-9 in rSlice));
5696 
5697     r = iota(0, 11, 3);
5698     assert(equal(r, [0, 3, 6, 9][]));
5699     assert(r[2] == 6);
5700     rSlice = r[1 .. 3];
5701     assert(equal(rSlice, [3, 6]));
5702 
5703     auto rf = iota(0.0, 0.5, 0.1);
5704     assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
5705     assert(rf.length == 5);
5706 
5707     rf.popFront();
5708     assert(rf.length == 4);
5709 
5710     auto rfSlice = rf[1 .. 4];
5711     assert(rfSlice.length == 3);
5712     assert(approxEqual(rfSlice, [0.2, 0.3, 0.4]));
5713 
5714     rfSlice.popFront();
5715     assert(approxEqual(rfSlice[0], 0.3));
5716 
5717     rf.popFront();
5718     assert(rf.length == 3);
5719 
5720     rfSlice = rf[1 .. 3];
5721     assert(rfSlice.length == 2);
5722     assert(approxEqual(rfSlice, [0.3, 0.4]));
5723     assert(approxEqual(rfSlice[0], 0.3));
5724 
5725     // With something just above 0.5
5726     rf = iota(0.0, nextUp(0.5), 0.1);
5727     assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
5728     rf.popBack();
5729     assert(rf[rf.length - 1] == rf.back);
5730     assert(approxEqual(rf.back, 0.4));
5731     assert(rf.length == 5);
5732 
5733     // going down
5734     rf = iota(0.0, -0.5, -0.1);
5735     assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
5736     rfSlice = rf[2 .. 5];
5737     assert(approxEqual(rfSlice, [-0.2, -0.3, -0.4]));
5738 
5739     rf = iota(0.0, nextDown(-0.5), -0.1);
5740     assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
5741 
5742     // iota of longs
5743     auto rl = iota(5_000_000L);
5744     assert(rl.length == 5_000_000L);
5745     assert(0 in rl);
5746     assert(4_000_000L in rl);
5747     assert(!(-4_000_000L in rl));
5748     assert(!(5_000_000L in rl));
5749 
5750     // iota of longs with steps
5751     auto iota_of_longs_with_steps = iota(50L, 101L, 10);
5752     assert(iota_of_longs_with_steps.length == 6);
5753     assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
5754 
5755     // iota of unsigned zero length (issue 6222, actually trying to consume it
5756     // is the only way to find something is wrong because the public
5757     // properties are all correct)
5758     auto iota_zero_unsigned = iota(0, 0u, 3);
5759     assert(count(iota_zero_unsigned) == 0);
5760 
5761     // unsigned reverse iota can be buggy if .length doesn't take them into
5762     // account (issue 7982).
5763     assert(iota(10u, 0u, -1).length == 10);
5764     assert(iota(10u, 0u, -2).length == 5);
5765     assert(iota(uint.max, uint.max-10, -1).length == 10);
5766     assert(iota(uint.max, uint.max-10, -2).length == 5);
5767     assert(iota(uint.max, 0u, -1).length == uint.max);
5768 
5769     assert(20 in iota(20u, 10u, -2));
5770     assert(16 in iota(20u, 10u, -2));
5771     assert(!(15 in iota(20u, 10u, -2)));
5772     assert(!(10 in iota(20u, 10u, -2)));
5773     assert(!(uint.max in iota(20u, 10u, -1)));
5774     assert(!(int.min in iota(20u, 10u, -1)));
5775     assert(!(int.max in iota(20u, 10u, -1)));
5776 
5777 
5778     // Issue 8920
5779     foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
5780         int, uint, long, ulong))
5781     {
5782         Type val;
5783         foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
5784         assert(val == 10);
5785     }
5786 }
5787 
5788 @safe unittest
5789 {
5790     import std.algorithm.mutation : copy;
5791     auto idx = new size_t[100];
5792     copy(iota(0, idx.length), idx);
5793 }
5794 
5795 @safe unittest
5796 {
5797     import std.meta : AliasSeq;
5798     foreach (range; AliasSeq!(iota(2, 27, 4),
5799                              iota(3, 9),
5800                              iota(2.7, 12.3, .1),
5801                              iota(3.2, 9.7)))
5802     {
5803         const cRange = range;
5804         const e = cRange.empty;
5805         const f = cRange.front;
5806         const b = cRange.back;
5807         const i = cRange[2];
5808         const s1 = cRange[];
5809         const s2 = cRange[0 .. 3];
5810         const l = cRange.length;
5811     }
5812 }
5813 
5814 @system unittest
5815 {
5816     //The ptr stuff can't be done at compile time, so we unfortunately end
5817     //up with some code duplication here.
5818     auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
5819 
5820     {
5821         const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
5822         const e = cRange.empty;
5823         const f = cRange.front;
5824         const b = cRange.back;
5825         const i = cRange[2];
5826         const s1 = cRange[];
5827         const s2 = cRange[0 .. 3];
5828         const l = cRange.length;
5829     }
5830 
5831     {
5832         const cRange = iota(arr.ptr, arr.ptr + arr.length);
5833         const e = cRange.empty;
5834         const f = cRange.front;
5835         const b = cRange.back;
5836         const i = cRange[2];
5837         const s1 = cRange[];
5838         const s2 = cRange[0 .. 3];
5839         const l = cRange.length;
5840     }
5841 }
5842 
5843 @nogc nothrow pure @safe
5844 unittest
5845 {
5846     {
5847         ushort start = 0, end = 10, step = 2;
5848         foreach (i; iota(start, end, step))
5849             static assert(is(typeof(i) == ushort));
5850     }
5851     {
5852         ubyte start = 0, end = 255, step = 128;
5853         uint x;
foreach(i;iota (start,end,step))5854         foreach (i; iota(start, end, step))
5855         {
5856             static assert(is(typeof(i) == ubyte));
5857             ++x;
5858         }
5859         assert(x == 2);
5860     }
5861 }
5862 
5863 /* Generic overload that handles arbitrary types that support arithmetic
5864  * operations.
5865  *
5866  * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
5867  * as they can be incremented with $(D ++) and compared with $(D <) or $(D ==).
5868  */
5869 /// ditto
5870 auto iota(B, E)(B begin, E end)
5871 if (!isIntegral!(CommonType!(B, E)) &&
5872     !isFloatingPoint!(CommonType!(B, E)) &&
5873     !isPointer!(CommonType!(B, E)) &&
5874     is(typeof((ref B b) { ++b; })) &&
5875     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
5876 {
5877     static struct Result
5878     {
5879         B current;
5880         E end;
5881 
emptyResult5882         @property bool empty()
5883         {
5884             static if (is(typeof(B.init < E.init)))
5885                 return !(current < end);
5886             else static if (is(typeof(B.init != E.init)))
5887                 return current == end;
5888             else
5889                 static assert(0);
5890         }
frontResult5891         @property auto front() { return current; }
popFrontResult5892         void popFront()
5893         {
5894             assert(!empty);
5895             ++current;
5896         }
5897     }
5898     return Result(begin, end);
5899 }
5900 
5901 @safe unittest
5902 {
5903     import std.algorithm.comparison : equal;
5904 
5905     // Test iota() for a type that only supports ++ and != but does not have
5906     // '<'-ordering.
Cyclic(int wrapAround)5907     struct Cyclic(int wrapAround)
5908     {
5909         int current;
5910 
5911         this(int start) { current = start % wrapAround; }
5912 
5913         bool opEquals(Cyclic c) const { return current == c.current; }
5914         bool opEquals(int i) const { return current == i; }
5915         void opUnary(string op)() if (op == "++")
5916         {
5917             current = (current + 1) % wrapAround;
5918         }
5919     }
5920     alias Cycle5 = Cyclic!5;
5921 
5922     // Easy case
5923     auto i1 = iota(Cycle5(1), Cycle5(4));
5924     assert(i1.equal([1, 2, 3]));
5925 
5926     // Wraparound case
5927     auto i2 = iota(Cycle5(3), Cycle5(2));
5928     assert(i2.equal([3, 4, 0, 1 ]));
5929 }
5930 
5931 /**
5932    Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
5933    (below).
5934 */
5935 enum TransverseOptions
5936 {
5937 /**
5938    When transversed, the elements of a range of ranges are assumed to
5939    have different lengths (e.g. a jagged array).
5940 */
5941     assumeJagged,                      //default
5942     /**
5943        The transversal enforces that the elements of a range of ranges have
5944        all the same length (e.g. an array of arrays, all having the same
5945        length). Checking is done once upon construction of the transversal
5946        range.
5947     */
5948         enforceNotJagged,
5949     /**
5950        The transversal assumes, without verifying, that the elements of a
5951        range of ranges have all the same length. This option is useful if
5952        checking was already done from the outside of the range.
5953     */
5954         assumeNotJagged,
5955         }
5956 
5957 /**
5958    Given a range of ranges, iterate transversally through the first
5959    elements of each of the enclosed ranges.
5960 */
5961 struct FrontTransversal(Ror,
5962         TransverseOptions opt = TransverseOptions.assumeJagged)
5963 {
5964     alias RangeOfRanges = Unqual!(Ror);
5965     alias RangeType     = .ElementType!RangeOfRanges;
5966     alias ElementType   = .ElementType!RangeType;
5967 
prime()5968     private void prime()
5969     {
5970         static if (opt == TransverseOptions.assumeJagged)
5971         {
5972             while (!_input.empty && _input.front.empty)
5973             {
5974                 _input.popFront();
5975             }
5976             static if (isBidirectionalRange!RangeOfRanges)
5977             {
5978                 while (!_input.empty && _input.back.empty)
5979                 {
5980                     _input.popBack();
5981                 }
5982             }
5983         }
5984     }
5985 
5986 /**
5987    Construction from an input.
5988 */
this(RangeOfRanges input)5989     this(RangeOfRanges input)
5990     {
5991         _input = input;
5992         prime();
5993         static if (opt == TransverseOptions.enforceNotJagged)
5994             // (isRandomAccessRange!RangeOfRanges
5995             //     && hasLength!RangeType)
5996         {
5997             import std.exception : enforce;
5998 
5999             if (empty) return;
6000             immutable commonLength = _input.front.length;
6001             foreach (e; _input)
6002             {
6003                 enforce(e.length == commonLength);
6004             }
6005         }
6006     }
6007 
6008 /**
6009    Forward range primitives.
6010 */
6011     static if (isInfinite!RangeOfRanges)
6012     {
6013         enum bool empty = false;
6014     }
6015     else
6016     {
empty()6017         @property bool empty()
6018         {
6019             static if (opt != TransverseOptions.assumeJagged)
6020             {
6021                 if (!_input.empty)
6022                     return _input.front.empty;
6023             }
6024 
6025             return _input.empty;
6026         }
6027     }
6028 
6029     /// Ditto
front()6030     @property auto ref front()
6031     {
6032         assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
6033         return _input.front.front;
6034     }
6035 
6036     /// Ditto
6037     static if (hasMobileElements!RangeType)
6038     {
moveFront()6039         ElementType moveFront()
6040         {
6041             return _input.front.moveFront();
6042         }
6043     }
6044 
6045     static if (hasAssignableElements!RangeType)
6046     {
front(ElementType val)6047         @property void front(ElementType val)
6048         {
6049             _input.front.front = val;
6050         }
6051     }
6052 
6053     /// Ditto
popFront()6054     void popFront()
6055     {
6056         assert(!empty, "Attempting to popFront an empty FrontTransversal");
6057         _input.popFront();
6058         prime();
6059     }
6060 
6061 /**
6062    Duplicates this $(D frontTransversal). Note that only the encapsulating
6063    range of range will be duplicated. Underlying ranges will not be
6064    duplicated.
6065 */
6066     static if (isForwardRange!RangeOfRanges)
6067     {
save()6068         @property FrontTransversal save()
6069         {
6070             return FrontTransversal(_input.save);
6071         }
6072     }
6073 
6074     static if (isBidirectionalRange!RangeOfRanges)
6075     {
6076 /**
6077    Bidirectional primitives. They are offered if $(D
6078    isBidirectionalRange!RangeOfRanges).
6079 */
back()6080         @property auto ref back()
6081         {
6082             assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
6083             return _input.back.front;
6084         }
6085         /// Ditto
popBack()6086         void popBack()
6087         {
6088             assert(!empty, "Attempting to popBack an empty FrontTransversal");
6089             _input.popBack();
6090             prime();
6091         }
6092 
6093         /// Ditto
6094         static if (hasMobileElements!RangeType)
6095         {
moveBack()6096             ElementType moveBack()
6097             {
6098                 return _input.back.moveFront();
6099             }
6100         }
6101 
6102         static if (hasAssignableElements!RangeType)
6103         {
back(ElementType val)6104             @property void back(ElementType val)
6105             {
6106                 _input.back.front = val;
6107             }
6108         }
6109     }
6110 
6111     static if (isRandomAccessRange!RangeOfRanges &&
6112             (opt == TransverseOptions.assumeNotJagged ||
6113                     opt == TransverseOptions.enforceNotJagged))
6114     {
6115 /**
6116    Random-access primitive. It is offered if $(D
6117    isRandomAccessRange!RangeOfRanges && (opt ==
6118    TransverseOptions.assumeNotJagged || opt ==
6119    TransverseOptions.enforceNotJagged)).
6120 */
opIndex(size_t n)6121         auto ref opIndex(size_t n)
6122         {
6123             return _input[n].front;
6124         }
6125 
6126         /// Ditto
6127         static if (hasMobileElements!RangeType)
6128         {
moveAt(size_t n)6129             ElementType moveAt(size_t n)
6130             {
6131                 return _input[n].moveFront();
6132             }
6133         }
6134         /// Ditto
6135         static if (hasAssignableElements!RangeType)
6136         {
opIndexAssign(ElementType val,size_t n)6137             void opIndexAssign(ElementType val, size_t n)
6138             {
6139                 _input[n].front = val;
6140             }
6141         }
6142         /// Ditto
6143         static if (hasLength!RangeOfRanges)
6144         {
length()6145             @property size_t length()
6146             {
6147                 return _input.length;
6148             }
6149 
6150             alias opDollar = length;
6151         }
6152 
6153 /**
6154    Slicing if offered if $(D RangeOfRanges) supports slicing and all the
6155    conditions for supporting indexing are met.
6156 */
6157         static if (hasSlicing!RangeOfRanges)
6158         {
opSlice(size_t lower,size_t upper)6159             typeof(this) opSlice(size_t lower, size_t upper)
6160             {
6161                 return typeof(this)(_input[lower .. upper]);
6162             }
6163         }
6164     }
6165 
opSlice()6166     auto opSlice() { return this; }
6167 
6168 private:
6169     RangeOfRanges _input;
6170 }
6171 
6172 /// Ditto
6173 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
6174     TransverseOptions opt = TransverseOptions.assumeJagged,
6175     RangeOfRanges)
6176 (RangeOfRanges rr)
6177 {
6178     return typeof(return)(rr);
6179 }
6180 
6181 ///
6182 @safe unittest
6183 {
6184     import std.algorithm.comparison : equal;
6185     int[][] x = new int[][2];
6186     x[0] = [1, 2];
6187     x[1] = [3, 4];
6188     auto ror = frontTransversal(x);
6189     assert(equal(ror, [ 1, 3 ][]));
6190 }
6191 
6192 @safe unittest
6193 {
6194     import std.algorithm.comparison : equal;
6195     import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
6196 
6197     static assert(is(FrontTransversal!(immutable int[][])));
6198 
foreach(DummyType;AllDummyRanges)6199     foreach (DummyType; AllDummyRanges)
6200     {
6201         auto dummies =
6202             [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
6203 
6204         foreach (i, ref elem; dummies)
6205         {
6206             // Just violate the DummyRange abstraction to get what I want.
6207             elem.arr = elem.arr[i..$ - (3 - i)];
6208         }
6209 
6210         auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
6211         static if (isForwardRange!DummyType)
6212         {
6213             static assert(isForwardRange!(typeof(ft)));
6214         }
6215 
6216         assert(equal(ft, [1, 2, 3, 4]));
6217 
6218         // Test slicing.
6219         assert(equal(ft[0 .. 2], [1, 2]));
6220         assert(equal(ft[1 .. 3], [2, 3]));
6221 
6222         assert(ft.front == ft.moveFront());
6223         assert(ft.back == ft.moveBack());
6224         assert(ft.moveAt(1) == ft[1]);
6225 
6226 
6227         // Test infiniteness propagation.
6228         static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
6229 
6230         static if (DummyType.r == ReturnBy.Reference)
6231         {
6232             {
6233                 ft.front++;
6234                 scope(exit) ft.front--;
6235                 assert(dummies.front.front == 2);
6236             }
6237 
6238             {
6239                 ft.front = 5;
6240                 scope(exit) ft.front = 1;
6241                 assert(dummies[0].front == 5);
6242             }
6243 
6244             {
6245                 ft.back = 88;
6246                 scope(exit) ft.back = 4;
6247                 assert(dummies.back.front == 88);
6248             }
6249 
6250             {
6251                 ft[1] = 99;
6252                 scope(exit) ft[1] = 2;
6253                 assert(dummies[1].front == 99);
6254             }
6255         }
6256     }
6257 }
6258 
6259 // Issue 16363
6260 @safe unittest
6261 {
6262     import std.algorithm.comparison : equal;
6263 
6264     int[][] darr = [[0, 1], [4, 5]];
6265     auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
6266 
6267     assert(equal(ft, [0, 4]));
6268     static assert(isRandomAccessRange!(typeof(ft)));
6269 }
6270 
6271 // Bugzilla 16442
6272 @safe unittest
6273 {
6274     int[][] arr = [[], []];
6275 
6276     auto ft1 = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
6277     assert(ft1.empty);
6278 
6279     auto ft2 = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
6280     assert(ft2.empty);
6281 }
6282 
6283 /**
6284     Given a range of ranges, iterate transversally through the
6285     `n`th element of each of the enclosed ranges.
6286 
6287     Params:
6288         opt = Controls the assumptions the function makes about the lengths
6289         of the ranges
6290         rr = An input range of random access ranges
6291     Returns:
6292         At minimum, an input range. Range primitives such as bidirectionality
6293         and random access are given if the element type of `rr` provides them.
6294 */
6295 struct Transversal(Ror,
6296         TransverseOptions opt = TransverseOptions.assumeJagged)
6297 {
6298     private alias RangeOfRanges = Unqual!Ror;
6299     private alias InnerRange = ElementType!RangeOfRanges;
6300     private alias E = ElementType!InnerRange;
6301 
primeTransversal6302     private void prime()
6303     {
6304         static if (opt == TransverseOptions.assumeJagged)
6305         {
6306             while (!_input.empty && _input.front.length <= _n)
6307             {
6308                 _input.popFront();
6309             }
6310             static if (isBidirectionalRange!RangeOfRanges)
6311             {
6312                 while (!_input.empty && _input.back.length <= _n)
6313                 {
6314                     _input.popBack();
6315                 }
6316             }
6317         }
6318     }
6319 
6320 /**
6321    Construction from an input and an index.
6322 */
thisTransversal6323     this(RangeOfRanges input, size_t n)
6324     {
6325         _input = input;
6326         _n = n;
6327         prime();
6328         static if (opt == TransverseOptions.enforceNotJagged)
6329         {
6330             import std.exception : enforce;
6331 
6332             if (empty) return;
6333             immutable commonLength = _input.front.length;
6334             foreach (e; _input)
6335             {
6336                 enforce(e.length == commonLength);
6337             }
6338         }
6339     }
6340 
6341 /**
6342    Forward range primitives.
6343 */
6344     static if (isInfinite!(RangeOfRanges))
6345     {
6346         enum bool empty = false;
6347     }
6348     else
6349     {
emptyTransversal6350         @property bool empty()
6351         {
6352             return _input.empty;
6353         }
6354     }
6355 
6356     /// Ditto
frontTransversal6357     @property auto ref front()
6358     {
6359         assert(!empty, "Attempting to fetch the front of an empty Transversal");
6360         return _input.front[_n];
6361     }
6362 
6363     /// Ditto
6364     static if (hasMobileElements!InnerRange)
6365     {
moveFrontTransversal6366         E moveFront()
6367         {
6368             return _input.front.moveAt(_n);
6369         }
6370     }
6371 
6372     /// Ditto
6373     static if (hasAssignableElements!InnerRange)
6374     {
frontTransversal6375         @property void front(E val)
6376         {
6377             _input.front[_n] = val;
6378         }
6379     }
6380 
6381 
6382     /// Ditto
popFrontTransversal6383     void popFront()
6384     {
6385         assert(!empty, "Attempting to popFront an empty Transversal");
6386         _input.popFront();
6387         prime();
6388     }
6389 
6390     /// Ditto
6391     static if (isForwardRange!RangeOfRanges)
6392     {
typeofTransversal6393         @property typeof(this) save()
6394         {
6395             auto ret = this;
6396             ret._input = _input.save;
6397             return ret;
6398         }
6399     }
6400 
6401     static if (isBidirectionalRange!RangeOfRanges)
6402     {
6403 /**
6404    Bidirectional primitives. They are offered if $(D
6405    isBidirectionalRange!RangeOfRanges).
6406 */
backTransversal6407         @property auto ref back()
6408         {
6409             assert(!empty, "Attempting to fetch the back of an empty Transversal");
6410             return _input.back[_n];
6411         }
6412 
6413         /// Ditto
popBackTransversal6414         void popBack()
6415         {
6416             assert(!empty, "Attempting to popBack an empty Transversal");
6417             _input.popBack();
6418             prime();
6419         }
6420 
6421         /// Ditto
6422         static if (hasMobileElements!InnerRange)
6423         {
moveBackTransversal6424             E moveBack()
6425             {
6426                 return _input.back.moveAt(_n);
6427             }
6428         }
6429 
6430         /// Ditto
6431         static if (hasAssignableElements!InnerRange)
6432         {
backTransversal6433             @property void back(E val)
6434             {
6435                 _input.back[_n] = val;
6436             }
6437         }
6438 
6439     }
6440 
6441     static if (isRandomAccessRange!RangeOfRanges &&
6442             (opt == TransverseOptions.assumeNotJagged ||
6443                     opt == TransverseOptions.enforceNotJagged))
6444     {
6445 /**
6446    Random-access primitive. It is offered if $(D
6447    isRandomAccessRange!RangeOfRanges && (opt ==
6448    TransverseOptions.assumeNotJagged || opt ==
6449    TransverseOptions.enforceNotJagged)).
6450 */
opIndexTransversal6451         auto ref opIndex(size_t n)
6452         {
6453             return _input[n][_n];
6454         }
6455 
6456         /// Ditto
6457         static if (hasMobileElements!InnerRange)
6458         {
moveAtTransversal6459             E moveAt(size_t n)
6460             {
6461                 return _input[n].moveAt(_n);
6462             }
6463         }
6464 
6465         /// Ditto
6466         static if (hasAssignableElements!InnerRange)
6467         {
opIndexAssignTransversal6468             void opIndexAssign(E val, size_t n)
6469             {
6470                 _input[n][_n] = val;
6471             }
6472         }
6473 
6474         /// Ditto
6475         static if (hasLength!RangeOfRanges)
6476         {
lengthTransversal6477             @property size_t length()
6478             {
6479                 return _input.length;
6480             }
6481 
6482             alias opDollar = length;
6483         }
6484 
6485 /**
6486    Slicing if offered if $(D RangeOfRanges) supports slicing and all the
6487    conditions for supporting indexing are met.
6488 */
6489         static if (hasSlicing!RangeOfRanges)
6490         {
opSliceTransversal6491             typeof(this) opSlice(size_t lower, size_t upper)
6492             {
6493                 return typeof(this)(_input[lower .. upper], _n);
6494             }
6495         }
6496     }
6497 
opSliceTransversal6498     auto opSlice() { return this; }
6499 
6500 private:
6501     RangeOfRanges _input;
6502     size_t _n;
6503 }
6504 
6505 /// Ditto
6506 Transversal!(RangeOfRanges, opt) transversal
6507 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
6508 (RangeOfRanges rr, size_t n)
6509 {
6510     return typeof(return)(rr, n);
6511 }
6512 
6513 ///
6514 @safe unittest
6515 {
6516     import std.algorithm.comparison : equal;
6517     int[][] x = new int[][2];
6518     x[0] = [1, 2];
6519     x[1] = [3, 4];
6520     auto ror = transversal(x, 1);
6521     assert(equal(ror, [ 2, 4 ][]));
6522 }
6523 
6524 @safe unittest
6525 {
6526     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
6527 
6528     int[][] x = new int[][2];
6529     x[0] = [ 1, 2 ];
6530     x[1] = [3, 4];
6531     auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
6532     auto witness = [ 2, 4 ];
6533     uint i;
6534     foreach (e; ror) assert(e == witness[i++]);
6535     assert(i == 2);
6536     assert(ror.length == 2);
6537 
6538     static assert(is(Transversal!(immutable int[][])));
6539 
6540     // Make sure ref, assign is being propagated.
6541     {
6542         ror.front++;
6543         scope(exit) ror.front--;
6544         assert(x[0][1] == 3);
6545     }
6546     {
6547         ror.front = 5;
6548         scope(exit) ror.front = 2;
6549         assert(x[0][1] == 5);
6550         assert(ror.moveFront() == 5);
6551     }
6552     {
6553         ror.back = 999;
6554         scope(exit) ror.back = 4;
6555         assert(x[1][1] == 999);
6556         assert(ror.moveBack() == 999);
6557     }
6558     {
6559         ror[0] = 999;
6560         scope(exit) ror[0] = 2;
6561         assert(x[0][1] == 999);
6562         assert(ror.moveAt(0) == 999);
6563     }
6564 
6565     // Test w/o ref return.
6566     alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
6567     auto drs = [D.init, D.init];
6568     foreach (num; 0 .. 10)
6569     {
6570         auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
6571         assert(t[0] == t[1]);
6572         assert(t[1] == num + 1);
6573     }
6574 
6575     static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
6576 
6577     // Test slicing.
6578     auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
6579     auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
6580     assert(mat1[0] == 6);
6581     assert(mat1[1] == 10);
6582 }
6583 
6584 struct Transposed(RangeOfRanges)
6585 if (isForwardRange!RangeOfRanges &&
6586     isInputRange!(ElementType!RangeOfRanges) &&
6587     hasAssignableElements!RangeOfRanges)
6588 {
6589     //alias ElementType = typeof(map!"a.front"(RangeOfRanges.init));
6590 
this(RangeOfRanges input)6591     this(RangeOfRanges input)
6592     {
6593         this._input = input;
6594     }
6595 
front()6596     @property auto front()
6597     {
6598         import std.algorithm.iteration : filter, map;
6599         return _input.save
6600                      .filter!(a => !a.empty)
6601                      .map!(a => a.front);
6602     }
6603 
popFront()6604     void popFront()
6605     {
6606         // Advance the position of each subrange.
6607         auto r = _input.save;
6608         while (!r.empty)
6609         {
6610             auto e = r.front;
6611             if (!e.empty)
6612             {
6613                 e.popFront();
6614                 r.front = e;
6615             }
6616 
6617             r.popFront();
6618         }
6619     }
6620 
6621     // ElementType opIndex(size_t n)
6622     // {
6623     //     return _input[n].front;
6624     // }
6625 
empty()6626     @property bool empty()
6627     {
6628         if (_input.empty) return true;
6629         foreach (e; _input.save)
6630         {
6631             if (!e.empty) return false;
6632         }
6633         return true;
6634     }
6635 
save()6636     @property Transposed save()
6637     {
6638         return Transposed(_input.save);
6639     }
6640 
opSlice()6641     auto opSlice() { return this; }
6642 
6643 private:
6644     RangeOfRanges _input;
6645 }
6646 
6647 @safe unittest
6648 {
6649     // Boundary case: transpose of empty range should be empty
6650     int[][] ror = [];
6651     assert(transposed(ror).empty);
6652 }
6653 
6654 // Issue 9507
6655 @safe unittest
6656 {
6657     import std.algorithm.comparison : equal;
6658 
6659     auto r = [[1,2], [3], [4,5], [], [6]];
6660     assert(r.transposed.equal!equal([
6661         [1, 3, 4, 6],
6662         [2, 5]
6663     ]));
6664 }
6665 
6666 /**
6667 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
6668 contains the $(I i)'th elements of the original subranges.
6669  */
6670 Transposed!RangeOfRanges transposed(RangeOfRanges)(RangeOfRanges rr)
6671 if (isForwardRange!RangeOfRanges &&
6672     isInputRange!(ElementType!RangeOfRanges) &&
6673     hasAssignableElements!RangeOfRanges)
6674 {
6675     return Transposed!RangeOfRanges(rr);
6676 }
6677 
6678 ///
6679 @safe unittest
6680 {
6681     import std.algorithm.comparison : equal;
6682     int[][] ror = [
6683         [1, 2, 3],
6684         [4, 5, 6]
6685     ];
6686     auto xp = transposed(ror);
6687     assert(equal!"a.equal(b)"(xp, [
6688         [1, 4],
6689         [2, 5],
6690         [3, 6]
6691     ]));
6692 }
6693 
6694 ///
6695 @safe unittest
6696 {
6697     int[][] x = new int[][2];
6698     x[0] = [1, 2];
6699     x[1] = [3, 4];
6700     auto tr = transposed(x);
6701     int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
6702     uint i;
6703 
foreach(e;tr)6704     foreach (e; tr)
6705     {
6706         assert(array(e) == witness[i++]);
6707     }
6708 }
6709 
6710 // Issue 8764
6711 @safe unittest
6712 {
6713     import std.algorithm.comparison : equal;
6714     ulong[1] t0 = [ 123 ];
6715 
6716     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
6717     assert(!is(typeof(transposed(t0[].chunks(1)))));
6718     assert(is(typeof(transposed(t0[].chunks(1).array()))));
6719 
6720     auto t1 = transposed(t0[].chunks(1).array());
6721     assert(equal!"a.equal(b)"(t1, [[123]]));
6722 }
6723 
6724 /**
6725 This struct takes two ranges, $(D source) and $(D indices), and creates a view
6726 of $(D source) as if its elements were reordered according to $(D indices).
6727 $(D indices) may include only a subset of the elements of $(D source) and
6728 may also repeat elements.
6729 
6730 $(D Source) must be a random access range.  The returned range will be
6731 bidirectional or random-access if $(D Indices) is bidirectional or
6732 random-access, respectively.
6733 */
6734 struct Indexed(Source, Indices)
6735 if (isRandomAccessRange!Source && isInputRange!Indices &&
6736     is(typeof(Source.init[ElementType!(Indices).init])))
6737 {
this(Source source,Indices indices)6738     this(Source source, Indices indices)
6739     {
6740         this._source = source;
6741         this._indices = indices;
6742     }
6743 
6744     /// Range primitives
front()6745     @property auto ref front()
6746     {
6747         assert(!empty, "Attempting to fetch the front of an empty Indexed");
6748         return _source[_indices.front];
6749     }
6750 
6751     /// Ditto
popFront()6752     void popFront()
6753     {
6754         assert(!empty, "Attempting to popFront an empty Indexed");
6755         _indices.popFront();
6756     }
6757 
6758     static if (isInfinite!Indices)
6759     {
6760         enum bool empty = false;
6761     }
6762     else
6763     {
6764         /// Ditto
empty()6765         @property bool empty()
6766         {
6767             return _indices.empty;
6768         }
6769     }
6770 
6771     static if (isForwardRange!Indices)
6772     {
6773         /// Ditto
typeof(this)6774         @property typeof(this) save()
6775         {
6776             // Don't need to save _source because it's never consumed.
6777             return typeof(this)(_source, _indices.save);
6778         }
6779     }
6780 
6781     /// Ditto
6782     static if (hasAssignableElements!Source)
6783     {
6784         @property auto ref front(ElementType!Source newVal)
6785         {
6786             assert(!empty);
6787             return _source[_indices.front] = newVal;
6788         }
6789     }
6790 
6791 
6792     static if (hasMobileElements!Source)
6793     {
6794         /// Ditto
moveFront()6795         auto moveFront()
6796         {
6797             assert(!empty);
6798             return _source.moveAt(_indices.front);
6799         }
6800     }
6801 
6802     static if (isBidirectionalRange!Indices)
6803     {
6804         /// Ditto
back()6805         @property auto ref back()
6806         {
6807             assert(!empty, "Attempting to fetch the back of an empty Indexed");
6808             return _source[_indices.back];
6809         }
6810 
6811         /// Ditto
popBack()6812         void popBack()
6813         {
6814            assert(!empty, "Attempting to popBack an empty Indexed");
6815            _indices.popBack();
6816         }
6817 
6818         /// Ditto
6819         static if (hasAssignableElements!Source)
6820         {
6821             @property auto ref back(ElementType!Source newVal)
6822             {
6823                 assert(!empty);
6824                 return _source[_indices.back] = newVal;
6825             }
6826         }
6827 
6828 
6829         static if (hasMobileElements!Source)
6830         {
6831             /// Ditto
moveBack()6832             auto moveBack()
6833             {
6834                 assert(!empty);
6835                 return _source.moveAt(_indices.back);
6836             }
6837         }
6838     }
6839 
6840     static if (hasLength!Indices)
6841     {
6842         /// Ditto
length()6843          @property size_t length()
6844         {
6845             return _indices.length;
6846         }
6847 
6848         alias opDollar = length;
6849     }
6850 
6851     static if (isRandomAccessRange!Indices)
6852     {
6853         /// Ditto
opIndex(size_t index)6854         auto ref opIndex(size_t index)
6855         {
6856             return _source[_indices[index]];
6857         }
6858 
6859         static if (hasSlicing!Indices)
6860         {
6861             /// Ditto
opSlice(size_t a,size_t b)6862             typeof(this) opSlice(size_t a, size_t b)
6863             {
6864                 return typeof(this)(_source, _indices[a .. b]);
6865             }
6866         }
6867 
6868 
6869         static if (hasAssignableElements!Source)
6870         {
6871             /// Ditto
6872             auto opIndexAssign(ElementType!Source newVal, size_t index)
6873             {
6874                 return _source[_indices[index]] = newVal;
6875             }
6876         }
6877 
6878 
6879         static if (hasMobileElements!Source)
6880         {
6881             /// Ditto
moveAt(size_t index)6882             auto moveAt(size_t index)
6883             {
6884                 return _source.moveAt(_indices[index]);
6885             }
6886         }
6887     }
6888 
6889     // All this stuff is useful if someone wants to index an Indexed
6890     // without adding a layer of indirection.
6891 
6892     /**
6893     Returns the source range.
6894     */
source()6895     @property Source source()
6896     {
6897         return _source;
6898     }
6899 
6900     /**
6901     Returns the indices range.
6902     */
indices()6903      @property Indices indices()
6904     {
6905         return _indices;
6906     }
6907 
6908     static if (isRandomAccessRange!Indices)
6909     {
6910         /**
6911         Returns the physical index into the source range corresponding to a
6912         given logical index.  This is useful, for example, when indexing
6913         an $(D Indexed) without adding another layer of indirection.
6914         */
physicalIndex(size_t logicalIndex)6915         size_t physicalIndex(size_t logicalIndex)
6916         {
6917             return _indices[logicalIndex];
6918         }
6919 
6920         ///
6921         @safe unittest
6922         {
6923             auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
6924             assert(ind.physicalIndex(0) == 1);
6925         }
6926     }
6927 
6928 private:
6929     Source _source;
6930     Indices _indices;
6931 
6932 }
6933 
6934 /// Ditto
6935 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
6936 {
6937     return typeof(return)(source, indices);
6938 }
6939 
6940 ///
6941 @safe unittest
6942 {
6943     import std.algorithm.comparison : equal;
6944     auto source = [1, 2, 3, 4, 5];
6945     auto indices = [4, 3, 1, 2, 0, 4];
6946     auto ind = indexed(source, indices);
6947     assert(equal(ind, [5, 4, 2, 3, 1, 5]));
6948     assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
6949 }
6950 
6951 @safe unittest
6952 {
6953     {
6954         auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
6955         assert(ind.physicalIndex(0) == 1);
6956     }
6957 
6958     auto source = [1, 2, 3, 4, 5];
6959     auto indices = [4, 3, 1, 2, 0, 4];
6960     auto ind = indexed(source, indices);
6961 
6962     // When elements of indices are duplicated and Source has lvalue elements,
6963     // these are aliased in ind.
6964     ind[0]++;
6965     assert(ind[0] == 6);
6966     assert(ind[5] == 6);
6967 }
6968 
6969 @safe unittest
6970 {
6971     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
6972         propagatesRangeType, RangeType;
6973 
foreach(DummyType;AllDummyRanges)6974     foreach (DummyType; AllDummyRanges)
6975     {
6976         auto d = DummyType.init;
6977         auto r = indexed([1, 2, 3, 4, 5], d);
6978         static assert(propagatesRangeType!(DummyType, typeof(r)));
6979         static assert(propagatesLength!(DummyType, typeof(r)));
6980     }
6981 }
6982 
6983 /**
6984 This range iterates over fixed-sized chunks of size $(D chunkSize) of a
6985 $(D source) range. $(D Source) must be an input range. $(D chunkSize) must be
6986 greater than zero.
6987 
6988 If $(D !isInfinite!Source) and $(D source.walkLength) is not evenly
6989 divisible by $(D chunkSize), the back element of this range will contain
6990 fewer than $(D chunkSize) elements.
6991 
6992 If `Source` is a forward range, the resulting range will be forward ranges as
6993 well. Otherwise, the resulting chunks will be input ranges consuming the same
6994 input: iterating over `front` will shrink the chunk such that subsequent
6995 invocations of `front` will no longer return the full chunk, and calling
6996 `popFront` on the outer range will invalidate any lingering references to
6997 previous values of `front`.
6998 
6999 Params:
7000     source = Range from which the chunks will be selected
7001     chunkSize = Chunk size
7002 
7003 See_Also: $(LREF slide)
7004 
7005 Returns: Range of chunks.
7006 */
7007 struct Chunks(Source)
7008 if (isInputRange!Source)
7009 {
7010     static if (isForwardRange!Source)
7011     {
7012         /// Standard constructor
this(Source source,size_t chunkSize)7013         this(Source source, size_t chunkSize)
7014         {
7015             assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
7016             _source = source;
7017             _chunkSize = chunkSize;
7018         }
7019 
7020         /// Input range primitives. Always present.
front()7021         @property auto front()
7022         {
7023             assert(!empty, "Attempting to fetch the front of an empty Chunks");
7024             return _source.save.take(_chunkSize);
7025         }
7026 
7027         /// Ditto
popFront()7028         void popFront()
7029         {
7030             assert(!empty, "Attempting to popFront and empty Chunks");
7031             _source.popFrontN(_chunkSize);
7032         }
7033 
7034         static if (!isInfinite!Source)
7035             /// Ditto
empty()7036             @property bool empty()
7037             {
7038                 return _source.empty;
7039             }
7040         else
7041             // undocumented
7042             enum empty = false;
7043 
7044         /// Forward range primitives. Only present if `Source` is a forward range.
typeof(this)7045         @property typeof(this) save()
7046         {
7047             return typeof(this)(_source.save, _chunkSize);
7048         }
7049 
7050         static if (hasLength!Source)
7051         {
7052             /// Length. Only if $(D hasLength!Source) is $(D true)
length()7053             @property size_t length()
7054             {
7055                 // Note: _source.length + _chunkSize may actually overflow.
7056                 // We cast to ulong to mitigate the problem on x86 machines.
7057                 // For x64 machines, we just suppose we'll never overflow.
7058                 // The "safe" code would require either an extra branch, or a
7059                 //   modulo operation, which is too expensive for such a rare case
7060                 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
7061             }
7062             //Note: No point in defining opDollar here without slicing.
7063             //opDollar is defined below in the hasSlicing!Source section
7064         }
7065 
7066         static if (hasSlicing!Source)
7067         {
7068             //Used for various purposes
7069             private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
7070 
7071             /**
7072             Indexing and slicing operations. Provided only if
7073             $(D hasSlicing!Source) is $(D true).
7074              */
opIndex(size_t index)7075             auto opIndex(size_t index)
7076             {
7077                 immutable start = index * _chunkSize;
7078                 immutable end   = start + _chunkSize;
7079 
7080                 static if (isInfinite!Source)
7081                     return _source[start .. end];
7082                 else
7083                 {
7084                     import std.algorithm.comparison : min;
7085                     immutable len = _source.length;
7086                     assert(start < len, "chunks index out of bounds");
7087                     return _source[start .. min(end, len)];
7088                 }
7089             }
7090 
7091             /// Ditto
7092             static if (hasLength!Source)
opSlice(size_t lower,size_t upper)7093                 typeof(this) opSlice(size_t lower, size_t upper)
7094                 {
7095                     import std.algorithm.comparison : min;
7096                     assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
7097                     immutable len = _source.length;
7098                     return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
7099                 }
7100             else static if (hasSliceToEnd)
7101                 //For slicing an infinite chunk, we need to slice the source to the end.
opSlice(size_t lower,size_t upper)7102                 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
7103                 {
7104                     assert(lower <= upper, "chunks slicing index out of bounds");
7105                     return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
7106                 }
7107 
7108             static if (isInfinite!Source)
7109             {
7110                 static if (hasSliceToEnd)
7111                 {
7112                     private static struct DollarToken{}
opDollar()7113                     DollarToken opDollar()
7114                     {
7115                         return DollarToken();
7116                     }
7117                     //Slice to dollar
opSlice(size_t lower,DollarToken)7118                     typeof(this) opSlice(size_t lower, DollarToken)
7119                     {
7120                         return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
7121                     }
7122                 }
7123             }
7124             else
7125             {
7126                 //Dollar token carries a static type, with no extra information.
7127                 //It can lazily transform into _source.length on algorithmic
7128                 //operations such as : chunks[$/2, $-1];
7129                 private static struct DollarToken
7130                 {
7131                     Chunks!Source* mom;
momLengthDollarToken7132                     @property size_t momLength()
7133                     {
7134                         return mom.length;
7135                     }
7136                     alias momLength this;
7137                 }
opDollar()7138                 DollarToken opDollar()
7139                 {
7140                     return DollarToken(&this);
7141                 }
7142 
7143                 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
7144                 //1. Evaluate chunks.length
7145                 //2. Multiply by _chunksSize
7146                 //3. To finally just compare it (with min) to the original length of source (!)
7147                 //These overloads avoid that.
opSlice(DollarToken,DollarToken)7148                 typeof(this) opSlice(DollarToken, DollarToken)
7149                 {
7150                     static if (hasSliceToEnd)
7151                         return chunks(_source[$ .. $], _chunkSize);
7152                     else
7153                     {
7154                         immutable len = _source.length;
7155                         return chunks(_source[len .. len], _chunkSize);
7156                     }
7157                 }
opSlice(size_t lower,DollarToken)7158                 typeof(this) opSlice(size_t lower, DollarToken)
7159                 {
7160                     import std.algorithm.comparison : min;
7161                     assert(lower <= length, "chunks slicing index out of bounds");
7162                     static if (hasSliceToEnd)
7163                         return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
7164                     else
7165                     {
7166                         immutable len = _source.length;
7167                         return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
7168                     }
7169                 }
opSlice(DollarToken,size_t upper)7170                 typeof(this) opSlice(DollarToken, size_t upper)
7171                 {
7172                     assert(upper == length, "chunks slicing index out of bounds");
7173                     return this[$ .. $];
7174                 }
7175             }
7176         }
7177 
7178         //Bidirectional range primitives
7179         static if (hasSlicing!Source && hasLength!Source)
7180         {
7181             /**
7182             Bidirectional range primitives. Provided only if both
7183             $(D hasSlicing!Source) and $(D hasLength!Source) are $(D true).
7184              */
back()7185             @property auto back()
7186             {
7187                 assert(!empty, "back called on empty chunks");
7188                 immutable len = _source.length;
7189                 immutable start = (len - 1) / _chunkSize * _chunkSize;
7190                 return _source[start .. len];
7191             }
7192 
7193             /// Ditto
popBack()7194             void popBack()
7195             {
7196                 assert(!empty, "popBack() called on empty chunks");
7197                 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
7198                 _source = _source[0 .. end];
7199             }
7200         }
7201 
7202     private:
7203         Source _source;
7204         size_t _chunkSize;
7205     }
7206     else // is input range only
7207     {
7208         import std.typecons : RefCounted;
7209 
7210         static struct Chunk
7211         {
7212             private RefCounted!Impl impl;
7213 
emptyChunk7214             @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
frontChunk7215             @property auto front() { return impl.r.front; }
popFrontChunk7216             void popFront()
7217             {
7218                 assert(impl.curSizeLeft > 0 && !impl.r.empty);
7219                 impl.curSizeLeft--;
7220                 impl.r.popFront();
7221             }
7222         }
7223 
7224         static struct Impl
7225         {
7226             private Source r;
7227             private size_t chunkSize;
7228             private size_t curSizeLeft;
7229         }
7230 
7231         private RefCounted!Impl impl;
7232 
this(Source r,size_t chunkSize)7233         private this(Source r, size_t chunkSize)
7234         {
7235             impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
7236         }
7237 
empty()7238         @property bool empty() { return impl.chunkSize == 0; }
7239         @property Chunk front() return { return Chunk(impl); }
7240 
7241         void popFront()
7242         {
7243             impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
7244             if (!impl.r.empty)
7245                 impl.curSizeLeft = impl.chunkSize;
7246             else
7247                 impl.chunkSize = 0;
7248         }
7249 
7250         static assert(isInputRange!(typeof(this)));
7251     }
7252 }
7253 
7254 /// Ditto
7255 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
7256 if (isInputRange!Source)
7257 {
7258     return typeof(return)(source, chunkSize);
7259 }
7260 
7261 ///
7262 @safe unittest
7263 {
7264     import std.algorithm.comparison : equal;
7265     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7266     auto chunks = chunks(source, 4);
7267     assert(chunks[0] == [1, 2, 3, 4]);
7268     assert(chunks[1] == [5, 6, 7, 8]);
7269     assert(chunks[2] == [9, 10]);
7270     assert(chunks.back == chunks[2]);
7271     assert(chunks.front == chunks[0]);
7272     assert(chunks.length == 3);
7273     assert(equal(retro(array(chunks)), array(retro(chunks))));
7274 }
7275 
7276 /// Non-forward input ranges are supported, but with limited semantics.
7277 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
7278 {
7279     import std.algorithm.comparison : equal;
7280 
7281     int i;
7282 
7283     // The generator doesn't save state, so it cannot be a forward range.
7284     auto inputRange = generate!(() => ++i).take(10);
7285 
7286     // We can still process it in chunks, but it will be single-pass only.
7287     auto chunked = inputRange.chunks(2);
7288 
7289     assert(chunked.front.equal([1, 2]));
7290     assert(chunked.front.empty); // Iterating the chunk has consumed it
7291     chunked.popFront;
7292     assert(chunked.front.equal([3, 4]));
7293 }
7294 
7295 @system /*@safe*/ unittest
7296 {
7297     import std.algorithm.comparison : equal;
7298     import std.internal.test.dummyrange : ReferenceInputRange;
7299 
7300     auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
7301     auto r = new ReferenceInputRange!int(data).chunks(3);
7302     assert(r.equal!equal([
7303         [ 1, 2, 3 ],
7304         [ 4, 5, 6 ],
7305         [ 7, 8, 9 ],
7306         [ 10 ]
7307     ]));
7308 
7309     auto data2 = [ 1, 2, 3, 4, 5, 6 ];
7310     auto r2 = new ReferenceInputRange!int(data2).chunks(3);
7311     assert(r2.equal!equal([
7312         [ 1, 2, 3 ],
7313         [ 4, 5, 6 ]
7314     ]));
7315 
7316     auto data3 = [ 1, 2, 3, 4, 5 ];
7317     auto r3 = new ReferenceInputRange!int(data3).chunks(2);
7318     assert(r3.front.equal([1, 2]));
7319     r3.popFront();
7320     assert(!r3.empty);
7321     r3.popFront();
7322     assert(r3.front.equal([5]));
7323 }
7324 
7325 @safe unittest
7326 {
7327     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7328     auto chunks = chunks(source, 4);
7329     auto chunks2 = chunks.save;
7330     chunks.popFront();
7331     assert(chunks[0] == [5, 6, 7, 8]);
7332     assert(chunks[1] == [9, 10]);
7333     chunks2.popBack();
7334     assert(chunks2[1] == [5, 6, 7, 8]);
7335     assert(chunks2.length == 2);
7336 
7337     static assert(isRandomAccessRange!(typeof(chunks)));
7338 }
7339 
7340 @safe unittest
7341 {
7342     import std.algorithm.comparison : equal;
7343 
7344     //Extra toying with slicing and indexing.
7345     auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
7346     auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
7347 
7348     assert(chunks1.length == 5);
7349     assert(chunks2.length == 5);
7350     assert(chunks1[4] == [4]);
7351     assert(chunks2[4] == [4, 4]);
7352     assert(chunks1.back == [4]);
7353     assert(chunks2.back == [4, 4]);
7354 
7355     assert(chunks1[0 .. 1].equal([[0, 0]]));
7356     assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
7357     assert(chunks1[4 .. 5].equal([[4]]));
7358     assert(chunks2[4 .. 5].equal([[4, 4]]));
7359 
7360     assert(chunks1[0 .. 0].equal((int[][]).init));
7361     assert(chunks1[5 .. 5].equal((int[][]).init));
7362     assert(chunks2[5 .. 5].equal((int[][]).init));
7363 
7364     //Fun with opDollar
7365     assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
7366     assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
7367     assert(chunks1[$ - 1 .. $].equal([[4]]));      //Semiquick
7368     assert(chunks2[$ - 1 .. $].equal([[4, 4]]));   //Semiquick
7369     assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
7370     assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
7371 
7372     assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
7373 }
7374 
7375 @safe unittest
7376 {
7377     import std.algorithm.comparison : equal;
7378     import std.algorithm.iteration : filter;
7379 
7380     //ForwardRange
7381     auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
7382     assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
7383 
7384     //InfiniteRange w/o RA
7385     auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
7386     assert(equal!`equal(a, b)`(fibsByPairs.take(2),         [[ 1,  1], [ 2,  3]]));
7387 
7388     //InfiniteRange w/ RA and slicing
7389     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
7390     auto oddsByPairs = odds.chunks(2);
7391     assert(equal!`equal(a, b)`(oddsByPairs.take(2),         [[ 1,  3], [ 5,  7]]));
7392 
7393     //Requires phobos#991 for Sequence to have slice to end
7394     static assert(hasSlicing!(typeof(odds)));
7395     assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5],         [[13, 15], [17, 19]]));
7396     assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
7397 }
7398 
7399 
7400 
7401 /**
7402 This range splits a $(D source) range into $(D chunkCount) chunks of
7403 approximately equal length. $(D Source) must be a forward range with
7404 known length.
7405 
7406 Unlike $(LREF chunks), $(D evenChunks) takes a chunk count (not size).
7407 The returned range will contain zero or more $(D source.length /
7408 chunkCount + 1) elements followed by $(D source.length / chunkCount)
7409 elements. If $(D source.length < chunkCount), some chunks will be empty.
7410 
7411 $(D chunkCount) must not be zero, unless $(D source) is also empty.
7412 */
7413 struct EvenChunks(Source)
7414 if (isForwardRange!Source && hasLength!Source)
7415 {
7416     /// Standard constructor
this(Source source,size_t chunkCount)7417     this(Source source, size_t chunkCount)
7418     {
7419         assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
7420         _source = source;
7421         _chunkCount = chunkCount;
7422     }
7423 
7424     /// Forward range primitives. Always present.
front()7425     @property auto front()
7426     {
7427         assert(!empty, "Attempting to fetch the front of an empty evenChunks");
7428         return _source.save.take(_chunkPos(1));
7429     }
7430 
7431     /// Ditto
popFront()7432     void popFront()
7433     {
7434         assert(!empty, "Attempting to popFront an empty evenChunks");
7435         _source.popFrontN(_chunkPos(1));
7436         _chunkCount--;
7437     }
7438 
7439     /// Ditto
empty()7440     @property bool empty()
7441     {
7442         return _source.empty;
7443     }
7444 
7445     /// Ditto
typeof(this)7446     @property typeof(this) save()
7447     {
7448         return typeof(this)(_source.save, _chunkCount);
7449     }
7450 
7451     /// Length
length()7452     @property size_t length() const
7453     {
7454         return _chunkCount;
7455     }
7456     //Note: No point in defining opDollar here without slicing.
7457     //opDollar is defined below in the hasSlicing!Source section
7458 
7459     static if (hasSlicing!Source)
7460     {
7461         /**
7462         Indexing, slicing and bidirectional operations and range primitives.
7463         Provided only if $(D hasSlicing!Source) is $(D true).
7464          */
opIndex(size_t index)7465         auto opIndex(size_t index)
7466         {
7467             assert(index < _chunkCount, "evenChunks index out of bounds");
7468             return _source[_chunkPos(index) .. _chunkPos(index+1)];
7469         }
7470 
7471         /// Ditto
opSlice(size_t lower,size_t upper)7472         typeof(this) opSlice(size_t lower, size_t upper)
7473         {
7474             assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
7475             return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
7476         }
7477 
7478         /// Ditto
back()7479         @property auto back()
7480         {
7481             assert(!empty, "back called on empty evenChunks");
7482             return _source[_chunkPos(_chunkCount - 1) .. _source.length];
7483         }
7484 
7485         /// Ditto
popBack()7486         void popBack()
7487         {
7488             assert(!empty, "popBack() called on empty evenChunks");
7489             _source = _source[0 .. _chunkPos(_chunkCount - 1)];
7490             _chunkCount--;
7491         }
7492     }
7493 
7494 private:
7495     Source _source;
7496     size_t _chunkCount;
7497 
_chunkPos(size_t i)7498     size_t _chunkPos(size_t i)
7499     {
7500         /*
7501             _chunkCount = 5, _source.length = 13:
7502 
7503                chunk0
7504                  |   chunk3
7505                  |     |
7506                  v     v
7507                 +-+-+-+-+-+   ^
7508                 |0|3|.| | |   |
7509                 +-+-+-+-+-+   | div
7510                 |1|4|.| | |   |
7511                 +-+-+-+-+-+   v
7512                 |2|5|.|
7513                 +-+-+-+
7514 
7515                 <----->
7516                   mod
7517 
7518                 <--------->
7519                 _chunkCount
7520 
7521             One column is one chunk.
7522             popFront and popBack pop the left-most
7523             and right-most column, respectively.
7524         */
7525 
7526         auto div = _source.length / _chunkCount;
7527         auto mod = _source.length % _chunkCount;
7528         auto pos = i <= mod
7529             ? i   * (div+1)
7530             : mod * (div+1) + (i-mod) * div
7531         ;
7532         //auto len = i < mod
7533         //    ? div+1
7534         //    : div
7535         //;
7536         return pos;
7537     }
7538 }
7539 
7540 /// Ditto
7541 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
7542 if (isForwardRange!Source && hasLength!Source)
7543 {
7544     return typeof(return)(source, chunkCount);
7545 }
7546 
7547 ///
7548 @safe unittest
7549 {
7550     import std.algorithm.comparison : equal;
7551     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7552     auto chunks = evenChunks(source, 3);
7553     assert(chunks[0] == [1, 2, 3, 4]);
7554     assert(chunks[1] == [5, 6, 7]);
7555     assert(chunks[2] == [8, 9, 10]);
7556 }
7557 
7558 @safe unittest
7559 {
7560     import std.algorithm.comparison : equal;
7561 
7562     auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7563     auto chunks = evenChunks(source, 3);
7564     assert(chunks.back == chunks[2]);
7565     assert(chunks.front == chunks[0]);
7566     assert(chunks.length == 3);
7567     assert(equal(retro(array(chunks)), array(retro(chunks))));
7568 
7569     auto chunks2 = chunks.save;
7570     chunks.popFront();
7571     assert(chunks[0] == [5, 6, 7]);
7572     assert(chunks[1] == [8, 9, 10]);
7573     chunks2.popBack();
7574     assert(chunks2[1] == [5, 6, 7]);
7575     assert(chunks2.length == 2);
7576 
7577     static assert(isRandomAccessRange!(typeof(chunks)));
7578 }
7579 
7580 @safe unittest
7581 {
7582     import std.algorithm.comparison : equal;
7583 
7584     int[] source = [];
7585     auto chunks = source.evenChunks(0);
7586     assert(chunks.length == 0);
7587     chunks = source.evenChunks(3);
7588     assert(equal(chunks, [[], [], []]));
7589     chunks = [1, 2, 3].evenChunks(5);
7590     assert(equal(chunks, [[1], [2], [3], [], []]));
7591 }
7592 
7593 /*
7594 A fixed-sized sliding window iteration
7595 of size `windowSize` over a `source` range by a custom `stepSize`.
7596 
7597 The `Source` range must be at least an `ForwardRange` and
7598 the `windowSize` must be greater than zero.
7599 
7600 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
7601 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
7602 
7603 Params:
7604     f = If `Yes.withFewerElements` slide with fewer
7605         elements than `windowSize`. This can only happen if the initial range
7606         contains less elements than `windowSize`. In this case
7607         if `No.withFewerElements` an empty range will be returned.
7608     source = Range from which the slide will be selected
7609     windowSize = Sliding window size
7610     stepSize = Steps between the windows (by default 1)
7611 
7612 Returns: Range of all sliding windows with propagated bi-directionality,
7613          forwarding, conditional random access, and slicing.
7614 
7615 See_Also: $(LREF chunks)
7616 */
7617 // Explicitly set to private to delay the release until 2.076
7618 private
7619 auto slide(Flag!"withFewerElements" f = Yes.withFewerElements,
7620             Source)(Source source, size_t windowSize, size_t stepSize = 1)
7621     if (isForwardRange!Source)
7622 {
7623     return Slides!(f, Source)(source, windowSize, stepSize);
7624 }
7625 
7626 private struct Slides(Flag!"withFewerElements" withFewerElements = Yes.withFewerElements, Source)
7627     if (isForwardRange!Source)
7628 {
7629 private:
7630     Source _source;
7631     size_t _windowSize;
7632     size_t _stepSize;
7633 
7634     static if (hasLength!Source)
7635     {
7636         enum needsEndTracker = false;
7637     }
7638     else
7639     {
7640         // if there's no information about the length, track needs to be kept manually
7641         Source _nextSource;
7642         enum needsEndTracker = true;
7643     }
7644 
7645     bool _empty;
7646 
7647     static if (hasSlicing!Source)
7648     {
7649         enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
7650     }
7651 
7652 public:
7653     /// Standard constructor
thisSlides7654     this(Source source, size_t windowSize, size_t stepSize)
7655     {
7656         assert(windowSize > 0, "windowSize must be greater than zero");
7657         assert(stepSize > 0, "stepSize must be greater than zero");
7658         _source = source;
7659         _windowSize = windowSize;
7660         _stepSize = stepSize;
7661 
7662         static if (needsEndTracker)
7663         {
7664             // _nextSource is used to "look into the future" and check for the end
7665             _nextSource = source.save;
7666             _nextSource.popFrontN(windowSize);
7667         }
7668 
7669         static if (!withFewerElements)
7670         {
7671             // empty source range is needed, s.t. length, slicing etc. works properly
7672             static if (needsEndTracker)
7673             {
7674                 if (_nextSource.empty)
7675                     _source = _nextSource;
7676             }
7677             else
7678             {
7679                 if (_source.length < windowSize)
7680                 {
7681                     static if (hasSlicing!Source)
7682                     {
7683                         // if possible use the faster opDollar overload
7684                         static if (hasSliceToEnd)
7685                             _source = _source[$ .. $];
7686                         else
7687                             _source = _source[_source.length .. _source.length];
7688                     }
7689                     else
7690                     {
7691                         _source.popFrontN(_source.length);
7692                     }
7693                 }
7694             }
7695         }
7696 
7697         _empty = _source.empty;
7698     }
7699 
7700     /// Forward range primitives. Always present.
frontSlides7701     @property auto front()
7702     {
7703         assert(!empty, "Attempting to access front on an empty slide");
7704         static if (hasSlicing!Source && hasLength!Source)
7705         {
7706             import std.algorithm.comparison : min;
7707             return _source[0 .. min(_windowSize, _source.length)];
7708         }
7709         else
7710         {
7711             return _source.save.take(_windowSize);
7712         }
7713     }
7714 
7715     /// Ditto
popFrontSlides7716     void popFront()
7717     {
7718         assert(!empty, "Attempting to call popFront() on an empty slide");
7719         _source.popFrontN(_stepSize);
7720 
7721         // if the range has less elements than its window size,
7722         // we have seen the last full window (i.e. its empty)
7723         static if (needsEndTracker)
7724         {
7725             if (_nextSource.empty)
7726                 _empty = true;
7727             else
7728                 _nextSource.popFrontN(_stepSize);
7729         }
7730         else
7731         {
7732             if (_source.length < _windowSize)
7733                 _empty = true;
7734         }
7735     }
7736 
7737     static if (!isInfinite!Source)
7738     {
7739         /// Ditto
emptySlides7740         @property bool empty() const
7741         {
7742             return _empty;
7743         }
7744     }
7745     else
7746     {
7747         // undocumented
7748         enum empty = false;
7749     }
7750 
7751     /// Ditto
typeofSlides7752     @property typeof(this) save()
7753     {
7754         return typeof(this)(_source.save, _windowSize, _stepSize);
7755     }
7756 
7757     static if (hasLength!Source)
7758     {
7759         /// Length. Only if $(D hasLength!Source) is $(D true)
lengthSlides7760         @property size_t length()
7761         {
7762             if (_source.length < _windowSize)
7763             {
7764                 static if (withFewerElements)
7765                     return 1;
7766                 else
7767                     return 0;
7768             }
7769             else
7770             {
7771                 return (_source.length - _windowSize + _stepSize) / _stepSize;
7772             }
7773         }
7774     }
7775 
7776     static if (hasSlicing!Source)
7777     {
7778         /**
7779         Indexing and slicing operations. Provided only if
7780         `hasSlicing!Source` is `true`.
7781          */
opIndexSlides7782         auto opIndex(size_t index)
7783         {
7784             immutable start = index * _stepSize;
7785 
7786             static if (isInfinite!Source)
7787             {
7788                 immutable end = start + _windowSize;
7789             }
7790             else
7791             {
7792                 import std.algorithm.comparison : min;
7793 
7794                 immutable len = _source.length;
7795                 assert(start < len, "slide index out of bounds");
7796                 immutable end = min(start + _windowSize, len);
7797             }
7798 
7799             return _source[start .. end];
7800         }
7801 
7802         static if (!isInfinite!Source)
7803         {
7804             /// ditto
opSliceSlides7805             typeof(this) opSlice(size_t lower, size_t upper)
7806             {
7807                 import std.algorithm.comparison : min;
7808                 assert(lower <= upper && upper <= length, "slide slicing index out of bounds");
7809 
7810                 lower *= _stepSize;
7811                 upper *= _stepSize;
7812 
7813                 immutable len = _source.length;
7814 
7815                 /*
7816                 * Notice that we only need to move for windowSize - 1 to the right:
7817                 * source = [0, 1, 2, 3] (length: 4)
7818                 * - source.slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
7819                 *   right pos for s[0 .. 3]: 3 (upper) + 2 (windowSize) - 1 = 4
7820                 *
7821                 * - source.slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
7822                 *   right pos for s[0 .. 2]: 2 (upper) + 3 (windowSize) - 1 = 4
7823                 *
7824                 * source = [0, 1, 2, 3, 4] (length: 5)
7825                 * - source.slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
7826                 *   right pos for s[0 .. 2]: 2 (upper) + 4 (windowSize) - 1 = 5
7827                 */
7828                 return typeof(this)
7829                     (_source[min(lower, len) .. min(upper + _windowSize - 1, len)],
7830                      _windowSize, _stepSize);
7831             }
7832         }
7833         else static if (hasSliceToEnd)
7834         {
7835             //For slicing an infinite chunk, we need to slice the source to the infinite end.
opSliceSlides7836             auto opSlice(size_t lower, size_t upper)
7837             {
7838                 assert(lower <= upper, "slide slicing index out of bounds");
7839                 return typeof(this)(_source[lower * _stepSize .. $],
7840                        _windowSize, _stepSize).takeExactly(upper - lower);
7841             }
7842         }
7843 
7844         static if (isInfinite!Source)
7845         {
7846             static if (hasSliceToEnd)
7847             {
7848                 private static struct DollarToken{}
opDollarSlides7849                 DollarToken opDollar()
7850                 {
7851                     return DollarToken();
7852                 }
7853                 //Slice to dollar
opSliceSlides7854                 typeof(this) opSlice(size_t lower, DollarToken)
7855                 {
7856                     return typeof(this)(_source[lower * _stepSize .. $], _windowSize, _stepSize);
7857                 }
7858             }
7859         }
7860         else
7861         {
7862             //Dollar token carries a static type, with no extra information.
7863             //It can lazily transform into _source.length on algorithmic
7864             //operations such as : slide[$/2, $-1];
7865             private static struct DollarToken
7866             {
7867                 private size_t _length;
7868                 alias _length this;
7869             }
7870 
opDollarSlides7871             DollarToken opDollar()
7872             {
7873                 return DollarToken(this.length);
7874             }
7875 
7876             // Optimized slice overloads optimized for using dollar.
opSliceSlides7877             typeof(this) opSlice(DollarToken, DollarToken)
7878             {
7879                 static if (hasSliceToEnd)
7880                 {
7881                     return typeof(this)(_source[$ .. $], _windowSize, _stepSize);
7882                 }
7883                 else
7884                 {
7885                     immutable len = _source.length;
7886                     return typeof(this)(_source[len .. len], _windowSize, _stepSize);
7887                 }
7888             }
7889 
7890             // Optimized slice overloads optimized for using dollar.
opSliceSlides7891             typeof(this) opSlice(size_t lower, DollarToken)
7892             {
7893                 import std.algorithm.comparison : min;
7894                 assert(lower <= length, "slide slicing index out of bounds");
7895                 lower *= _stepSize;
7896                 static if (hasSliceToEnd)
7897                 {
7898                     return typeof(this)(_source[min(lower, _source.length) .. $], _windowSize, _stepSize);
7899                 }
7900                 else
7901                 {
7902                     immutable len = _source.length;
7903                     return typeof(this)(_source[min(lower, len) .. len], _windowSize, _stepSize);
7904                 }
7905             }
7906 
7907             // Optimized slice overloads optimized for using dollar.
opSliceSlides7908             typeof(this) opSlice(DollarToken, size_t upper)
7909             {
7910                 assert(upper == length, "slide slicing index out of bounds");
7911                 return this[$ .. $];
7912             }
7913         }
7914 
7915         // Bidirectional range primitives
7916         static if (!isInfinite!Source)
7917         {
7918             /**
7919             Bidirectional range primitives. Provided only if both
7920             `hasSlicing!Source` and `!isInfinite!Source` are `true`.
7921              */
backSlides7922             @property auto back()
7923             {
7924                 import std.algorithm.comparison : max;
7925 
7926                 assert(!empty, "Attempting to access front on an empty slide");
7927 
7928                 immutable len = _source.length;
7929                 /*
7930                 * Note:
7931                 * - `end` in the following is the exclusive end as used in opSlice
7932                 * - For the trivial case with `stepSize = 1`  `end` is at `len`:
7933                 *
7934                 *    iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]    (end = 4)
7935                 *    iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]]     (end = 4)
7936                 *
7937                 * - For the non-trivial cases, we need to calculate the gap
7938                 *   between `len` and `end` - this is the number of missing elements
7939                 *   from the input range:
7940                 *
7941                 *    iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
7942                 *    iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
7943                 *    iota(7).slide(1, 5) = [[0], [5]]       || <gap: 1> 6
7944                 *
7945                 *   As it can be seen `gap` can be at most `stepSize - 1`
7946                 *   More generally the elements of the sliding window with
7947                 *   `w = windowSize` and `s = stepSize` are:
7948                 *
7949                 *     [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
7950                 *
7951                 *  We can thus calculate the gap between the `end` and `len` as:
7952                 *
7953                 *     gap = len - (n * s + w) = len - w - (n * s)
7954                 *
7955                 *  As we aren't interested in exact value of `n`, but the best
7956                 *  minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
7957                 *
7958                 *     gap = len - w - (s - s ... - s) = (len - w) % s
7959                 *
7960                 *  So for example:
7961                 *
7962                 *    iota(7).slide(2, 3) = [[0, 1], [3, 4]]
7963                 *      gap: (7 - 2) % 3 = 5 % 3 = 2
7964                 *      end: 7 - 2 = 5
7965                 *
7966                 *    iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
7967                 *      gap: (7 - 4) % 2 = 3 % 2 = 1
7968                 *      end: 7 - 1 = 6
7969                 */
7970                 size_t gap = (len - _windowSize)  % _stepSize;
7971 
7972                 // check for underflow
7973                 immutable start = (len > _windowSize + gap) ? len - _windowSize - gap : 0;
7974 
7975                 return _source[start .. len - gap];
7976             }
7977 
7978             /// Ditto
popBackSlides7979             void popBack()
7980             {
7981                 assert(!empty, "Attempting to call popBack() on an empty slide");
7982 
7983                 immutable end = _source.length > _stepSize ? _source.length - _stepSize : 0;
7984                 _source = _source[0 .. end];
7985 
7986                 if (_source.length < _windowSize)
7987                     _empty = true;
7988             }
7989         }
7990     }
7991 }
7992 
7993 //
7994 @safe pure nothrow unittest
7995 {
7996     import std.algorithm.comparison : equal;
7997     import std.array : array;
7998 
7999     assert([0, 1, 2, 3].slide(2).equal!equal(
8000         [[0, 1], [1, 2], [2, 3]]
8001     ));
8002     assert(5.iota.slide(3).equal!equal(
8003         [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
8004     ));
8005 
8006     assert(iota(7).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5]]));
8007     assert(iota(12).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]]));
8008 
8009     // set a custom stepsize (default 1)
8010     assert(6.iota.slide(1, 2).equal!equal(
8011         [[0], [2], [4]]
8012     ));
8013 
8014     assert(6.iota.slide(2, 4).equal!equal(
8015         [[0, 1], [4, 5]]
8016     ));
8017 
8018     // allow slide with less elements than the window size
8019     assert(3.iota.slide!(No.withFewerElements)(4).empty);
8020     assert(3.iota.slide!(Yes.withFewerElements)(4).equal!equal(
8021         [[0, 1, 2]]
8022     ));
8023 }
8024 
8025 // count k-mers
8026 @safe pure nothrow unittest
8027 {
8028     import std.algorithm.comparison : equal;
8029     import std.algorithm.iteration : each;
8030 
8031     int[dstring] d;
8032     "AGAGA"d.slide(2).each!(a => d[a]++);
8033     assert(d == ["AG"d: 2, "GA"d: 2]);
8034 }
8035 
8036 // @nogc
8037 @safe pure nothrow @nogc unittest
8038 {
8039     import std.algorithm.comparison : equal;
8040 
8041     static immutable res1 = [[0], [1], [2], [3]];
8042     assert(4.iota.slide(1).equal!equal(res1));
8043 
8044     static immutable res2 = [[0, 1], [1, 2], [2, 3]];
8045     assert(4.iota.slide(2).equal!equal(res2));
8046 }
8047 
8048 // different window sizes
8049 @safe pure nothrow unittest
8050 {
8051     import std.algorithm.comparison : equal;
8052     import std.array : array;
8053 
8054     assert([0, 1, 2, 3].slide(1).array == [[0], [1], [2], [3]]);
8055     assert([0, 1, 2, 3].slide(2).array == [[0, 1], [1, 2], [2, 3]]);
8056     assert([0, 1, 2, 3].slide(3).array == [[0, 1, 2], [1, 2, 3]]);
8057     assert([0, 1, 2, 3].slide(4).array == [[0, 1, 2, 3]]);
8058     assert([0, 1, 2, 3].slide(5).array == [[0, 1, 2, 3]]);
8059 
8060 
8061     assert(iota(2).slide(2).front.equal([0, 1]));
8062     assert(iota(3).slide(2).equal!equal([[0, 1],[1, 2]]));
8063     assert(iota(3).slide(3).equal!equal([[0, 1, 2]]));
8064     assert(iota(3).slide(4).equal!equal([[0, 1, 2]]));
8065     assert(iota(1, 4).slide(1).equal!equal([[1], [2], [3]]));
8066     assert(iota(1, 4).slide(3).equal!equal([[1, 2, 3]]));
8067 }
8068 
8069 @safe unittest
8070 {
8071     import std.algorithm.comparison : equal;
8072 
8073     assert(6.iota.slide(1, 1).equal!equal(
8074         [[0], [1], [2], [3], [4], [5]]
8075     ));
8076     assert(6.iota.slide(1, 2).equal!equal(
8077         [[0], [2], [4]]
8078     ));
8079     assert(6.iota.slide(1, 3).equal!equal(
8080         [[0], [3]]
8081     ));
8082     assert(6.iota.slide(1, 4).equal!equal(
8083         [[0], [4]]
8084     ));
8085     assert(6.iota.slide(1, 5).equal!equal(
8086         [[0], [5]]
8087     ));
8088     assert(6.iota.slide(2, 1).equal!equal(
8089         [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]
8090     ));
8091     assert(6.iota.slide(2, 2).equal!equal(
8092         [[0, 1], [2, 3], [4, 5]]
8093     ));
8094     assert(6.iota.slide(2, 3).equal!equal(
8095         [[0, 1], [3, 4]]
8096     ));
8097     assert(6.iota.slide(2, 4).equal!equal(
8098         [[0, 1], [4, 5]]
8099     ));
8100     assert(6.iota.slide(2, 5).equal!equal(
8101         [[0, 1]]
8102     ));
8103     assert(6.iota.slide(3, 1).equal!equal(
8104         [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
8105     ));
8106     assert(6.iota.slide(3, 2).equal!equal(
8107         [[0, 1, 2], [2, 3, 4]]
8108     ));
8109     assert(6.iota.slide(3, 3).equal!equal(
8110         [[0, 1, 2], [3, 4, 5]]
8111     ));
8112     assert(6.iota.slide(3, 4).equal!equal(
8113         [[0, 1, 2]]
8114     ));
8115     assert(6.iota.slide(4, 1).equal!equal(
8116         [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
8117     ));
8118     assert(6.iota.slide(4, 2).equal!equal(
8119         [[0, 1, 2, 3], [2, 3, 4, 5]]
8120     ));
8121     assert(6.iota.slide(4, 3).equal!equal(
8122         [[0, 1, 2, 3]]
8123     ));
8124     assert(6.iota.slide(5, 1).equal!equal(
8125         [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]
8126     ));
8127     assert(6.iota.slide(5, 2).equal!equal(
8128         [[0, 1, 2, 3, 4]]
8129     ));
8130     assert(6.iota.slide(5, 3).equal!equal(
8131         [[0, 1, 2, 3, 4]]
8132     ));
8133 }
8134 
8135 // emptyness, copyability, strings
8136 @safe pure nothrow unittest
8137 {
8138     import std.algorithm.comparison : equal;
8139     import std.algorithm.iteration : each, map;
8140 
8141     // check with empty input
8142     int[] d;
8143     assert(d.slide(2).empty);
8144     assert(d.slide(2, 2).empty);
8145 
8146     // is copyable?
8147     auto e = iota(5).slide(2);
8148     e.popFront;
8149     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
8150     assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
8151     assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
8152 
8153     // test with strings
8154     int[dstring] f;
8155     "AGAGA"d.slide(3).each!(a => f[a]++);
8156     assert(f == ["AGA"d: 2, "GAG"d: 1]);
8157 
8158     int[dstring] g;
8159     "ABCDEFG"d.slide(3, 3).each!(a => g[a]++);
8160     assert(g == ["ABC"d:1, "DEF"d:1]);
8161 }
8162 
8163 // test slicing, length
8164 @safe pure nothrow unittest
8165 {
8166     import std.algorithm.comparison : equal;
8167     import std.array : array;
8168 
8169     // test index
8170     assert(iota(3).slide(4)[0].equal([0, 1, 2]));
8171     assert(iota(5).slide(4)[1].equal([1, 2, 3, 4]));
8172     assert(iota(3).slide(4, 2)[0].equal([0, 1, 2]));
8173     assert(iota(5).slide(4, 2)[1].equal([2, 3, 4]));
8174     assert(iota(3).slide(4, 3)[0].equal([0, 1, 2]));
8175     assert(iota(5).slide(4, 3)[1].equal([3, 4,]));
8176 
8177     // test slicing
8178     assert(iota(3).slide(4)[0 .. $].equal!equal([[0, 1, 2]]));
8179     assert(iota(3).slide(2)[1 .. $].equal!equal([[1, 2]]));
8180     assert(iota(1, 5).slide(2)[0 .. 1].equal!equal([[1, 2]]));
8181     assert(iota(1, 5).slide(2)[0 .. 2].equal!equal([[1, 2], [2, 3]]));
8182     assert(iota(1, 5).slide(3)[0 .. 1].equal!equal([[1, 2, 3]]));
8183     assert(iota(1, 5).slide(3)[0 .. 2].equal!equal([[1, 2, 3], [2, 3, 4]]));
8184     assert(iota(1, 6).slide(3)[2 .. 3].equal!equal([[3, 4, 5]]));
8185     assert(iota(1, 5).slide(4)[0 .. 1].equal!equal([[1, 2, 3, 4]]));
8186 
8187     // length
8188     assert(iota(3).slide(1).length == 3);
8189     assert(iota(3).slide(1, 2).length == 2);
8190     assert(iota(3).slide(1, 3).length == 1);
8191     assert(iota(3).slide(1, 4).length == 1);
8192     assert(iota(3).slide(2).length == 2);
8193     assert(iota(3).slide(2, 2).length == 1);
8194     assert(iota(3).slide(2, 3).length == 1);
8195     assert(iota(3).slide(3).length == 1);
8196     assert(iota(3).slide(3, 2).length == 1);
8197 
8198     // opDollar
8199     assert(iota(3).slide(4)[$/2 .. $].equal!equal([[0, 1, 2]]));
8200     assert(iota(3).slide(4)[$ .. $].empty);
8201     assert(iota(3).slide(4)[$ .. 1].empty);
8202 
8203     assert(iota(5).slide(3, 1)[$/2 .. $].equal!equal([[1, 2, 3], [2, 3, 4]]));
8204     assert(iota(5).slide(3, 2)[$/2 .. $].equal!equal([[2, 3, 4]]));
8205     assert(iota(5).slide(3, 3)[$/2 .. $].equal!equal([[0, 1, 2]]));
8206     assert(iota(3).slide(4, 3)[$ .. $].empty);
8207     assert(iota(3).slide(4, 3)[$ .. 1].empty);
8208 }
8209 
8210 // test No.withFewerElements
8211 @safe pure nothrow unittest
8212 {
8213     assert(iota(3).slide(4).length == 1);
8214     assert(iota(3).slide(4, 4).length == 1);
8215 
8216     assert(iota(3).slide!(No.withFewerElements)(4).empty);
8217     assert(iota(3, 3).slide!(No.withFewerElements)(4).empty);
8218     assert(iota(3).slide!(No.withFewerElements)(4).length == 0);
8219     assert(iota(3).slide!(No.withFewerElements)(4, 4).length == 0);
8220 
8221     assert(iota(3).slide!(No.withFewerElements)(400).empty);
8222     assert(iota(3).slide!(No.withFewerElements)(400).length == 0);
8223     assert(iota(3).slide!(No.withFewerElements)(400, 10).length == 0);
8224 
8225     assert(iota(3).slide!(No.withFewerElements)(4)[0 .. $].empty);
8226     assert(iota(3).slide!(No.withFewerElements)(4)[$ .. $].empty);
8227     assert(iota(3).slide!(No.withFewerElements)(4)[$ .. 0].empty);
8228     assert(iota(3).slide!(No.withFewerElements)(4)[$/2 .. $].empty);
8229 
8230     // with different step sizes
8231     assert(iota(3).slide!(No.withFewerElements)(4, 5)[0 .. $].empty);
8232     assert(iota(3).slide!(No.withFewerElements)(4, 6)[$ .. $].empty);
8233     assert(iota(3).slide!(No.withFewerElements)(4, 7)[$ .. 0].empty);
8234     assert(iota(3).slide!(No.withFewerElements)(4, 8)[$/2 .. $].empty);
8235 }
8236 
8237 // test with infinite ranges
8238 @safe pure nothrow unittest
8239 {
8240     import std.algorithm.comparison : equal;
8241 
8242     // InfiniteRange without RandomAccess
8243     auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
8244     assert(fibs.slide(2).take(2).equal!equal([[1,  1], [1,  2]]));
8245     assert(fibs.slide(2, 3).take(2).equal!equal([[1,  1], [3,  5]]));
8246 
8247     // InfiniteRange with RandomAccess and slicing
8248     auto odds = sequence!("a[0] + n * a[1]")(1, 2);
8249     auto oddsByPairs = odds.slide(2);
8250     assert(oddsByPairs.take(2).equal!equal([[ 1,  3], [ 3,  5]]));
8251     assert(oddsByPairs[1].equal([3, 5]));
8252     assert(oddsByPairs[4].equal([9, 11]));
8253 
8254     static assert(hasSlicing!(typeof(odds)));
8255     assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
8256     assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
8257 
8258     auto oddsWithGaps = odds.slide(2, 4);
8259     assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
8260     assert(oddsWithGaps[2].equal([17, 19]));
8261     assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
8262     assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
8263 }
8264 
8265 // test reverse
8266 @safe pure nothrow unittest
8267 {
8268     import std.algorithm.comparison : equal;
8269 
8270     auto e = iota(3).slide(2);
8271     assert(e.retro.equal!equal([[1, 2], [0, 1]]));
8272     assert(e.retro.array.equal(e.array.retro));
8273 
8274     auto e2 = iota(5).slide(3);
8275     assert(e2.retro.equal!equal([[2, 3, 4], [1, 2, 3], [0, 1, 2]]));
8276     assert(e2.retro.array.equal(e2.array.retro));
8277 
8278     auto e3 = iota(3).slide(4);
8279     assert(e3.retro.equal!equal([[0, 1, 2]]));
8280     assert(e3.retro.array.equal(e3.array.retro));
8281 }
8282 
8283 // test reverse with different steps
8284 @safe pure nothrow unittest
8285 {
8286     import std.algorithm.comparison : equal;
8287 
8288     assert(iota(7).slide(2, 1).retro.equal!equal(
8289         [[5, 6], [4, 5], [3, 4], [2, 3], [1, 2], [0, 1]]
8290     ));
8291     assert(iota(7).slide(2, 2).retro.equal!equal(
8292         [[4, 5], [2, 3], [0, 1]]
8293     ));
8294     assert(iota(7).slide(2, 3).retro.equal!equal(
8295         [[3, 4], [0, 1]]
8296     ));
8297     assert(iota(7).slide(2, 4).retro.equal!equal(
8298         [[4, 5], [0, 1]]
8299     ));
8300     assert(iota(7).slide(2, 5).retro.equal!equal(
8301         [[5, 6], [0, 1]]
8302     ));
8303     assert(iota(7).slide(3, 1).retro.equal!equal(
8304         [[4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
8305     ));
8306     assert(iota(7).slide(3, 2).retro.equal!equal(
8307         [[4, 5, 6], [2, 3, 4], [0, 1, 2]]
8308     ));
8309     assert(iota(7).slide(4, 1).retro.equal!equal(
8310         [[3, 4, 5, 6], [2, 3, 4, 5], [1, 2, 3, 4], [0, 1, 2, 3]]
8311     ));
8312     assert(iota(7).slide(4, 2).retro.equal!equal(
8313         [[2, 3, 4, 5], [0, 1, 2, 3]]
8314     ));
8315     assert(iota(7).slide(4, 3).retro.equal!equal(
8316         [[3, 4, 5, 6], [0, 1, 2, 3]]
8317     ));
8318     assert(iota(7).slide(4, 4).retro.equal!equal(
8319         [[0, 1, 2, 3]]
8320     ));
8321     assert(iota(7).slide(5, 1).retro.equal!equal(
8322         [[2, 3, 4, 5, 6], [1, 2, 3, 4, 5], [0, 1, 2, 3, 4]]
8323     ));
8324     assert(iota(7).slide(5, 2).retro.equal!equal(
8325         [[2, 3, 4, 5, 6], [0, 1, 2, 3, 4]]
8326     ));
8327     assert(iota(7).slide(5, 3).retro.equal!equal(
8328         [[0, 1, 2, 3, 4]]
8329     ));
8330     assert(iota(7).slide(5, 4).retro.equal!equal(
8331         [[0, 1, 2, 3, 4]]
8332     ));
8333 }
8334 
8335 // step size
8336 @safe pure nothrow unittest
8337 {
8338     import std.algorithm.comparison : equal;
8339 
8340     assert(iota(7).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5]]));
8341     assert(iota(8).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5], [6, 7]]));
8342     assert(iota(9).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5], [6, 7]]));
8343     assert(iota(12).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]]));
8344     assert(iota(13).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]]));
8345 }
8346 
8347 // test with dummy ranges
8348 @safe pure nothrow unittest
8349 {
8350     import std.algorithm.comparison : equal;
8351     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy, AllDummyRanges;
8352     import std.meta : AliasSeq;
8353 
8354     alias AllForwardDummyRanges = AliasSeq!(
8355         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
8356         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
8357         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
8358         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
8359         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional),
8360         //DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
8361         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
8362         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
8363         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
8364         //DummyRange!(ReturnBy.Value, Length.No, RangeType.Input),
8365         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward),
8366         DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional)
8367     );
8368 
8369     foreach (Range; AliasSeq!AllForwardDummyRanges)
8370     {
8371         Range r;
8372         assert(r.slide(1).equal!equal(
8373             [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
8374         ));
8375         assert(r.slide(2).equal!equal(
8376             [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
8377         ));
8378         assert(r.slide(3).equal!equal(
8379             [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
8380             [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
8381         ));
8382         assert(r.slide(6).equal!equal(
8383             [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
8384             [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
8385         ));
8386         assert(r.slide(15).equal!equal(
8387             [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
8388         ));
8389 
8390         assert(r.slide!(No.withFewerElements)(15).empty);
8391     }
8392 
8393     alias BackwardsDummyRanges = AliasSeq!(
8394         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
8395         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
8396     );
8397 
8398     foreach (Range; AliasSeq!BackwardsDummyRanges)
8399     {
8400         Range r;
8401         assert(r.slide(1).retro.equal!equal(
8402             [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]
8403         ));
8404         assert(r.slide(2).retro.equal!equal(
8405             [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]
8406         ));
8407         assert(r.slide(5).retro.equal!equal(
8408             [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
8409             [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]
8410         ));
8411         assert(r.slide(15).retro.equal!equal(
8412             [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
8413         ));
8414 
8415         // different step sizes
8416         assert(r.slide(2, 4)[2].equal([9, 10]));
8417         assert(r.slide(2, 1).equal!equal(
8418             [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
8419         ));
8420         assert(r.slide(2, 2).equal!equal(
8421             [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
8422         ));
8423         assert(r.slide(2, 3).equal!equal(
8424             [[1, 2], [4, 5], [7, 8]]
8425         ));
8426         assert(r.slide(2, 4).equal!equal(
8427             [[1, 2], [5, 6], [9, 10]]
8428         ));
8429 
8430         // front = back
8431         foreach (windowSize; 1 .. 10)
8432             foreach (stepSize; 1 .. 10)
8433             {
8434                 auto slider = r.slide(windowSize, stepSize);
8435                 assert(slider.retro.retro.equal!equal(slider));
8436             }
8437     }
8438 
8439     assert(iota(1, 12).slide(2, 4)[0 .. 3].equal!equal([[1, 2], [5, 6], [9, 10]]));
8440     assert(iota(1, 12).slide(2, 4)[0 .. $].equal!equal([[1, 2], [5, 6], [9, 10]]));
8441     assert(iota(1, 12).slide(2, 4)[$/2 .. $].equal!equal([[5, 6], [9, 10]]));
8442 
8443     // reverse
8444     assert(iota(1, 12).slide(2, 4).retro.equal!equal([[9, 10], [5, 6], [1, 2]]));
8445 }
8446 
8447 // test different sliceable ranges
8448 @safe pure nothrow unittest
8449 {
8450     import std.algorithm.comparison : equal;
8451     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
8452     import std.meta : AliasSeq;
8453 
8454     struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
8455                                  Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
8456     {
8457         Range arr = 10.iota.array; // similar to DummyRange
saveSliceableRange8458         @property auto save() { return typeof(this)(arr); }
frontSliceableRange8459         @property auto front() { return arr[0]; }
popFrontSliceableRange8460         void popFront() { arr.popFront(); }
opSliceSliceableRange8461         auto opSlice(size_t i, size_t j)
8462         {
8463             // subslices can't be infinite
8464             return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
8465         }
8466 
8467         static if (withInfiniteness)
8468         {
8469             enum empty = false;
8470         }
8471         else
8472         {
emptySliceableRange8473             @property bool empty() { return arr.empty; }
lengthSliceableRange8474             @property auto length() { return arr.length; }
8475         }
8476 
8477         static if (withOpDollar)
8478         {
8479             static if (withInfiniteness)
8480             {
8481                 struct Dollar {}
opDollarSliceableRange8482                 Dollar opDollar() const { return Dollar.init; }
8483 
8484                 //Slice to dollar
opSliceSliceableRange8485                 typeof(this) opSlice(size_t lower, Dollar)
8486                 {
8487                     return typeof(this)(arr[lower .. $]);
8488                 }
8489 
8490             }
8491             else
8492             {
8493                 alias opDollar = length;
8494             }
8495         }
8496     }
8497 
8498     alias T = int[];
8499 
8500     alias SliceableDummyRanges = AliasSeq!(
8501         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, T),
8502         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, T),
8503         SliceableRange!(T, No.withOpDollar, No.withInfiniteness),
8504         SliceableRange!(T, Yes.withOpDollar, No.withInfiniteness),
8505         SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness),
8506     );
8507 
8508     foreach (Range; AliasSeq!SliceableDummyRanges)
8509     {
8510         Range r;
8511         r.arr = 10.iota.array; // for clarity
8512 
8513         static assert(isForwardRange!Range);
8514         enum hasSliceToEnd = hasSlicing!Range && is(typeof(Range.init[0 .. $]) == Range);
8515 
8516         assert(r.slide(2)[0].equal([0, 1]));
8517         assert(r.slide(2)[1].equal([1, 2]));
8518 
8519         // saveable
8520         auto s = r.slide(2);
8521         assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
8522         s.save.popFront;
8523         assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
8524 
8525         assert(r.slide(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
8526     }
8527 
8528     alias SliceableDummyRangesWithoutInfinity = AliasSeq!(
8529         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, T),
8530         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, T),
8531         SliceableRange!(T, No.withOpDollar, No.withInfiniteness),
8532         SliceableRange!(T, Yes.withOpDollar, No.withInfiniteness),
8533     );
8534 
8535     foreach (Range; AliasSeq!SliceableDummyRangesWithoutInfinity)
8536     {
8537         static assert(hasSlicing!Range);
8538         static assert(hasLength!Range);
8539 
8540         Range r;
8541         r.arr = 10.iota.array; // for clarity
8542 
8543         assert(r.slide!(No.withFewerElements)(6).equal!equal(
8544             [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
8545             [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
8546         ));
8547         assert(r.slide!(No.withFewerElements)(16).empty);
8548 
8549         assert(r.slide(4)[0 .. $].equal(r.slide(4)));
8550         assert(r.slide(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
8551         assert(r.slide(2)[$ .. $].empty);
8552 
8553         assert(r.slide(3).retro.equal!equal(
8554             [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
8555         ));
8556     }
8557 
8558     // separate checks for infinity
8559     auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
8560     assert(infIndex.slide(2)[0].equal([0, 1]));
8561     assert(infIndex.slide(2)[1].equal([1, 2]));
8562 
8563     auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
8564     assert(infDollar.slide(2)[1 .. $].front.equal([1, 2]));
8565     assert(infDollar.slide(4)[0 .. $].front.equal([0, 1, 2, 3]));
8566     assert(infDollar.slide(4)[2 .. $].front.equal([2, 3, 4, 5]));
8567 }
8568 
OnlyResult(T,size_t arity)8569 private struct OnlyResult(T, size_t arity)
8570 {
8571     private this(Values...)(auto ref Values values)
8572     {
8573         this.data = [values];
8574         this.backIndex = arity;
8575     }
8576 
8577     bool empty() @property
8578     {
8579         return frontIndex >= backIndex;
8580     }
8581 
8582     T front() @property
8583     {
8584         assert(!empty, "Attempting to fetch the front of an empty Only range");
8585         return data[frontIndex];
8586     }
8587 
8588     void popFront()
8589     {
8590         assert(!empty, "Attempting to popFront an empty Only range");
8591         ++frontIndex;
8592     }
8593 
8594     T back() @property
8595     {
8596         assert(!empty, "Attempting to fetch the back of an empty Only range");
8597         return data[backIndex - 1];
8598     }
8599 
8600     void popBack()
8601     {
8602         assert(!empty, "Attempting to popBack an empty Only range");
8603         --backIndex;
8604     }
8605 
8606     OnlyResult save() @property
8607     {
8608         return this;
8609     }
8610 
8611     size_t length() const @property
8612     {
8613         return backIndex - frontIndex;
8614     }
8615 
8616     alias opDollar = length;
8617 
8618     T opIndex(size_t idx)
8619     {
8620         // when i + idx points to elements popped
8621         // with popBack
8622         assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
8623         return data[frontIndex + idx];
8624     }
8625 
8626     OnlyResult opSlice()
8627     {
8628         return this;
8629     }
8630 
8631     OnlyResult opSlice(size_t from, size_t to)
8632     {
8633         OnlyResult result = this;
8634         result.frontIndex += from;
8635         result.backIndex = this.frontIndex + to;
8636         assert(
8637             from <= to,
8638             "Attempting to slice an Only range with a larger first argument than the second."
8639         );
8640         assert(
8641             to <= length,
8642             "Attempting to slice using an out of bounds index on an Only range"
8643         );
8644         return result;
8645     }
8646 
8647     private size_t frontIndex = 0;
8648     private size_t backIndex = 0;
8649 
8650     // @@@BUG@@@ 10643
8651     version (none)
8652     {
8653         import std.traits : hasElaborateAssign;
8654         static if (hasElaborateAssign!T)
8655             private T[arity] data;
8656         else
8657             private T[arity] data = void;
8658     }
8659     else
8660         private T[arity] data;
8661 }
8662 
8663 // Specialize for single-element results
8664 private struct OnlyResult(T, size_t arity : 1)
8665 {
frontOnlyResult8666     @property T front()
8667     {
8668         assert(!empty, "Attempting to fetch the front of an empty Only range");
8669         return _value;
8670     }
backOnlyResult8671     @property T back()
8672     {
8673         assert(!empty, "Attempting to fetch the back of an empty Only range");
8674         return _value;
8675     }
emptyOnlyResult8676     @property bool empty() const { return _empty; }
lengthOnlyResult8677     @property size_t length() const { return !_empty; }
saveOnlyResult8678     @property auto save() { return this; }
popFrontOnlyResult8679     void popFront()
8680     {
8681         assert(!_empty, "Attempting to popFront an empty Only range");
8682         _empty = true;
8683     }
popBackOnlyResult8684     void popBack()
8685     {
8686         assert(!_empty, "Attempting to popBack an empty Only range");
8687         _empty = true;
8688     }
8689     alias opDollar = length;
8690 
thisOnlyResult8691     private this()(auto ref T value)
8692     {
8693         this._value = value;
8694         this._empty = false;
8695     }
8696 
opIndexOnlyResult8697     T opIndex(size_t i)
8698     {
8699         assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
8700         return _value;
8701     }
8702 
opSliceOnlyResult8703     OnlyResult opSlice()
8704     {
8705         return this;
8706     }
8707 
opSliceOnlyResult8708     OnlyResult opSlice(size_t from, size_t to)
8709     {
8710         assert(
8711             from <= to,
8712             "Attempting to slice an Only range with a larger first argument than the second."
8713         );
8714         assert(
8715             to <= length,
8716             "Attempting to slice using an out of bounds index on an Only range"
8717         );
8718         OnlyResult copy = this;
8719         copy._empty = _empty || from == to;
8720         return copy;
8721     }
8722 
8723     private Unqual!T _value;
8724     private bool _empty = true;
8725 }
8726 
8727 // Specialize for the empty range
8728 private struct OnlyResult(T, size_t arity : 0)
8729 {
8730     private static struct EmptyElementType {}
8731 
empty()8732     bool empty() @property { return true; }
length()8733     size_t length() const @property { return 0; }
8734     alias opDollar = length;
front()8735     EmptyElementType front() @property { assert(false); }
popFront()8736     void popFront() { assert(false); }
back()8737     EmptyElementType back() @property { assert(false); }
popBack()8738     void popBack() { assert(false); }
save()8739     OnlyResult save() @property { return this; }
8740 
opIndex(size_t i)8741     EmptyElementType opIndex(size_t i)
8742     {
8743         assert(false);
8744     }
8745 
opSlice()8746     OnlyResult opSlice() { return this; }
8747 
opSlice(size_t from,size_t to)8748     OnlyResult opSlice(size_t from, size_t to)
8749     {
8750         assert(from == 0 && to == 0);
8751         return this;
8752     }
8753 }
8754 
8755 /**
8756 Assemble $(D values) into a range that carries all its
8757 elements in-situ.
8758 
8759 Useful when a single value or multiple disconnected values
8760 must be passed to an algorithm expecting a range, without
8761 having to perform dynamic memory allocation.
8762 
8763 As copying the range means copying all elements, it can be
8764 safely returned from functions. For the same reason, copying
8765 the returned range may be expensive for a large number of arguments.
8766 
8767 Params:
8768     values = the values to assemble together
8769 
8770 Returns:
8771     A `RandomAccessRange` of the assembled values.
8772 
8773 See_Also: $(LREF chain) to chain ranges
8774  */
8775 auto only(Values...)(auto ref Values values)
8776 if (!is(CommonType!Values == void) || Values.length == 0)
8777 {
8778     return OnlyResult!(CommonType!Values, Values.length)(values);
8779 }
8780 
8781 ///
8782 @safe unittest
8783 {
8784     import std.algorithm.comparison : equal;
8785     import std.algorithm.iteration : filter, joiner, map;
8786     import std.algorithm.searching : findSplitBefore;
8787     import std.uni : isUpper;
8788 
8789     assert(equal(only('♡'), "♡"));
8790     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
8791 
8792     assert(only("one", "two", "three").joiner(" ").equal("one two three"));
8793 
8794     string title = "The D Programming Language";
8795     assert(title
8796         .filter!isUpper // take the upper case letters
8797         .map!only       // make each letter its own range
8798         .joiner(".")    // join the ranges together lazily
8799         .equal("T.D.P.L"));
8800 }
8801 
8802 @safe unittest
8803 {
8804     // Verify that the same common type and same arity
8805     // results in the same template instantiation
8806     static assert(is(typeof(only(byte.init, int.init)) ==
8807         typeof(only(int.init, byte.init))));
8808 
8809     static assert(is(typeof(only((const(char)[]).init, string.init)) ==
8810         typeof(only((const(char)[]).init, (const(char)[]).init))));
8811 }
8812 
8813 // Tests the zero-element result
8814 @safe unittest
8815 {
8816     import std.algorithm.comparison : equal;
8817 
8818     auto emptyRange = only();
8819 
8820     alias EmptyRange = typeof(emptyRange);
8821     static assert(isInputRange!EmptyRange);
8822     static assert(isForwardRange!EmptyRange);
8823     static assert(isBidirectionalRange!EmptyRange);
8824     static assert(isRandomAccessRange!EmptyRange);
8825     static assert(hasLength!EmptyRange);
8826     static assert(hasSlicing!EmptyRange);
8827 
8828     assert(emptyRange.empty);
8829     assert(emptyRange.length == 0);
8830     assert(emptyRange.equal(emptyRange[]));
8831     assert(emptyRange.equal(emptyRange.save));
8832     assert(emptyRange[0 .. 0].equal(emptyRange));
8833 }
8834 
8835 // Tests the single-element result
8836 @safe unittest
8837 {
8838     import std.algorithm.comparison : equal;
8839     import std.typecons : tuple;
8840     foreach (x; tuple(1, '1', 1.0, "1", [1]))
8841     {
8842         auto a = only(x);
8843         typeof(x)[] e = [];
8844         assert(a.front == x);
8845         assert(a.back == x);
8846         assert(!a.empty);
8847         assert(a.length == 1);
8848         assert(equal(a, a[]));
8849         assert(equal(a, a[0 .. 1]));
8850         assert(equal(a[0 .. 0], e));
8851         assert(equal(a[1 .. 1], e));
8852         assert(a[0] == x);
8853 
8854         auto b = a.save;
8855         assert(equal(a, b));
8856         a.popFront();
8857         assert(a.empty && a.length == 0 && a[].empty);
8858         b.popBack();
8859         assert(b.empty && b.length == 0 && b[].empty);
8860 
8861         alias A = typeof(a);
8862         static assert(isInputRange!A);
8863         static assert(isForwardRange!A);
8864         static assert(isBidirectionalRange!A);
8865         static assert(isRandomAccessRange!A);
8866         static assert(hasLength!A);
8867         static assert(hasSlicing!A);
8868     }
8869 
8870     auto imm = only!(immutable int)(1);
8871     immutable int[] imme = [];
8872     assert(imm.front == 1);
8873     assert(imm.back == 1);
8874     assert(!imm.empty);
8875     assert(imm.init.empty); // Issue 13441
8876     assert(imm.length == 1);
8877     assert(equal(imm, imm[]));
8878     assert(equal(imm, imm[0 .. 1]));
8879     assert(equal(imm[0 .. 0], imme));
8880     assert(equal(imm[1 .. 1], imme));
8881     assert(imm[0] == 1);
8882 }
8883 
8884 // Tests multiple-element results
8885 @safe unittest
8886 {
8887     import std.algorithm.comparison : equal;
8888     import std.algorithm.iteration : joiner;
8889     import std.meta : AliasSeq;
8890     static assert(!__traits(compiles, only(1, "1")));
8891 
8892     auto nums = only!(byte, uint, long)(1, 2, 3);
8893     static assert(is(ElementType!(typeof(nums)) == long));
8894     assert(nums.length == 3);
8895 
8896     foreach (i; 0 .. 3)
8897         assert(nums[i] == i + 1);
8898 
8899     auto saved = nums.save;
8900 
8901     foreach (i; 1 .. 4)
8902     {
8903         assert(nums.front == nums[0]);
8904         assert(nums.front == i);
8905         nums.popFront();
8906         assert(nums.length == 3 - i);
8907     }
8908 
8909     assert(nums.empty);
8910 
8911     assert(saved.equal(only(1, 2, 3)));
8912     assert(saved.equal(saved[]));
8913     assert(saved[0 .. 1].equal(only(1)));
8914     assert(saved[0 .. 2].equal(only(1, 2)));
8915     assert(saved[0 .. 3].equal(saved));
8916     assert(saved[1 .. 3].equal(only(2, 3)));
8917     assert(saved[2 .. 3].equal(only(3)));
8918     assert(saved[0 .. 0].empty);
8919     assert(saved[3 .. 3].empty);
8920 
8921     alias data = AliasSeq!("one", "two", "three", "four");
8922     static joined =
8923         ["one two", "one two three", "one two three four"];
8924     string[] joinedRange = joined;
8925 
8926     foreach (argCount; AliasSeq!(2, 3, 4))
8927     {
8928         auto values = only(data[0 .. argCount]);
8929         alias Values = typeof(values);
8930         static assert(is(ElementType!Values == string));
8931         static assert(isInputRange!Values);
8932         static assert(isForwardRange!Values);
8933         static assert(isBidirectionalRange!Values);
8934         static assert(isRandomAccessRange!Values);
8935         static assert(hasSlicing!Values);
8936         static assert(hasLength!Values);
8937 
8938         assert(values.length == argCount);
8939         assert(values[0 .. $].equal(values[0 .. values.length]));
8940         assert(values.joiner(" ").equal(joinedRange.front));
8941         joinedRange.popFront();
8942     }
8943 
8944     assert(saved.retro.equal(only(3, 2, 1)));
8945     assert(saved.length == 3);
8946 
8947     assert(saved.back == 3);
8948     saved.popBack();
8949     assert(saved.length == 2);
8950     assert(saved.back == 2);
8951 
8952     assert(saved.front == 1);
8953     saved.popFront();
8954     assert(saved.length == 1);
8955     assert(saved.front == 2);
8956 
8957     saved.popBack();
8958     assert(saved.empty);
8959 
8960     auto imm = only!(immutable int, immutable int)(42, 24);
8961     alias Imm = typeof(imm);
8962     static assert(is(ElementType!Imm == immutable(int)));
8963     assert(!imm.empty);
8964     assert(imm.init.empty); // Issue 13441
8965     assert(imm.front == 42);
8966     imm.popFront();
8967     assert(imm.front == 24);
8968     imm.popFront();
8969     assert(imm.empty);
8970 
8971     static struct Test { int* a; }
8972     immutable(Test) test;
8973     cast(void) only(test, test); // Works with mutable indirection
8974 }
8975 
8976 /**
8977 Iterate over `range` with an attached index variable.
8978 
8979 Each element is a $(REF Tuple, std,typecons) containing the index
8980 and the element, in that order, where the index member is named $(D index)
8981 and the element member is named `value`.
8982 
8983 The index starts at `start` and is incremented by one on every iteration.
8984 
8985 Overflow:
8986     If `range` has length, then it is an error to pass a value for `start`
8987     so that `start + range.length` is bigger than `Enumerator.max`, thus
8988     it is ensured that overflow cannot happen.
8989 
8990     If `range` does not have length, and `popFront` is called when
8991     `front.index == Enumerator.max`, the index will overflow and
8992     continue from `Enumerator.min`.
8993 
8994 Params:
8995     range = the input range to attach indexes to
8996     start = the number to start the index counter from
8997 
8998 Returns:
8999     At minimum, an input range. All other range primitives are given in the
9000     resulting range if `range` has them. The exceptions are the bidirectional
9001     primitives, which are propagated only if `range` has length.
9002 
9003 Example:
9004 Useful for using $(D foreach) with an index loop variable:
9005 ----
9006     import std.stdio : stdin, stdout;
9007     import std.range : enumerate;
9008 
9009     foreach (lineNum, line; stdin.byLine().enumerate(1))
9010         stdout.writefln("line #%s: %s", lineNum, line);
9011 ----
9012 */
9013 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
9014 if (isIntegral!Enumerator && isInputRange!Range)
9015 in
9016 {
9017     static if (hasLength!Range)
9018     {
9019         // TODO: core.checkedint supports mixed signedness yet?
9020         import core.checkedint : adds, addu;
9021         import std.conv : ConvException, to;
9022         import std.traits : isSigned, Largest, Signed;
9023 
9024         alias LengthType = typeof(range.length);
9025         bool overflow;
9026         static if (isSigned!Enumerator && isSigned!LengthType)
9027             auto result = adds(start, range.length, overflow);
9028         else static if (isSigned!Enumerator)
9029         {
9030             Largest!(Enumerator, Signed!LengthType) signedLength;
9031             try signedLength = to!(typeof(signedLength))(range.length);
9032             catch (ConvException)
9033                 overflow = true;
9034             catch (Exception)
9035                 assert(false);
9036 
9037             auto result = adds(start, signedLength, overflow);
9038         }
9039         else
9040         {
9041             static if (isSigned!LengthType)
9042                 assert(range.length >= 0);
9043             auto result = addu(start, range.length, overflow);
9044         }
9045 
9046         assert(!overflow && result <= Enumerator.max);
9047     }
9048 }
9049 body
9050 {
9051     // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
9052     static struct Result
9053     {
9054         import std.typecons : Tuple;
9055 
9056         private:
9057         alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
9058         Range range;
9059         Enumerator index;
9060 
9061         public:
frontResult9062         ElemType front() @property
9063         {
9064             assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
9065             return typeof(return)(index, range.front);
9066         }
9067 
9068         static if (isInfinite!Range)
9069             enum bool empty = false;
9070         else
9071         {
emptyResult9072             bool empty() @property
9073             {
9074                 return range.empty;
9075             }
9076         }
9077 
popFrontResult9078         void popFront()
9079         {
9080             assert(!range.empty, "Attempting to popFront an empty enumerate");
9081             range.popFront();
9082             ++index; // When !hasLength!Range, overflow is expected
9083         }
9084 
9085         static if (isForwardRange!Range)
9086         {
saveResult9087             Result save() @property
9088             {
9089                 return typeof(return)(range.save, index);
9090             }
9091         }
9092 
9093         static if (hasLength!Range)
9094         {
lengthResult9095             size_t length() @property
9096             {
9097                 return range.length;
9098             }
9099 
9100             alias opDollar = length;
9101 
9102             static if (isBidirectionalRange!Range)
9103             {
backResult9104                 ElemType back() @property
9105                 {
9106                     assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
9107                     return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
9108                 }
9109 
popBackResult9110                 void popBack()
9111                 {
9112                     assert(!range.empty, "Attempting to popBack an empty enumerate");
9113                     range.popBack();
9114                 }
9115             }
9116         }
9117 
9118         static if (isRandomAccessRange!Range)
9119         {
opIndexResult9120              ElemType opIndex(size_t i)
9121              {
9122                 return typeof(return)(cast(Enumerator)(index + i), range[i]);
9123              }
9124         }
9125 
9126         static if (hasSlicing!Range)
9127         {
9128             static if (hasLength!Range)
9129             {
opSliceResult9130                 Result opSlice(size_t i, size_t j)
9131                 {
9132                     return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
9133                 }
9134             }
9135             else
9136             {
9137                 static struct DollarToken {}
9138                 enum opDollar = DollarToken.init;
9139 
opSliceResult9140                 Result opSlice(size_t i, DollarToken)
9141                 {
9142                     return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
9143                 }
9144 
opSliceResult9145                 auto opSlice(size_t i, size_t j)
9146                 {
9147                     return this[i .. $].takeExactly(j - 1);
9148                 }
9149             }
9150         }
9151     }
9152 
9153     return Result(range, start);
9154 }
9155 
9156 /// Can start enumeration from a negative position:
9157 pure @safe nothrow unittest
9158 {
9159     import std.array : assocArray;
9160     import std.range : enumerate;
9161 
9162     bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
9163     assert(aa[-1]);
9164     assert(aa[0]);
9165     assert(aa[1]);
9166 }
9167 
9168 pure @safe nothrow unittest
9169 {
9170     import std.internal.test.dummyrange : AllDummyRanges;
9171     import std.meta : AliasSeq;
9172     import std.typecons : tuple;
9173 
9174     static struct HasSlicing
9175     {
frontHasSlicing9176         typeof(this) front() @property { return typeof(this).init; }
emptyHasSlicing9177         bool empty() @property { return true; }
popFrontHasSlicing9178         void popFront() {}
9179 
opSliceHasSlicing9180         typeof(this) opSlice(size_t, size_t)
9181         {
9182             return typeof(this)();
9183         }
9184     }
9185 
9186     foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
9187     {
9188         alias R = typeof(enumerate(DummyType.init));
9189         static assert(isInputRange!R);
9190         static assert(isForwardRange!R == isForwardRange!DummyType);
9191         static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
9192         static assert(!hasAssignableElements!R);
9193 
9194         static if (hasLength!DummyType)
9195         {
9196             static assert(hasLength!R);
9197             static assert(isBidirectionalRange!R ==
9198                 isBidirectionalRange!DummyType);
9199         }
9200 
9201         static assert(hasSlicing!R == hasSlicing!DummyType);
9202     }
9203 
9204     static immutable values = ["zero", "one", "two", "three"];
9205     auto enumerated = values[].enumerate();
9206     assert(!enumerated.empty);
9207     assert(enumerated.front == tuple(0, "zero"));
9208     assert(enumerated.back == tuple(3, "three"));
9209 
9210     typeof(enumerated) saved = enumerated.save;
9211     saved.popFront();
9212     assert(enumerated.front == tuple(0, "zero"));
9213     assert(saved.front == tuple(1, "one"));
9214     assert(saved.length == enumerated.length - 1);
9215     saved.popBack();
9216     assert(enumerated.back == tuple(3, "three"));
9217     assert(saved.back == tuple(2, "two"));
9218     saved.popFront();
9219     assert(saved.front == tuple(2, "two"));
9220     assert(saved.back == tuple(2, "two"));
9221     saved.popFront();
9222     assert(saved.empty);
9223 
9224     size_t control = 0;
foreach(i,v;enumerated)9225     foreach (i, v; enumerated)
9226     {
9227         static assert(is(typeof(i) == size_t));
9228         static assert(is(typeof(v) == typeof(values[0])));
9229         assert(i == control);
9230         assert(v == values[i]);
9231         assert(tuple(i, v) == enumerated[i]);
9232         ++control;
9233     }
9234 
9235     assert(enumerated[0 .. $].front == tuple(0, "zero"));
9236     assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
9237 
9238     foreach (i; 0 .. 10)
9239     {
9240         auto shifted = values[0 .. 2].enumerate(i);
9241         assert(shifted.front == tuple(i, "zero"));
9242         assert(shifted[0] == shifted.front);
9243 
9244         auto next = tuple(i + 1, "one");
9245         assert(shifted[1] == next);
9246         shifted.popFront();
9247         assert(shifted.front == next);
9248         shifted.popFront();
9249         assert(shifted.empty);
9250     }
9251 
9252     foreach (T; AliasSeq!(ubyte, byte, uint, int))
9253     {
9254         auto inf = 42.repeat().enumerate(T.max);
9255         alias Inf = typeof(inf);
9256         static assert(isInfinite!Inf);
9257         static assert(hasSlicing!Inf);
9258 
9259         // test overflow
9260         assert(inf.front == tuple(T.max, 42));
9261         inf.popFront();
9262         assert(inf.front == tuple(T.min, 42));
9263 
9264         // test slicing
9265         inf = inf[42 .. $];
9266         assert(inf.front == tuple(T.min + 42, 42));
9267         auto window = inf[0 .. 2];
9268         assert(window.length == 1);
9269         assert(window.front == inf.front);
9270         window.popFront();
9271         assert(window.empty);
9272     }
9273 }
9274 
9275 pure @safe unittest
9276 {
9277     import std.algorithm.comparison : equal;
9278     import std.meta : AliasSeq;
9279     static immutable int[] values = [0, 1, 2, 3, 4];
9280     foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
9281     {
9282         auto enumerated = values.enumerate!T();
9283         static assert(is(typeof(enumerated.front.index) == T));
9284         assert(enumerated.equal(values[].zip(values)));
9285 
9286         foreach (T i; 0 .. 5)
9287         {
9288             auto subset = values[cast(size_t) i .. $];
9289             auto offsetEnumerated = subset.enumerate(i);
9290             static assert(is(typeof(enumerated.front.index) == T));
9291             assert(offsetEnumerated.equal(subset.zip(subset)));
9292         }
9293     }
9294 }
9295 
version(none)9296 version (none) // @@@BUG@@@ 10939
9297 {
9298     // Re-enable (or remove) if 10939 is resolved.
9299     /+pure+/ @safe unittest // Impure because of std.conv.to
9300     {
9301         import core.exception : RangeError;
9302         import std.exception : assertNotThrown, assertThrown;
9303         import std.meta : AliasSeq;
9304 
9305         static immutable values = [42];
9306 
9307         static struct SignedLengthRange
9308         {
9309             immutable(int)[] _values = values;
9310 
9311             int front() @property { assert(false); }
9312             bool empty() @property { assert(false); }
9313             void popFront() { assert(false); }
9314 
9315             int length() @property
9316             {
9317                 return cast(int)_values.length;
9318             }
9319         }
9320 
9321         SignedLengthRange svalues;
9322         foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
9323         {
9324             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
9325             assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
9326             assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
9327 
9328             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
9329             assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
9330             assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
9331         }
9332 
9333         foreach (Enumerator; AliasSeq!(byte, short, int))
9334         {
9335             assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
9336         }
9337 
9338         assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
9339     }
9340 }
9341 
9342 /**
9343   Returns true if $(D fn) accepts variables of type T1 and T2 in any order.
9344   The following code should compile:
9345   ---
9346   T1 foo();
9347   T2 bar();
9348 
9349   fn(foo(), bar());
9350   fn(bar(), foo());
9351   ---
9352 */
isTwoWayCompatible(alias fn,T1,T2)9353 template isTwoWayCompatible(alias fn, T1, T2)
9354 {
9355     enum isTwoWayCompatible = is(typeof( (){
9356             T1 foo();
9357             T2 bar();
9358 
9359             fn(foo(), bar());
9360             fn(bar(), foo());
9361         }
9362     ));
9363 }
9364 
9365 
9366 /**
9367    Policy used with the searching primitives $(D lowerBound), $(D
9368    upperBound), and $(D equalRange) of $(LREF SortedRange) below.
9369  */
9370 enum SearchPolicy
9371 {
9372     /**
9373        Searches in a linear fashion.
9374     */
9375     linear,
9376 
9377     /**
9378        Searches with a step that is grows linearly (1, 2, 3,...)
9379        leading to a quadratic search schedule (indexes tried are 0, 1,
9380        3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
9381        the remaining interval is searched using binary search. The
9382        search is completed in $(BIGOH sqrt(n)) time. Use it when you
9383        are reasonably confident that the value is around the beginning
9384        of the range.
9385     */
9386     trot,
9387 
9388     /**
9389        Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
9390        galloping search algorithm), i.e. searches
9391        with a step that doubles every time, (1, 2, 4, 8, ...)  leading
9392        to an exponential search schedule (indexes tried are 0, 1, 3,
9393        7, 15, 31, 63,...) Once the search overshoots its target, the
9394        remaining interval is searched using binary search. A value is
9395        found in $(BIGOH log(n)) time.
9396     */
9397         gallop,
9398 
9399     /**
9400        Searches using a classic interval halving policy. The search
9401        starts in the middle of the range, and each search step cuts
9402        the range in half. This policy finds a value in $(BIGOH log(n))
9403        time but is less cache friendly than $(D gallop) for large
9404        ranges. The $(D binarySearch) policy is used as the last step
9405        of $(D trot), $(D gallop), $(D trotBackwards), and $(D
9406        gallopBackwards) strategies.
9407     */
9408         binarySearch,
9409 
9410     /**
9411        Similar to $(D trot) but starts backwards. Use it when
9412        confident that the value is around the end of the range.
9413     */
9414         trotBackwards,
9415 
9416     /**
9417        Similar to $(D gallop) but starts backwards. Use it when
9418        confident that the value is around the end of the range.
9419     */
9420         gallopBackwards
9421         }
9422 
9423 /**
9424 Represents a sorted range. In addition to the regular range
9425 primitives, supports additional operations that take advantage of the
9426 ordering, such as merge and binary search. To obtain a $(D
9427 SortedRange) from an unsorted range $(D r), use
9428 $(REF sort, std,algorithm,sorting) which sorts $(D r) in place and returns the
9429 corresponding $(D SortedRange). To construct a $(D SortedRange) from a range
9430 $(D r) that is known to be already sorted, use $(LREF assumeSorted) described
9431 below.
9432 */
9433 struct SortedRange(Range, alias pred = "a < b")
9434 if (isInputRange!Range)
9435 {
9436     import std.functional : binaryFun;
9437 
9438     private alias predFun = binaryFun!pred;
geq(L,R)9439     private bool geq(L, R)(L lhs, R rhs)
9440     {
9441         return !predFun(lhs, rhs);
9442     }
gt(L,R)9443     private bool gt(L, R)(L lhs, R rhs)
9444     {
9445         return predFun(rhs, lhs);
9446     }
9447     private Range _input;
9448 
9449     // Undocummented because a clearer way to invoke is by calling
9450     // assumeSorted.
this(Range input)9451     this(Range input)
9452     out
9453     {
9454         // moved out of the body as a workaround for Issue 12661
9455         dbgVerifySorted();
9456     }
9457     body
9458     {
9459         this._input = input;
9460     }
9461 
9462     // Assertion only.
dbgVerifySorted()9463     private void dbgVerifySorted()
9464     {
9465         if (!__ctfe)
9466         debug
9467         {
9468             static if (isRandomAccessRange!Range && hasLength!Range)
9469             {
9470                 import core.bitop : bsr;
9471                 import std.algorithm.sorting : isSorted;
9472 
9473                 // Check the sortedness of the input
9474                 if (this._input.length < 2) return;
9475 
9476                 immutable size_t msb = bsr(this._input.length) + 1;
9477                 assert(msb > 0 && msb <= this._input.length);
9478                 immutable step = this._input.length / msb;
9479                 auto st = stride(this._input, step);
9480 
9481                 assert(isSorted!pred(st), "Range is not sorted");
9482             }
9483         }
9484     }
9485 
9486     /// Range primitives.
empty()9487     @property bool empty()             //const
9488     {
9489         return this._input.empty;
9490     }
9491 
9492     /// Ditto
9493     static if (isForwardRange!Range)
save()9494     @property auto save()
9495     {
9496         // Avoid the constructor
9497         typeof(this) result = this;
9498         result._input = _input.save;
9499         return result;
9500     }
9501 
9502     /// Ditto
front()9503     @property auto ref front()
9504     {
9505         return _input.front;
9506     }
9507 
9508     /// Ditto
popFront()9509     void popFront()
9510     {
9511         _input.popFront();
9512     }
9513 
9514     /// Ditto
9515     static if (isBidirectionalRange!Range)
9516     {
back()9517         @property auto ref back()
9518         {
9519             return _input.back;
9520         }
9521 
9522         /// Ditto
popBack()9523         void popBack()
9524         {
9525             _input.popBack();
9526         }
9527     }
9528 
9529     /// Ditto
9530     static if (isRandomAccessRange!Range)
opIndex(size_t i)9531         auto ref opIndex(size_t i)
9532         {
9533             return _input[i];
9534         }
9535 
9536     /// Ditto
9537     static if (hasSlicing!Range)
opSlice(size_t a,size_t b)9538         auto opSlice(size_t a, size_t b)
9539         {
9540             assert(
9541                 a <= b,
9542                 "Attempting to slice a SortedRange with a larger first argument than the second."
9543             );
9544             typeof(this) result = this;
9545             result._input = _input[a .. b];// skip checking
9546             return result;
9547         }
9548 
9549     /// Ditto
9550     static if (hasLength!Range)
9551     {
length()9552         @property size_t length()          //const
9553         {
9554             return _input.length;
9555         }
9556         alias opDollar = length;
9557     }
9558 
9559 /**
9560    Releases the controlled range and returns it.
9561 */
release()9562     auto release()
9563     {
9564         import std.algorithm.mutation : move;
9565         return move(_input);
9566     }
9567 
9568     // Assuming a predicate "test" that returns 0 for a left portion
9569     // of the range and then 1 for the rest, returns the index at
9570     // which the first 1 appears. Used internally by the search routines.
9571     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
9572     if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
9573     {
9574         size_t first = 0, count = _input.length;
9575         while (count > 0)
9576         {
9577             immutable step = count / 2, it = first + step;
9578             if (!test(_input[it], v))
9579             {
9580                 first = it + 1;
9581                 count -= step + 1;
9582             }
9583             else
9584             {
9585                 count = step;
9586             }
9587         }
9588         return first;
9589     }
9590 
9591     // Specialization for trot and gallop
9592     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
9593     if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
9594         && isRandomAccessRange!Range)
9595     {
9596         if (empty || test(front, v)) return 0;
9597         immutable count = length;
9598         if (count == 1) return 1;
9599         size_t below = 0, above = 1, step = 2;
9600         while (!test(_input[above], v))
9601         {
9602             // Still too small, update below and increase gait
9603             below = above;
9604             immutable next = above + step;
9605             if (next >= count)
9606             {
9607                 // Overshot - the next step took us beyond the end. So
9608                 // now adjust next and simply exit the loop to do the
9609                 // binary search thingie.
9610                 above = count;
9611                 break;
9612             }
9613             // Still in business, increase step and continue
9614             above = next;
9615             static if (sp == SearchPolicy.trot)
9616                 ++step;
9617             else
9618                 step <<= 1;
9619         }
9620         return below + this[below .. above].getTransitionIndex!(
9621             SearchPolicy.binarySearch, test, V)(v);
9622     }
9623 
9624     // Specialization for trotBackwards and gallopBackwards
9625     private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
9626     if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
9627         && isRandomAccessRange!Range)
9628     {
9629         immutable count = length;
9630         if (empty || !test(back, v)) return count;
9631         if (count == 1) return 0;
9632         size_t below = count - 2, above = count - 1, step = 2;
9633         while (test(_input[below], v))
9634         {
9635             // Still too large, update above and increase gait
9636             above = below;
9637             if (below < step)
9638             {
9639                 // Overshot - the next step took us beyond the end. So
9640                 // now adjust next and simply fall through to do the
9641                 // binary search thingie.
9642                 below = 0;
9643                 break;
9644             }
9645             // Still in business, increase step and continue
9646             below -= step;
9647             static if (sp == SearchPolicy.trot)
9648                 ++step;
9649             else
9650                 step <<= 1;
9651         }
9652         return below + this[below .. above].getTransitionIndex!(
9653             SearchPolicy.binarySearch, test, V)(v);
9654     }
9655 
9656 // lowerBound
9657 /**
9658    This function uses a search with policy $(D sp) to find the
9659    largest left subrange on which $(D pred(x, value)) is $(D true) for
9660    all $(D x) (e.g., if $(D pred) is "less than", returns the portion of
9661    the range with elements strictly smaller than $(D value)). The search
9662    schedule and its complexity are documented in
9663    $(LREF SearchPolicy).  See also STL's
9664    $(HTTP sgi.com/tech/stl/lower_bound.html, lower_bound).
9665 */
9666     auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
9667     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
9668          && hasSlicing!Range)
9669     {
9670         return this[0 .. getTransitionIndex!(sp, geq)(value)];
9671     }
9672 
9673     ///
9674     @safe unittest
9675     {
9676         import std.algorithm.comparison : equal;
9677         auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
9678         auto p = a.lowerBound(4);
9679         assert(equal(p, [ 0, 1, 2, 3 ]));
9680     }
9681 
9682 // upperBound
9683 /**
9684 This function searches with policy $(D sp) to find the largest right
9685 subrange on which $(D pred(value, x)) is $(D true) for all $(D x)
9686 (e.g., if $(D pred) is "less than", returns the portion of the range
9687 with elements strictly greater than $(D value)). The search schedule
9688 and its complexity are documented in $(LREF SearchPolicy).
9689 
9690 For ranges that do not offer random access, $(D SearchPolicy.linear)
9691 is the only policy allowed (and it must be specified explicitly lest it exposes
9692 user code to unexpected inefficiencies). For random-access searches, all
9693 policies are allowed, and $(D SearchPolicy.binarySearch) is the default.
9694 
9695 See_Also: STL's $(HTTP sgi.com/tech/stl/lower_bound.html,upper_bound).
9696 */
9697     auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
9698     if (isTwoWayCompatible!(predFun, ElementType!Range, V))
9699     {
9700         static assert(hasSlicing!Range || sp == SearchPolicy.linear,
9701             "Specify SearchPolicy.linear explicitly for "
9702             ~ typeof(this).stringof);
9703         static if (sp == SearchPolicy.linear)
9704         {
9705             for (; !_input.empty && !predFun(value, _input.front);
9706                  _input.popFront())
9707             {
9708             }
9709             return this;
9710         }
9711         else
9712         {
9713             return this[getTransitionIndex!(sp, gt)(value) .. length];
9714         }
9715     }
9716 
9717     ///
9718     @safe unittest
9719     {
9720         import std.algorithm.comparison : equal;
9721         auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
9722         auto p = a.upperBound(3);
9723         assert(equal(p, [4, 4, 5, 6]));
9724     }
9725 
9726 
9727 // equalRange
9728 /**
9729    Returns the subrange containing all elements $(D e) for which both $(D
9730    pred(e, value)) and $(D pred(value, e)) evaluate to $(D false) (e.g.,
9731    if $(D pred) is "less than", returns the portion of the range with
9732    elements equal to $(D value)). Uses a classic binary search with
9733    interval halving until it finds a value that satisfies the condition,
9734    then uses $(D SearchPolicy.gallopBackwards) to find the left boundary
9735    and $(D SearchPolicy.gallop) to find the right boundary. These
9736    policies are justified by the fact that the two boundaries are likely
9737    to be near the first found value (i.e., equal ranges are relatively
9738    small). Completes the entire search in $(BIGOH log(n)) time. See also
9739    STL's $(HTTP sgi.com/tech/stl/equal_range.html, equal_range).
9740 */
9741     auto equalRange(V)(V value)
9742     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
9743         && isRandomAccessRange!Range)
9744     {
9745         size_t first = 0, count = _input.length;
9746         while (count > 0)
9747         {
9748             immutable step = count / 2;
9749             auto it = first + step;
9750             if (predFun(_input[it], value))
9751             {
9752                 // Less than value, bump left bound up
9753                 first = it + 1;
9754                 count -= step + 1;
9755             }
9756             else if (predFun(value, _input[it]))
9757             {
9758                 // Greater than value, chop count
9759                 count = step;
9760             }
9761             else
9762             {
9763                 // Equal to value, do binary searches in the
9764                 // leftover portions
9765                 // Gallop towards the left end as it's likely nearby
9766                 immutable left = first
9767                     + this[first .. it]
9768                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
9769                 first += count;
9770                 // Gallop towards the right end as it's likely nearby
9771                 immutable right = first
9772                     - this[it + 1 .. first]
9773                     .upperBound!(SearchPolicy.gallop)(value).length;
9774                 return this[left .. right];
9775             }
9776         }
9777         return this.init;
9778     }
9779 
9780     ///
9781     @safe unittest
9782     {
9783         import std.algorithm.comparison : equal;
9784         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
9785         auto r = a.assumeSorted.equalRange(3);
9786         assert(equal(r, [ 3, 3, 3 ]));
9787     }
9788 
9789 // trisect
9790 /**
9791 Returns a tuple $(D r) such that $(D r[0]) is the same as the result
9792 of $(D lowerBound(value)), $(D r[1]) is the same as the result of $(D
9793 equalRange(value)), and $(D r[2]) is the same as the result of $(D
9794 upperBound(value)). The call is faster than computing all three
9795 separately. Uses a search schedule similar to $(D
9796 equalRange). Completes the entire search in $(BIGOH log(n)) time.
9797 */
9798     auto trisect(V)(V value)
9799     if (isTwoWayCompatible!(predFun, ElementType!Range, V)
9800         && isRandomAccessRange!Range && hasLength!Range)
9801     {
9802         import std.typecons : tuple;
9803         size_t first = 0, count = _input.length;
9804         while (count > 0)
9805         {
9806             immutable step = count / 2;
9807             auto it = first + step;
9808             if (predFun(_input[it], value))
9809             {
9810                 // Less than value, bump left bound up
9811                 first = it + 1;
9812                 count -= step + 1;
9813             }
9814             else if (predFun(value, _input[it]))
9815             {
9816                 // Greater than value, chop count
9817                 count = step;
9818             }
9819             else
9820             {
9821                 // Equal to value, do binary searches in the
9822                 // leftover portions
9823                 // Gallop towards the left end as it's likely nearby
9824                 immutable left = first
9825                     + this[first .. it]
9826                     .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
9827                 first += count;
9828                 // Gallop towards the right end as it's likely nearby
9829                 immutable right = first
9830                     - this[it + 1 .. first]
9831                     .upperBound!(SearchPolicy.gallop)(value).length;
9832                 return tuple(this[0 .. left], this[left .. right],
9833                         this[right .. length]);
9834             }
9835         }
9836         // No equal element was found
9837         return tuple(this[0 .. first], this.init, this[first .. length]);
9838     }
9839 
9840     ///
9841     @safe unittest
9842     {
9843         import std.algorithm.comparison : equal;
9844         auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
9845         auto r = assumeSorted(a).trisect(3);
9846         assert(equal(r[0], [ 1, 2 ]));
9847         assert(equal(r[1], [ 3, 3, 3 ]));
9848         assert(equal(r[2], [ 4, 4, 5, 6 ]));
9849     }
9850 
9851 // contains
9852 /**
9853 Returns $(D true) if and only if $(D value) can be found in $(D
9854 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
9855 evaluations of $(D pred). See also STL's $(HTTP
9856 sgi.com/tech/stl/binary_search.html, binary_search).
9857  */
9858 
9859     bool contains(V)(V value)
9860     if (isRandomAccessRange!Range)
9861     {
9862         if (empty) return false;
9863         immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
9864         if (i >= length) return false;
9865         return !predFun(value, _input[i]);
9866     }
9867 
9868 // groupBy
9869 /**
9870 Returns a range of subranges of elements that are equivalent according to the
9871 sorting relation.
9872  */
groupBy()9873     auto groupBy()()
9874     {
9875         import std.algorithm.iteration : chunkBy;
9876         return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
9877     }
9878 }
9879 
9880 ///
9881 @safe unittest
9882 {
9883     import std.algorithm.sorting : sort;
9884     auto a = [ 1, 2, 3, 42, 52, 64 ];
9885     auto r = assumeSorted(a);
9886     assert(r.contains(3));
9887     assert(!r.contains(32));
9888     auto r1 = sort!"a > b"(a);
9889     assert(r1.contains(3));
9890     assert(!r1.contains(32));
9891     assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
9892 }
9893 
9894 /**
9895 $(D SortedRange) could accept ranges weaker than random-access, but it
9896 is unable to provide interesting functionality for them. Therefore,
9897 $(D SortedRange) is currently restricted to random-access ranges.
9898 
9899 No copy of the original range is ever made. If the underlying range is
9900 changed concurrently with its corresponding $(D SortedRange) in ways
9901 that break its sorted-ness, $(D SortedRange) will work erratically.
9902 */
9903 @safe unittest
9904 {
9905     import std.algorithm.mutation : swap;
9906     auto a = [ 1, 2, 3, 42, 52, 64 ];
9907     auto r = assumeSorted(a);
9908     assert(r.contains(42));
9909     swap(a[3], a[5]);         // illegal to break sortedness of original range
9910     assert(!r.contains(42));  // passes although it shouldn't
9911 }
9912 
9913 @safe unittest
9914 {
9915     import std.algorithm.comparison : equal;
9916 
9917     auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
9918     auto r = assumeSorted(a).trisect(30);
9919     assert(equal(r[0], [ 10, 20 ]));
9920     assert(equal(r[1], [ 30, 30, 30 ]));
9921     assert(equal(r[2], [ 40, 40, 50, 60 ]));
9922 
9923     r = assumeSorted(a).trisect(35);
9924     assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
9925     assert(r[1].empty);
9926     assert(equal(r[2], [ 40, 40, 50, 60 ]));
9927 }
9928 
9929 @safe unittest
9930 {
9931     import std.algorithm.comparison : equal;
9932     auto a = [ "A", "AG", "B", "E", "F" ];
9933     auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
9934     assert(equal(r[0], [ "A", "AG" ]));
9935     assert(equal(r[1], [ "B" ]));
9936     assert(equal(r[2], [ "E", "F" ]));
9937     r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
9938     assert(r[0].empty);
9939     assert(equal(r[1], [ "A" ]));
9940     assert(equal(r[2], [ "AG", "B", "E", "F" ]));
9941 }
9942 
9943 @safe unittest
9944 {
9945     import std.algorithm.comparison : equal;
test(SearchPolicy pol)9946     static void test(SearchPolicy pol)()
9947     {
9948         auto a = [ 1, 2, 3, 42, 52, 64 ];
9949         auto r = assumeSorted(a);
9950         assert(equal(r.lowerBound(42), [1, 2, 3]));
9951 
9952         assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
9953         assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
9954         assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
9955         assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
9956         assert(equal(r.lowerBound!(pol)(3), [1, 2]));
9957         assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
9958         assert(equal(r.lowerBound!(pol)(420), a));
9959         assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
9960 
9961         assert(equal(r.upperBound!(pol)(42), [52, 64]));
9962         assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
9963         assert(equal(r.upperBound!(pol)(43), [52, 64]));
9964         assert(equal(r.upperBound!(pol)(51), [52, 64]));
9965         assert(equal(r.upperBound!(pol)(53), [64]));
9966         assert(equal(r.upperBound!(pol)(55), [64]));
9967         assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
9968         assert(equal(r.upperBound!(pol)(0), a));
9969     }
9970 
9971     test!(SearchPolicy.trot)();
9972     test!(SearchPolicy.gallop)();
9973     test!(SearchPolicy.trotBackwards)();
9974     test!(SearchPolicy.gallopBackwards)();
9975     test!(SearchPolicy.binarySearch)();
9976 }
9977 
9978 @safe unittest
9979 {
9980     // Check for small arrays
9981     int[] a;
9982     auto r = assumeSorted(a);
9983     a = [ 1 ];
9984     r = assumeSorted(a);
9985     a = [ 1, 2 ];
9986     r = assumeSorted(a);
9987     a = [ 1, 2, 3 ];
9988     r = assumeSorted(a);
9989 }
9990 
9991 @safe unittest
9992 {
9993     import std.algorithm.mutation : swap;
9994     auto a = [ 1, 2, 3, 42, 52, 64 ];
9995     auto r = assumeSorted(a);
9996     assert(r.contains(42));
9997     swap(a[3], a[5]);                  // illegal to break sortedness of original range
9998     assert(!r.contains(42));            // passes although it shouldn't
9999 }
10000 
10001 @safe unittest
10002 {
10003     immutable(int)[] arr = [ 1, 2, 3 ];
10004     auto s = assumeSorted(arr);
10005 }
10006 
10007 @system unittest
10008 {
10009     import std.algorithm.comparison : equal;
10010     int[] arr = [100, 101, 102, 200, 201, 300];
10011     auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
10012     assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
10013 }
10014 
10015 // Test on an input range
10016 @system unittest
10017 {
10018     import std.conv : text;
10019     import std.file : exists, remove, tempDir;
10020     import std.path : buildPath;
10021     import std.stdio : File;
10022     import std.uuid : randomUUID;
10023     auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
10024                           "." ~ randomUUID().toString());
10025     auto f = File(name, "w");
10026     scope(exit) if (exists(name)) remove(name);
10027     // write a sorted range of lines to the file
10028     f.write("abc\ndef\nghi\njkl");
10029     f.close();
10030     f.open(name, "r");
10031     auto r = assumeSorted(f.byLine());
10032     auto r1 = r.upperBound!(SearchPolicy.linear)("def");
10033     assert(r1.front == "ghi", r1.front);
10034     f.close();
10035 }
10036 
10037 /**
10038 Assumes $(D r) is sorted by predicate $(D pred) and returns the
10039 corresponding $(D SortedRange!(pred, R)) having $(D r) as support. To
10040 keep the checking costs low, the cost is $(BIGOH 1) in release mode
10041 (no checks for sorted-ness are performed). In debug mode, a few random
10042 elements of $(D r) are checked for sorted-ness. The size of the sample
10043 is proportional $(BIGOH log(r.length)). That way, checking has no
10044 effect on the complexity of subsequent operations specific to sorted
10045 ranges (such as binary search). The probability of an arbitrary
10046 unsorted range failing the test is very high (however, an
10047 almost-sorted range is likely to pass it). To check for sorted-ness at
10048 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
10049  */
10050 auto assumeSorted(alias pred = "a < b", R)(R r)
10051 if (isInputRange!(Unqual!R))
10052 {
10053     return SortedRange!(Unqual!R, pred)(r);
10054 }
10055 
10056 @safe unittest
10057 {
10058     import std.algorithm.comparison : equal;
10059     static assert(isRandomAccessRange!(SortedRange!(int[])));
10060     int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
10061     auto p = assumeSorted(a).lowerBound(4);
10062     assert(equal(p, [0, 1, 2, 3]));
10063     p = assumeSorted(a).lowerBound(5);
10064     assert(equal(p, [0, 1, 2, 3, 4]));
10065     p = assumeSorted(a).lowerBound(6);
10066     assert(equal(p, [ 0, 1, 2, 3, 4, 5]));
10067     p = assumeSorted(a).lowerBound(6.9);
10068     assert(equal(p, [ 0, 1, 2, 3, 4, 5, 6]));
10069 }
10070 
10071 @safe unittest
10072 {
10073     import std.algorithm.comparison : equal;
10074     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
10075     auto p = assumeSorted(a).upperBound(3);
10076     assert(equal(p, [4, 4, 5, 6 ]));
10077     p = assumeSorted(a).upperBound(4.2);
10078     assert(equal(p, [ 5, 6 ]));
10079 }
10080 
10081 @safe unittest
10082 {
10083     import std.algorithm.comparison : equal;
10084     import std.conv : text;
10085 
10086     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
10087     auto p = assumeSorted(a).equalRange(3);
10088     assert(equal(p, [ 3, 3, 3 ]), text(p));
10089     p = assumeSorted(a).equalRange(4);
10090     assert(equal(p, [ 4, 4 ]), text(p));
10091     p = assumeSorted(a).equalRange(2);
10092     assert(equal(p, [ 2 ]));
10093     p = assumeSorted(a).equalRange(0);
10094     assert(p.empty);
10095     p = assumeSorted(a).equalRange(7);
10096     assert(p.empty);
10097     p = assumeSorted(a).equalRange(3.0);
10098     assert(equal(p, [ 3, 3, 3]));
10099 }
10100 
10101 @safe unittest
10102 {
10103     int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
10104     if (a.length)
10105     {
10106         auto b = a[a.length / 2];
10107         //auto r = sort(a);
10108         //assert(r.contains(b));
10109     }
10110 }
10111 
10112 @safe unittest
10113 {
10114     auto a = [ 5, 7, 34, 345, 677 ];
10115     auto r = assumeSorted(a);
10116     a = null;
10117     r = assumeSorted(a);
10118     a = [ 1 ];
10119     r = assumeSorted(a);
10120 }
10121 
10122 @system unittest
10123 {
10124     bool ok = true;
10125     try
10126     {
10127         auto r2 = assumeSorted([ 677, 345, 34, 7, 5 ]);
10128         debug ok = false;
10129     }
catch(Throwable)10130     catch (Throwable)
10131     {
10132     }
10133     assert(ok);
10134 }
10135 
10136 // issue 15003
10137 @nogc @safe unittest
10138 {
10139     static immutable a = [1, 2, 3, 4];
10140     auto r = a.assumeSorted;
10141 }
10142 
10143 /++
10144     Wrapper which effectively makes it possible to pass a range by reference.
10145     Both the original range and the RefRange will always have the exact same
10146     elements. Any operation done on one will affect the other. So, for instance,
10147     if it's passed to a function which would implicitly copy the original range
10148     if it were passed to it, the original range is $(I not) copied but is
10149     consumed as if it were a reference type.
10150 
10151     Note:
10152         `save` works as normal and operates on a new _range, so if
10153         `save` is ever called on the `RefRange`, then no operations on the
10154         saved _range will affect the original.
10155 
10156     Params:
10157         range = the range to construct the `RefRange` from
10158 
10159     Returns:
10160         A `RefRange`. If the given _range is a class type
10161         (and thus is already a reference type), then the original
10162         range is returned rather than a `RefRange`.
10163   +/
10164 struct RefRange(R)
10165 if (isInputRange!R)
10166 {
10167 public:
10168 
10169     /++ +/
this(R * range)10170     this(R* range) @safe pure nothrow
10171     {
10172         _range = range;
10173     }
10174 
10175 
10176     /++
10177         This does not assign the pointer of $(D rhs) to this $(D RefRange).
10178         Rather it assigns the range pointed to by $(D rhs) to the range pointed
10179         to by this $(D RefRange). This is because $(I any) operation on a
10180         $(D RefRange) is the same is if it occurred to the original range. The
10181         one exception is when a $(D RefRange) is assigned $(D null) either
10182         directly or because $(D rhs) is $(D null). In that case, $(D RefRange)
10183         no longer refers to the original range but is $(D null).
10184       +/
10185     auto opAssign(RefRange rhs)
10186     {
10187         if (_range && rhs._range)
10188             *_range = *rhs._range;
10189         else
10190             _range = rhs._range;
10191 
10192         return this;
10193     }
10194 
10195     /++ +/
10196     void opAssign(typeof(null) rhs)
10197     {
10198         _range = null;
10199     }
10200 
10201 
10202     /++
10203         A pointer to the wrapped range.
10204       +/
10205     @property inout(R*) ptr() @safe inout pure nothrow
10206     {
10207         return _range;
10208     }
10209 
10210 
10211     version (StdDdoc)
10212     {
10213         /++ +/
10214         @property auto front() {assert(0);}
10215         /++ Ditto +/
10216         @property auto front() const {assert(0);}
10217         /++ Ditto +/
10218         @property auto front(ElementType!R value) {assert(0);}
10219     }
10220     else
10221     {
10222         @property auto front()
10223         {
10224             return (*_range).front;
10225         }
10226 
10227         static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
10228         {
10229             return (*_range).front;
10230         }
10231 
10232         static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
10233         {
10234             return (*_range).front = value;
10235         }
10236     }
10237 
10238 
10239     version (StdDdoc)
10240     {
10241         @property bool empty(); ///
10242         @property bool empty() const; ///Ditto
10243     }
10244     else static if (isInfinite!R)
10245         enum empty = false;
10246     else
10247     {
10248         @property bool empty()
10249         {
10250             return (*_range).empty;
10251         }
10252 
10253         static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
10254         {
10255             return (*_range).empty;
10256         }
10257     }
10258 
10259 
10260     /++ +/
10261     void popFront()
10262     {
10263         return (*_range).popFront();
10264     }
10265 
10266 
10267     version (StdDdoc)
10268     {
10269         /++
10270             Only defined if $(D isForwardRange!R) is $(D true).
10271           +/
10272         @property auto save() {assert(0);}
10273         /++ Ditto +/
10274         @property auto save() const {assert(0);}
10275         /++ Ditto +/
10276         auto opSlice() {assert(0);}
10277         /++ Ditto +/
10278         auto opSlice() const {assert(0);}
10279     }
10280     else static if (isForwardRange!R)
10281     {
10282         import std.traits : isSafe;
10283         private alias S = typeof((*_range).save);
10284 
10285         static if (is(typeof((*cast(const R*)_range).save)))
10286             private alias CS = typeof((*cast(const R*)_range).save);
10287 
10288         static if (isSafe!((R* r) => (*r).save))
10289         {
10290             @property RefRange!S save() @trusted
10291             {
10292                 mixin(_genSave());
10293             }
10294 
10295             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
10296             {
10297                 mixin(_genSave());
10298             }
10299         }
10300         else
10301         {
10302             @property RefRange!S save()
10303             {
10304                 mixin(_genSave());
10305             }
10306 
10307             static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
10308             {
10309                 mixin(_genSave());
10310             }
10311         }
10312 
10313         auto opSlice()()
10314         {
10315             return save;
10316         }
10317 
10318         auto opSlice()() const
10319         {
10320             return save;
10321         }
10322 
10323         private static string _genSave() @safe pure nothrow
10324         {
10325             return `import std.conv : emplace;` ~
10326                    `alias S = typeof((*_range).save);` ~
10327                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
10328                    `auto mem = new void[S.sizeof];` ~
10329                    `emplace!S(mem, cast(S)(*_range).save);` ~
10330                    `return RefRange!S(cast(S*) mem.ptr);`;
10331         }
10332 
10333         static assert(isForwardRange!RefRange);
10334     }
10335 
10336 
10337     version (StdDdoc)
10338     {
10339         /++
10340             Only defined if $(D isBidirectionalRange!R) is $(D true).
10341           +/
10342         @property auto back() {assert(0);}
10343         /++ Ditto +/
10344         @property auto back() const {assert(0);}
10345         /++ Ditto +/
10346         @property auto back(ElementType!R value) {assert(0);}
10347     }
10348     else static if (isBidirectionalRange!R)
10349     {
10350         @property auto back()
10351         {
10352             return (*_range).back;
10353         }
10354 
10355         static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
10356         {
10357             return (*_range).back;
10358         }
10359 
10360         static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
10361         {
10362             return (*_range).back = value;
10363         }
10364     }
10365 
10366 
10367     /++ Ditto +/
10368     static if (isBidirectionalRange!R) void popBack()
10369     {
10370         return (*_range).popBack();
10371     }
10372 
10373 
10374     version (StdDdoc)
10375     {
10376         /++
10377             Only defined if $(D isRandomAccesRange!R) is $(D true).
10378           +/
10379         auto ref opIndex(IndexType)(IndexType index) {assert(0);}
10380 
10381         /++ Ditto +/
10382         auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
10383     }
10384     else static if (isRandomAccessRange!R)
10385     {
10386         auto ref opIndex(IndexType)(IndexType index)
10387             if (is(typeof((*_range)[index])))
10388         {
10389             return (*_range)[index];
10390         }
10391 
10392         auto ref opIndex(IndexType)(IndexType index) const
10393             if (is(typeof((*cast(const R*)_range)[index])))
10394         {
10395             return (*_range)[index];
10396         }
10397     }
10398 
10399 
10400     /++
10401         Only defined if $(D hasMobileElements!R) and $(D isForwardRange!R) are
10402         $(D true).
10403       +/
10404     static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
10405     {
10406         return (*_range).moveFront();
10407     }
10408 
10409 
10410     /++
10411         Only defined if $(D hasMobileElements!R) and $(D isBidirectionalRange!R)
10412         are $(D true).
10413       +/
10414     static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
10415     {
10416         return (*_range).moveBack();
10417     }
10418 
10419 
10420     /++
10421         Only defined if $(D hasMobileElements!R) and $(D isRandomAccessRange!R)
10422         are $(D true).
10423       +/
10424     static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
10425     {
10426         return (*_range).moveAt(index);
10427     }
10428 
10429 
10430     version (StdDdoc)
10431     {
10432         /++
10433             Only defined if $(D hasLength!R) is $(D true).
10434           +/
10435         @property auto length() {assert(0);}
10436 
10437         /++ Ditto +/
10438         @property auto length() const {assert(0);}
10439 
10440         /++ Ditto +/
10441         alias opDollar = length;
10442     }
10443     else static if (hasLength!R)
10444     {
10445         @property auto length()
10446         {
10447             return (*_range).length;
10448         }
10449 
10450         static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
10451         {
10452             return (*_range).length;
10453         }
10454 
10455         alias opDollar = length;
10456     }
10457 
10458 
10459     version (StdDdoc)
10460     {
10461         /++
10462             Only defined if $(D hasSlicing!R) is $(D true).
10463           +/
10464         auto opSlice(IndexType1, IndexType2)
10465                     (IndexType1 begin, IndexType2 end) {assert(0);}
10466 
10467         /++ Ditto +/
10468         auto opSlice(IndexType1, IndexType2)
10469                     (IndexType1 begin, IndexType2 end) const {assert(0);}
10470     }
10471     else static if (hasSlicing!R)
10472     {
10473         private alias T = typeof((*_range)[1 .. 2]);
10474         static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
10475         {
10476             private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
10477         }
10478 
10479         RefRange!T opSlice(IndexType1, IndexType2)
10480                     (IndexType1 begin, IndexType2 end)
10481             if (is(typeof((*_range)[begin .. end])))
10482         {
10483             mixin(_genOpSlice());
10484         }
10485 
10486         RefRange!CT opSlice(IndexType1, IndexType2)
10487                     (IndexType1 begin, IndexType2 end) const
10488             if (is(typeof((*cast(const R*)_range)[begin .. end])))
10489         {
10490             mixin(_genOpSlice());
10491         }
10492 
10493         private static string _genOpSlice() @safe pure nothrow
10494         {
10495             return `import std.conv : emplace;` ~
10496                    `alias S = typeof((*_range)[begin .. end]);` ~
10497                    `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
10498                    `auto mem = new void[S.sizeof];` ~
10499                    `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
10500                    `return RefRange!S(cast(S*) mem.ptr);`;
10501         }
10502     }
10503 
10504 
10505 private:
10506 
10507     R* _range;
10508 }
10509 
10510 /// Basic Example
10511 @system unittest
10512 {
10513     import std.algorithm.searching : find;
10514     ubyte[] buffer = [1, 9, 45, 12, 22];
10515     auto found1 = find(buffer, 45);
10516     assert(found1 == [45, 12, 22]);
10517     assert(buffer == [1, 9, 45, 12, 22]);
10518 
10519     auto wrapped1 = refRange(&buffer);
10520     auto found2 = find(wrapped1, 45);
10521     assert(*found2.ptr == [45, 12, 22]);
10522     assert(buffer == [45, 12, 22]);
10523 
10524     auto found3 = find(wrapped1.save, 22);
10525     assert(*found3.ptr == [22]);
10526     assert(buffer == [45, 12, 22]);
10527 
10528     string str = "hello world";
10529     auto wrappedStr = refRange(&str);
10530     assert(str.front == 'h');
10531     str.popFrontN(5);
10532     assert(str == " world");
10533     assert(wrappedStr.front == ' ');
10534     assert(*wrappedStr.ptr == " world");
10535 }
10536 
10537 /// opAssign Example.
10538 @system unittest
10539 {
10540     ubyte[] buffer1 = [1, 2, 3, 4, 5];
10541     ubyte[] buffer2 = [6, 7, 8, 9, 10];
10542     auto wrapped1 = refRange(&buffer1);
10543     auto wrapped2 = refRange(&buffer2);
10544     assert(wrapped1.ptr is &buffer1);
10545     assert(wrapped2.ptr is &buffer2);
10546     assert(wrapped1.ptr !is wrapped2.ptr);
10547     assert(buffer1 != buffer2);
10548 
10549     wrapped1 = wrapped2;
10550 
10551     //Everything points to the same stuff as before.
10552     assert(wrapped1.ptr is &buffer1);
10553     assert(wrapped2.ptr is &buffer2);
10554     assert(wrapped1.ptr !is wrapped2.ptr);
10555 
10556     //But buffer1 has changed due to the assignment.
10557     assert(buffer1 == [6, 7, 8, 9, 10]);
10558     assert(buffer2 == [6, 7, 8, 9, 10]);
10559 
10560     buffer2 = [11, 12, 13, 14, 15];
10561 
10562     //Everything points to the same stuff as before.
10563     assert(wrapped1.ptr is &buffer1);
10564     assert(wrapped2.ptr is &buffer2);
10565     assert(wrapped1.ptr !is wrapped2.ptr);
10566 
10567     //But buffer2 has changed due to the assignment.
10568     assert(buffer1 == [6, 7, 8, 9, 10]);
10569     assert(buffer2 == [11, 12, 13, 14, 15]);
10570 
10571     wrapped2 = null;
10572 
10573     //The pointer changed for wrapped2 but not wrapped1.
10574     assert(wrapped1.ptr is &buffer1);
10575     assert(wrapped2.ptr is null);
10576     assert(wrapped1.ptr !is wrapped2.ptr);
10577 
10578     //buffer2 is not affected by the assignment.
10579     assert(buffer1 == [6, 7, 8, 9, 10]);
10580     assert(buffer2 == [11, 12, 13, 14, 15]);
10581 }
10582 
10583 @system unittest
10584 {
10585     import std.algorithm.iteration : filter;
10586     {
10587         ubyte[] buffer = [1, 2, 3, 4, 5];
10588         auto wrapper = refRange(&buffer);
10589         auto p = wrapper.ptr;
10590         auto f = wrapper.front;
10591         wrapper.front = f;
10592         auto e = wrapper.empty;
10593         wrapper.popFront();
10594         auto s = wrapper.save;
10595         auto b = wrapper.back;
10596         wrapper.back = b;
10597         wrapper.popBack();
10598         auto i = wrapper[0];
10599         wrapper.moveFront();
10600         wrapper.moveBack();
10601         wrapper.moveAt(0);
10602         auto l = wrapper.length;
10603         auto sl = wrapper[0 .. 1];
10604         assert(wrapper[0 .. $].length == buffer[0 .. $].length);
10605     }
10606 
10607     {
10608         ubyte[] buffer = [1, 2, 3, 4, 5];
10609         const wrapper = refRange(&buffer);
10610         const p = wrapper.ptr;
10611         const f = wrapper.front;
10612         const e = wrapper.empty;
10613         const s = wrapper.save;
10614         const b = wrapper.back;
10615         const i = wrapper[0];
10616         const l = wrapper.length;
10617         const sl = wrapper[0 .. 1];
10618     }
10619 
10620     {
10621         ubyte[] buffer = [1, 2, 3, 4, 5];
10622         auto filtered = filter!"true"(buffer);
10623         auto wrapper = refRange(&filtered);
10624         auto p = wrapper.ptr;
10625         auto f = wrapper.front;
10626         wrapper.front = f;
10627         auto e = wrapper.empty;
10628         wrapper.popFront();
10629         auto s = wrapper.save;
10630         wrapper.moveFront();
10631     }
10632 
10633     {
10634         ubyte[] buffer = [1, 2, 3, 4, 5];
10635         auto filtered = filter!"true"(buffer);
10636         const wrapper = refRange(&filtered);
10637         const p = wrapper.ptr;
10638 
10639         //Cannot currently be const. filter needs to be updated to handle const.
10640         /+
10641         const f = wrapper.front;
10642         const e = wrapper.empty;
10643         const s = wrapper.save;
10644         +/
10645     }
10646 
10647     {
10648         string str = "hello world";
10649         auto wrapper = refRange(&str);
10650         auto p = wrapper.ptr;
10651         auto f = wrapper.front;
10652         auto e = wrapper.empty;
10653         wrapper.popFront();
10654         auto s = wrapper.save;
10655         auto b = wrapper.back;
10656         wrapper.popBack();
10657     }
10658 
10659     {
10660         // Issue 16534 - opDollar should be defined if the
10661         // wrapped range defines length.
10662         auto range = 10.iota.takeExactly(5);
10663         auto wrapper = refRange(&range);
10664         assert(wrapper.length == 5);
10665         assert(wrapper[0 .. $ - 1].length == 4);
10666     }
10667 }
10668 
10669 //Test assignment.
10670 @system unittest
10671 {
10672     ubyte[] buffer1 = [1, 2, 3, 4, 5];
10673     ubyte[] buffer2 = [6, 7, 8, 9, 10];
10674     RefRange!(ubyte[]) wrapper1;
10675     RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
10676     assert(wrapper1.ptr is null);
10677     assert(wrapper2.ptr is &buffer2);
10678 
10679     wrapper1 = refRange(&buffer1);
10680     assert(wrapper1.ptr is &buffer1);
10681 
10682     wrapper1 = wrapper2;
10683     assert(wrapper1.ptr is &buffer1);
10684     assert(buffer1 == buffer2);
10685 
10686     wrapper1 = RefRange!(ubyte[]).init;
10687     assert(wrapper1.ptr is null);
10688     assert(wrapper2.ptr is &buffer2);
10689     assert(buffer1 == buffer2);
10690     assert(buffer1 == [6, 7, 8, 9, 10]);
10691 
10692     wrapper2 = null;
10693     assert(wrapper2.ptr is null);
10694     assert(buffer2 == [6, 7, 8, 9, 10]);
10695 }
10696 
10697 @system unittest
10698 {
10699     import std.algorithm.comparison : equal;
10700     import std.algorithm.mutation : bringToFront;
10701     import std.algorithm.searching : commonPrefix, find, until;
10702     import std.algorithm.sorting : sort;
10703 
10704     //Test that ranges are properly consumed.
10705     {
10706         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10707         auto wrapper = refRange(&arr);
10708 
10709         assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
10710         assert(arr == [41, 3, 40, 4, 42, 9]);
10711 
10712         assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
10713         assert(arr == [40, 4, 42, 9]);
10714 
10715         assert(equal(until(wrapper, 42), [40, 4]));
10716         assert(arr == [42, 9]);
10717 
10718         assert(find(wrapper, 12).empty);
10719         assert(arr.empty);
10720     }
10721 
10722     {
10723         string str = "Hello, world-like object.";
10724         auto wrapper = refRange(&str);
10725 
10726         assert(*find(wrapper, "l").ptr == "llo, world-like object.");
10727         assert(str == "llo, world-like object.");
10728 
10729         assert(equal(take(wrapper, 5), "llo, "));
10730         assert(str == "world-like object.");
10731     }
10732 
10733     //Test that operating on saved ranges does not consume the original.
10734     {
10735         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10736         auto wrapper = refRange(&arr);
10737         auto saved = wrapper.save;
10738         saved.popFrontN(3);
10739         assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
10740         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10741     }
10742 
10743     {
10744         string str = "Hello, world-like object.";
10745         auto wrapper = refRange(&str);
10746         auto saved = wrapper.save;
10747         saved.popFrontN(13);
10748         assert(*saved.ptr == "like object.");
10749         assert(str == "Hello, world-like object.");
10750     }
10751 
10752     //Test that functions which use save work properly.
10753     {
10754         int[] arr = [1, 42];
10755         auto wrapper = refRange(&arr);
10756         assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
10757     }
10758 
10759     {
10760         int[] arr = [4, 5, 6, 7, 1, 2, 3];
10761         auto wrapper = refRange(&arr);
10762         assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
10763         assert(arr == [1, 2, 3, 4, 5, 6, 7]);
10764     }
10765 
10766     //Test bidirectional functions.
10767     {
10768         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10769         auto wrapper = refRange(&arr);
10770 
10771         assert(wrapper.back == 9);
10772         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10773 
10774         wrapper.popBack();
10775         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
10776     }
10777 
10778     {
10779         string str = "Hello, world-like object.";
10780         auto wrapper = refRange(&str);
10781 
10782         assert(wrapper.back == '.');
10783         assert(str == "Hello, world-like object.");
10784 
10785         wrapper.popBack();
10786         assert(str == "Hello, world-like object");
10787     }
10788 
10789     //Test random access functions.
10790     {
10791         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10792         auto wrapper = refRange(&arr);
10793 
10794         assert(wrapper[2] == 2);
10795         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10796 
10797         assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
10798         assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10799     }
10800 
10801     //Test move functions.
10802     {
10803         int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10804         auto wrapper = refRange(&arr);
10805 
10806         auto t1 = wrapper.moveFront();
10807         auto t2 = wrapper.moveBack();
10808         wrapper.front = t2;
10809         wrapper.back = t1;
10810         assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
10811 
10812         sort(wrapper.save);
10813         assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
10814     }
10815 }
10816 
10817 @system unittest
10818 {
10819     struct S
10820     {
10821         @property int front() @safe const pure nothrow { return 0; }
10822         enum bool empty = false;
10823         void popFront() @safe pure nothrow { }
10824         @property auto save() @safe pure nothrow { return this; }
10825     }
10826 
10827     S s;
10828     auto wrapper = refRange(&s);
10829     static assert(isInfinite!(typeof(wrapper)));
10830 }
10831 
10832 @system unittest
10833 {
10834     class C
10835     {
10836         @property int front() @safe const pure nothrow { return 0; }
10837         @property bool empty() @safe const pure nothrow { return false; }
10838         void popFront() @safe pure nothrow { }
10839         @property auto save() @safe pure nothrow { return this; }
10840     }
10841     static assert(isForwardRange!C);
10842 
10843     auto c = new C;
10844     auto cWrapper = refRange(&c);
10845     static assert(is(typeof(cWrapper) == C));
10846     assert(cWrapper is c);
10847 }
10848 
10849 @system unittest // issue 14373
10850 {
10851     static struct R
10852     {
10853         @property int front() {return 0;}
10854         void popFront() {empty = true;}
10855         bool empty = false;
10856     }
10857     R r;
10858     refRange(&r).popFront();
10859     assert(r.empty);
10860 }
10861 
10862 @system unittest // issue 14575
10863 {
10864     struct R
10865     {
10866         Object front;
10867         alias back = front;
10868         bool empty = false;
10869         void popFront() {empty = true;}
10870         alias popBack = popFront;
10871         @property R save() {return this;}
10872     }
10873     static assert(isBidirectionalRange!R);
10874     R r;
10875     auto rr = refRange(&r);
10876 
10877     struct R2
10878     {
10879         @property Object front() {return null;}
10880         @property const(Object) front() const {return null;}
10881         alias back = front;
10882         bool empty = false;
10883         void popFront() {empty = true;}
10884         alias popBack = popFront;
10885         @property R2 save() {return this;}
10886     }
10887     static assert(isBidirectionalRange!R2);
10888     R2 r2;
10889     auto rr2 = refRange(&r2);
10890 }
10891 
10892 /// ditto
10893 auto refRange(R)(R* range)
10894 if (isInputRange!R)
10895 {
10896     static if (!is(R == class))
10897         return RefRange!R(range);
10898     else
10899         return *range;
10900 }
10901 
10902 /*****************************************************************************/
10903 
10904 @safe unittest    // bug 9060
10905 {
10906     import std.algorithm.iteration : map, joiner, group;
10907     import std.algorithm.searching : until;
10908     // fix for std.algorithm
10909     auto r = map!(x => 0)([1]);
10910     chain(r, r);
10911     zip(r, r);
10912     roundRobin(r, r);
10913 
10914     struct NRAR {
10915         typeof(r) input;
10916         @property empty() { return input.empty; }
10917         @property front() { return input.front; }
10918         void popFront()   { input.popFront(); }
10919         @property save()  { return NRAR(input.save); }
10920     }
10921     auto n1 = NRAR(r);
10922     cycle(n1);  // non random access range version
10923 
10924     assumeSorted(r);
10925 
10926     // fix for std.range
10927     joiner([r], [9]);
10928 
10929     struct NRAR2 {
10930         NRAR input;
10931         @property empty() { return true; }
10932         @property front() { return input; }
10933         void popFront() { }
10934         @property save()  { return NRAR2(input.save); }
10935     }
10936     auto n2 = NRAR2(n1);
10937     joiner(n2);
10938 
10939     group(r);
10940 
10941     until(r, 7);
10942     static void foo(R)(R r) { until!(x => x > 7)(r); }
10943     foo(r);
10944 }
10945 
10946 private struct Bitwise(R)
10947 if (isInputRange!R && isIntegral!(ElementType!R))
10948 {
10949 private:
10950     alias ElemType = ElementType!R;
10951     alias UnsignedElemType = Unsigned!ElemType;
10952 
10953     R parent;
10954     enum bitsNum = ElemType.sizeof * 8;
10955     size_t maskPos = 1;
10956 
10957     static if (isBidirectionalRange!R)
10958     {
10959         size_t backMaskPos = bitsNum;
10960     }
10961 
10962 public:
10963     this()(auto ref R range)
10964     {
10965         parent = range;
10966     }
10967 
10968     static if (isInfinite!R)
10969     {
10970         enum empty = false;
10971     }
10972     else
10973     {
10974         /**
10975          * Check if the range is empty
10976          *
10977          * Returns: a boolean true or false
10978          */
10979         bool empty()
10980         {
10981             static if (hasLength!R)
10982             {
10983                 return length == 0;
10984             }
10985             else static if (isBidirectionalRange!R)
10986             {
10987                 if (parent.empty)
10988                 {
10989                     return true;
10990                 }
10991                 else
10992                 {
10993                     /*
10994                        If we have consumed the last element of the range both from
10995                        the front and the back, then the masks positions will overlap
10996                      */
10997                     return parent.save.dropOne.empty && (maskPos > backMaskPos);
10998                 }
10999             }
11000             else
11001             {
11002                 /*
11003                    If we consumed the last element of the range, but not all the
11004                    bits in the last element
11005                  */
11006                 return parent.empty;
11007             }
11008         }
11009     }
11010 
11011     bool front()
11012     {
11013         assert(!empty);
11014         return (parent.front & mask(maskPos)) != 0;
11015     }
11016 
11017     void popFront()
11018     {
11019         assert(!empty);
11020         ++maskPos;
11021         if (maskPos > bitsNum)
11022         {
11023             parent.popFront;
11024             maskPos = 1;
11025         }
11026     }
11027 
11028     static if (hasLength!R)
11029     {
11030         size_t length()
11031         {
11032             auto len = parent.length * bitsNum - (maskPos - 1);
11033             static if (isBidirectionalRange!R)
11034             {
11035                 len -= bitsNum - backMaskPos;
11036             }
11037             return len;
11038         }
11039 
11040         alias opDollar = length;
11041     }
11042 
11043     static if (isForwardRange!R)
11044     {
11045         typeof(this) save()
11046         {
11047             auto result = this;
11048             result.parent = parent.save;
11049             return result;
11050         }
11051     }
11052 
11053     static if (isBidirectionalRange!R)
11054     {
11055         bool back()
11056         {
11057             assert(!empty);
11058             return (parent.back & mask(backMaskPos)) != 0;
11059         }
11060 
11061         void popBack()
11062         {
11063             assert(!empty);
11064             --backMaskPos;
11065             if (backMaskPos == 0)
11066             {
11067                 parent.popBack;
11068                 backMaskPos = bitsNum;
11069             }
11070         }
11071     }
11072 
11073     static if (isRandomAccessRange!R)
11074     {
11075         /**
11076           Return the `n`th bit within the range
11077          */
11078         bool opIndex(size_t n)
11079         in
11080         {
11081             /*
11082                If it does not have the length property, it means that R is
11083                an infinite range
11084              */
11085             static if (hasLength!R)
11086             {
11087                 assert(n < length, "Index out of bounds");
11088             }
11089         }
11090         body
11091         {
11092             immutable size_t remainingBits = bitsNum - maskPos + 1;
11093             // If n >= maskPos, then the bit sign will be 1, otherwise 0
11094             immutable sizediff_t sign = (remainingBits - n - 1) >> (sizediff_t.sizeof * 8 - 1);
11095             /*
11096                By truncating n with remainingBits bits we have skipped the
11097                remaining bits in parent[0], so we need to add 1 to elemIndex.
11098 
11099                Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
11100              */
11101             import core.bitop : bsf;
11102             immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
11103 
11104             /*
11105                Since the indexing is from LSB to MSB, we need to index at the
11106                remainder of (n - remainingBits).
11107 
11108                Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
11109              */
11110             immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
11111                              + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
11112 
11113             return (parent[elemIndex] & mask(elemMaskPos)) != 0;
11114         }
11115 
11116         static if (hasAssignableElements!R)
11117         {
11118             /**
11119               Assigns `flag` to the `n`th bit within the range
11120              */
11121             void opIndexAssign(bool flag, size_t n)
11122                 in
11123                 {
11124                     static if (hasLength!R)
11125                     {
11126                         assert(n < length, "Index out of bounds");
11127                     }
11128                 }
11129             body
11130             {
11131                 import core.bitop : bsf;
11132 
11133                 immutable size_t remainingBits = bitsNum - maskPos + 1;
11134                 immutable sizediff_t sign = (remainingBits - n - 1) >> (sizediff_t.sizeof * 8 - 1);
11135                 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
11136                 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
11137                     + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
11138 
11139                 auto elem = parent[elemIndex];
11140                 auto elemMask = mask(elemMaskPos);
11141                 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
11142                         + (flag ^ 1) * (elem & ~elemMask));
11143             }
11144         }
11145 
11146         Bitwise!R opSlice()
11147         {
11148             return this.save;
11149         }
11150 
11151         Bitwise!R opSlice(size_t start, size_t end)
11152         in
11153         {
11154             assert(start < end, "Invalid bounds: end <= start");
11155         }
11156         body
11157         {
11158             import core.bitop : bsf;
11159 
11160             size_t remainingBits = bitsNum - maskPos + 1;
11161             sizediff_t sign = (remainingBits - start - 1) >> (sizediff_t.sizeof * 8 - 1);
11162             immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
11163             immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
11164                                               + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
11165 
11166             immutable size_t sliceLen = end - start - 1;
11167             remainingBits = bitsNum - startElemMaskPos + 1;
11168             sign = (remainingBits - sliceLen - 1) >> (sizediff_t.sizeof * 8 - 1);
11169             immutable size_t endElemIndex = startElemIndex
11170                                           + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
11171             immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
11172                                             + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
11173 
11174             typeof(return) result;
11175             // Get the slice to be returned from the parent
11176             result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
11177             result.maskPos = startElemMaskPos;
11178             static if (isBidirectionalRange!R)
11179             {
11180                 result.backMaskPos = endElemMaskPos;
11181             }
11182             return result;
11183         }
11184     }
11185 
11186 private:
11187     auto mask(size_t maskPos)
11188     {
11189         return (1UL << (maskPos - 1UL));
11190     }
11191 }
11192 
11193 /**
11194 Bitwise adapter over an integral type range. Consumes the range elements bit by
11195 bit, from the least significant bit to the most significant bit.
11196 
11197 Params:
11198     R = an integral input range to iterate over
11199     range = range to consume bit by by
11200 
11201 Returns:
11202     A `Bitwise` input range with propagated forward, bidirectional
11203     and random access capabilities
11204 */
11205 auto bitwise(R)(auto ref R range)
11206 if (isInputRange!R && isIntegral!(ElementType!R))
11207 {
11208     return Bitwise!R(range);
11209 }
11210 
11211 ///
11212 @safe pure unittest
11213 {
11214     import std.algorithm.comparison : equal;
11215     import std.format : format;
11216 
11217     // 00000011 00001001
11218     ubyte[] arr = [3, 9];
11219     auto r = arr.bitwise;
11220 
11221     // iterate through it as with any other range
11222     assert(format("%(%d%)", r) == "1100000010010000");
11223     assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
11224 
11225     auto r2 = r[5 .. $];
11226     // set a bit
11227     r[2] = 1;
11228     assert(arr[0] == 7);
11229     assert(r[5] == r2[0]);
11230 }
11231 
11232 /// You can use bitwise to implement an uniform bool generator
11233 @safe unittest
11234 {
11235     import std.algorithm.comparison : equal;
11236     import std.random : rndGen;
11237 
11238     auto rb = rndGen.bitwise;
11239     static assert(isInfinite!(typeof(rb)));
11240 
11241     auto rb2 = rndGen.bitwise;
11242     // Don't forget that structs are passed by value
11243     assert(rb.take(10).equal(rb2.take(10)));
11244 }
11245 
11246 // Test nogc inference
11247 @safe @nogc unittest
11248 {
11249     static ubyte[] arr = [3, 9];
11250     auto bw = arr.bitwise;
11251     auto bw2 = bw[];
11252     auto bw3 = bw[8 .. $];
11253     bw3[2] = true;
11254 
11255     assert(arr[1] == 13);
11256     assert(bw[$ - 6]);
11257     assert(bw[$ - 6] == bw2[$ - 6]);
11258     assert(bw[$ - 6] == bw3[$ - 6]);
11259 }
11260 
11261 // Test all range types over all integral types
11262 @safe pure nothrow unittest
11263 {
11264     import std.internal.test.dummyrange;
11265 
11266     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
11267             long, ulong);
foreach(IntegralType;IntegralTypes)11268     foreach (IntegralType; IntegralTypes)
11269     {
11270         foreach (T; AllDummyRangesType!(IntegralType[]))
11271         {
11272             T a;
11273             auto bw = Bitwise!T(a);
11274 
11275             static if (isForwardRange!T)
11276             {
11277                 auto bwFwdSave = bw.save;
11278             }
11279 
11280             static if (isBidirectionalRange!T)
11281             {
11282                 auto bwBack = bw.save;
11283                 auto bwBackSave = bw.save;
11284             }
11285 
11286             static if (hasLength!T)
11287             {
11288                 auto bwLength = bw.length;
11289                 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
11290                 static if (isForwardRange!T)
11291                 {
11292                     assert(bw.length == bwFwdSave.length);
11293                 }
11294             }
11295 
11296             // Make sure front and back are not the mechanisms that modify the range
11297             long numCalls = 42;
11298             bool initialFrontValue;
11299 
11300             if (!bw.empty)
11301             {
11302                 initialFrontValue = bw.front;
11303             }
11304 
11305             while (!bw.empty && (--numCalls))
11306             {
11307                 bw.front;
11308                 assert(bw.front == initialFrontValue);
11309             }
11310 
11311             /*
11312                Check that empty works properly and that popFront does not get called
11313                more times than it should
11314              */
11315             numCalls = 0;
11316             while (!bw.empty)
11317             {
11318                 ++numCalls;
11319 
11320                 static if (hasLength!T)
11321                 {
11322                     assert(bw.length == bwLength);
11323                     --bwLength;
11324                 }
11325 
11326                 static if (isForwardRange!T)
11327                 {
11328                     assert(bw.front == bwFwdSave.front);
11329                     bwFwdSave.popFront();
11330                 }
11331 
11332                 static if (isBidirectionalRange!T)
11333                 {
11334                     assert(bwBack.front == bwBackSave.front);
11335                     bwBack.popBack();
11336                     bwBackSave.popBack();
11337                 }
11338                 bw.popFront();
11339             }
11340 
11341             auto rangeLen = numCalls / (IntegralType.sizeof * 8);
11342             assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
11343             assert(bw.empty);
11344             static if (isForwardRange!T)
11345             {
11346                 assert(bwFwdSave.empty);
11347             }
11348 
11349             static if (isBidirectionalRange!T)
11350             {
11351                 assert(bwBack.empty);
11352             }
11353         }
11354     }
11355 }
11356 
11357 // Test opIndex and opSlice
11358 @system unittest
11359 {
11360     alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
11361             long, ulong);
foreach(IntegralType;IntegralTypes)11362     foreach (IntegralType; IntegralTypes)
11363     {
11364         size_t bitsNum = IntegralType.sizeof * 8;
11365 
11366         auto first = cast(IntegralType)(1);
11367 
11368         // 2 ^ (bitsNum - 1)
11369         auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
11370 
11371         IntegralType[] a = [first, second];
11372         auto bw = Bitwise!(IntegralType[])(a);
11373 
11374         // Check against lsb of a[0]
11375         assert(bw[0] == true);
11376         // Check against msb - 1 of a[1]
11377         assert(bw[2 * bitsNum - 2] == true);
11378 
11379         bw.popFront();
11380         assert(bw[2 * bitsNum - 3] == true);
11381 
11382         import core.exception : Error;
11383         import std.exception : assertThrown;
11384 
11385         // Check out of bounds error
11386         assertThrown!Error(bw[2 * bitsNum - 1]);
11387 
11388         bw[2] = true;
11389         assert(bw[2] == true);
11390         bw.popFront();
11391         assert(bw[1] == true);
11392 
11393         auto bw2 = bw[0 .. $ - 5];
11394         auto bw3 = bw2[];
11395         assert(bw2.length == (bw.length - 5));
11396         assert(bw2.length == bw3.length);
11397         bw2.popFront();
11398         assert(bw2.length != bw3.length);
11399     }
11400 }
11401 
11402 /*********************************
11403  * An OutputRange that discards the data it receives.
11404  */
11405 struct NullSink
11406 {
putNullSink11407     void put(E)(E){}
11408 }
11409 
11410 ///
11411 @safe unittest
11412 {
11413     import std.algorithm.iteration : map;
11414     import std.algorithm.mutation : copy;
11415     [4, 5, 6].map!(x => x * 2).copy(NullSink()); // data is discarded
11416 }
11417 
11418 
11419 /++
11420 
11421   Implements a "tee" style pipe, wrapping an input range so that elements of the
11422   range can be passed to a provided function or $(LREF OutputRange) as they are
11423   iterated over. This is useful for printing out intermediate values in a long
11424   chain of range code, performing some operation with side-effects on each call
11425   to $(D front) or $(D popFront), or diverting the elements of a range into an
11426   auxiliary $(LREF OutputRange).
11427 
11428   It is important to note that as the resultant range is evaluated lazily,
11429   in the case of the version of $(D tee) that takes a function, the function
11430   will not actually be executed until the range is "walked" using functions
11431   that evaluate ranges, such as $(REF array, std,array) or
11432   $(REF fold, std,algorithm,iteration).
11433 
11434   Params:
11435   pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
11436   calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
11437   respectively, `fun`). If `No.pipeOnPop`, only elements for which `front` does
11438   get called will be also sent to `outputRange`/`fun`.
11439   inputRange = The input range being passed through.
11440   outputRange = This range will receive elements of `inputRange` progressively
11441   as iteration proceeds.
11442   fun = This function will be called with elements of `inputRange`
11443   progressively as iteration proceeds.
11444 
11445   Returns:
11446   An input range that offers the elements of `inputRange`. Regardless of
11447   whether `inputRange` is a more powerful range (forward, bidirectional etc),
11448   the result is always an input range. Reading this causes `inputRange` to be
11449   iterated and returns its elements in turn. In addition, the same elements
11450   will be passed to `outputRange` or `fun` as well.
11451 
11452   See_Also: $(REF each, std,algorithm,iteration)
11453 +/
11454 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
11455 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
11456 {
11457     static struct Result
11458     {
11459         private R1 _input;
11460         private R2 _output;
11461         static if (!pipeOnPop)
11462         {
11463             private bool _frontAccessed;
11464         }
11465 
11466         static if (hasLength!R1)
11467         {
lengthResult11468             @property auto length()
11469             {
11470                 return _input.length;
11471             }
11472         }
11473 
11474         static if (isInfinite!R1)
11475         {
11476             enum bool empty = false;
11477         }
11478         else
11479         {
emptyResult11480             @property bool empty() { return _input.empty; }
11481         }
11482 
popFrontResult11483         void popFront()
11484         {
11485             assert(!_input.empty, "Attempting to popFront an empty tee");
11486             static if (pipeOnPop)
11487             {
11488                 put(_output, _input.front);
11489             }
11490             else
11491             {
11492                 _frontAccessed = false;
11493             }
11494             _input.popFront();
11495         }
11496 
frontResult11497         @property auto ref front()
11498         {
11499             assert(!_input.empty, "Attempting to fetch the front of an empty tee");
11500             static if (!pipeOnPop)
11501             {
11502                 if (!_frontAccessed)
11503                 {
11504                     _frontAccessed = true;
11505                     put(_output, _input.front);
11506                 }
11507             }
11508             return _input.front;
11509         }
11510     }
11511 
11512     return Result(inputRange, outputRange);
11513 }
11514 
11515 /// Ditto
11516 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
11517 if (is(typeof(fun) == void) || isSomeFunction!fun)
11518 {
11519     import std.traits : isDelegate, isFunctionPointer;
11520     /*
11521         Distinguish between function literals and template lambdas
11522         when using either as an $(LREF OutputRange). Since a template
11523         has no type, typeof(template) will always return void.
11524         If it's a template lambda, it's first necessary to instantiate
11525         it with $(D ElementType!R1).
11526     */
11527     static if (is(typeof(fun) == void))
11528         alias _fun = fun!(ElementType!R1);
11529     else
11530         alias _fun = fun;
11531 
11532     static if (isFunctionPointer!_fun || isDelegate!_fun)
11533     {
11534         return tee!pipeOnPop(inputRange, _fun);
11535     }
11536     else
11537     {
11538         return tee!pipeOnPop(inputRange, &_fun);
11539     }
11540 }
11541 
11542 ///
11543 @safe unittest
11544 {
11545     import std.algorithm.comparison : equal;
11546     import std.algorithm.iteration : filter, map;
11547 
11548     // Sum values while copying
11549     int[] values = [1, 4, 9, 16, 25];
11550     int sum = 0;
11551     auto newValues = values.tee!(a => sum += a).array;
11552     assert(equal(newValues, values));
11553     assert(sum == 1 + 4 + 9 + 16 + 25);
11554 
11555     // Count values that pass the first filter
11556     int count = 0;
11557     auto newValues4 = values.filter!(a => a < 10)
11558                             .tee!(a => count++)
11559                             .map!(a => a + 1)
11560                             .filter!(a => a < 10);
11561 
11562     //Fine, equal also evaluates any lazy ranges passed to it.
11563     //count is not 3 until equal evaluates newValues4
11564     assert(equal(newValues4, [2, 5]));
11565     assert(count == 3);
11566 }
11567 
11568 //
11569 @safe unittest
11570 {
11571     import std.algorithm.comparison : equal;
11572     import std.algorithm.iteration : filter, map;
11573 
11574     int[] values = [1, 4, 9, 16, 25];
11575 
11576     int count = 0;
11577     auto newValues = values.filter!(a => a < 10)
11578         .tee!(a => count++, No.pipeOnPop)
11579         .map!(a => a + 1)
11580         .filter!(a => a < 10);
11581 
11582     auto val = newValues.front;
11583     assert(count == 1);
11584     //front is only evaluated once per element
11585     val = newValues.front;
11586     assert(count == 1);
11587 
11588     //popFront() called, fun will be called
11589     //again on the next access to front
11590     newValues.popFront();
11591     newValues.front;
11592     assert(count == 2);
11593 
11594     int[] preMap = new int[](3), postMap = [];
11595     auto mappedValues = values.filter!(a => a < 10)
11596         //Note the two different ways of using tee
11597         .tee(preMap)
11598         .map!(a => a + 1)
11599         .tee!(a => postMap ~= a)
11600         .filter!(a => a < 10);
11601     assert(equal(mappedValues, [2, 5]));
11602     assert(equal(preMap, [1, 4, 9]));
11603     assert(equal(postMap, [2, 5, 10]));
11604 }
11605 
11606 //
11607 @safe unittest
11608 {
11609     import std.algorithm.comparison : equal;
11610     import std.algorithm.iteration : filter, map;
11611 
11612     char[] txt = "Line one, Line 2".dup;
11613 
isVowel(dchar c)11614     bool isVowel(dchar c)
11615     {
11616         import std.string : indexOf;
11617         return "AaEeIiOoUu".indexOf(c) != -1;
11618     }
11619 
11620     int vowelCount = 0;
11621     int shiftedCount = 0;
11622     auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
11623                                 .filter!(c => !isVowel(c))
11624                                 .map!(c => (c == ' ') ? c : c + 1)
11625                                 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
11626     assert(equal(removeVowels, "Mo o- Mo 3"));
11627     assert(vowelCount == 6);
11628     assert(shiftedCount == 3);
11629 }
11630 
11631 @safe unittest
11632 {
11633     // Manually stride to test different pipe behavior.
testRange(Range)11634     void testRange(Range)(Range r)
11635     {
11636         const int strideLen = 3;
11637         int i = 0;
11638         ElementType!Range elem1;
11639         ElementType!Range elem2;
11640         while (!r.empty)
11641         {
11642             if (i % strideLen == 0)
11643             {
11644                 //Make sure front is only
11645                 //evaluated once per item
11646                 elem1 = r.front;
11647                 elem2 = r.front;
11648                 assert(elem1 == elem2);
11649             }
11650             r.popFront();
11651             i++;
11652         }
11653     }
11654 
11655     string txt = "abcdefghijklmnopqrstuvwxyz";
11656 
11657     int popCount = 0;
11658     auto pipeOnPop = txt.tee!(a => popCount++);
11659     testRange(pipeOnPop);
11660     assert(popCount == 26);
11661 
11662     int frontCount = 0;
11663     auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
11664     testRange(pipeOnFront);
11665     assert(frontCount == 9);
11666 }
11667 
11668 @safe unittest
11669 {
11670     import std.algorithm.comparison : equal;
11671     import std.meta : AliasSeq;
11672 
11673     //Test diverting elements to an OutputRange
11674     string txt = "abcdefghijklmnopqrstuvwxyz";
11675 
11676     dchar[] asink1 = [];
11677     auto fsink = (dchar c) { asink1 ~= c; };
11678     auto result1 = txt.tee(fsink).array;
11679     assert(equal(txt, result1) && (equal(result1, asink1)));
11680 
11681     dchar[] _asink1 = [];
11682     auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
11683     assert(equal(txt, _result1) && (equal(_result1, _asink1)));
11684 
11685     dchar[] asink2 = new dchar[](txt.length);
fsink2(dchar c)11686     void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
11687     auto result2 = txt.tee(&fsink2).array;
11688     assert(equal(txt, result2) && equal(result2, asink2));
11689 
11690     dchar[] asink3 = new dchar[](txt.length);
11691     auto result3 = txt.tee(asink3).array;
11692     assert(equal(txt, result3) && equal(result3, asink3));
11693 
11694     foreach (CharType; AliasSeq!(char, wchar, dchar))
11695     {
11696         auto appSink = appender!(CharType[])();
11697         auto appResult = txt.tee(appSink).array;
11698         assert(equal(txt, appResult) && equal(appResult, appSink.data));
11699     }
11700 
11701     foreach (StringType; AliasSeq!(string, wstring, dstring))
11702     {
11703         auto appSink = appender!StringType();
11704         auto appResult = txt.tee(appSink).array;
11705         assert(equal(txt, appResult) && equal(appResult, appSink.data));
11706     }
11707 }
11708 
11709 @safe unittest
11710 {
11711     // Issue 13483
func1(T)11712     static void func1(T)(T x) {}
func2(int x)11713     void func2(int x) {}
11714 
11715     auto r = [1, 2, 3, 4].tee!func1.tee!func2;
11716 }
11717 
11718 /**
11719 Extends the length of the input range `r` by padding out the start of the
11720 range with the element `e`. The element `e` must be of a common type with
11721 the element type of the range `r` as defined by $(REF CommonType, std, traits).
11722 If `n` is less than the length of of `r`, then `r` is returned unmodified.
11723 
11724 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
11725 about length for strings, which is not the number of characters, or
11726 graphemes, but instead the number of encoding units. If you want to treat each
11727 grapheme as only one encoding unit long, then call
11728 $(REF byGrapheme, std, uni) before calling this function.
11729 
11730 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
11731 
11732 Params:
11733     r = an input range with a length, or a forward range
11734     e = element to pad the range with
11735     n = the length to pad to
11736 
11737 Returns:
11738     A range containing the elements of the original range with the extra padding
11739 
11740 See Also:
11741     $(REF leftJustifier, std, string)
11742 */
11743 auto padLeft(R, E)(R r, E e, size_t n)
11744 if (
11745     ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
11746     !is(CommonType!(ElementType!R, E) == void)
11747 )
11748 {
11749     static if (hasLength!R)
11750         auto dataLength = r.length;
11751     else
11752         auto dataLength = r.save.walkLength(n);
11753 
11754     return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
11755 }
11756 
11757 ///
11758 @safe pure unittest
11759 {
11760     import std.algorithm.comparison : equal;
11761 
11762     assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
11763     assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
11764 
11765     assert("abc".padLeft('_', 6).equal("___abc"));
11766 }
11767 
11768 @safe pure nothrow unittest
11769 {
11770     import std.algorithm.comparison : equal;
11771     import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
11772     import std.meta : AliasSeq;
11773 
11774     alias DummyRanges = AliasSeq!(
11775         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
11776         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
11777         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
11778         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
11779         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
11780         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
11781         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
11782         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
11783         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
11784         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
11785     );
11786 
foreach(Range;DummyRanges)11787     foreach (Range; DummyRanges)
11788     {
11789         Range r;
11790         assert(r
11791             .padLeft(0, 12)
11792             .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
11793         );
11794     }
11795 }
11796 
11797 // Test nogc inference
11798 @safe @nogc pure unittest
11799 {
11800     import std.algorithm.comparison : equal;
11801 
11802     static immutable r1 = [1, 2, 3, 4];
11803     static immutable r2 = [0, 0, 1, 2, 3, 4];
11804     assert(r1.padLeft(0, 6).equal(r2));
11805 }
11806 
11807 /**
11808 Extend the length of the input range `r` by padding out the end of the range
11809 with the element `e`. The element `e` must be of a common type with the
11810 element type of the range `r` as defined by $(REF CommonType, std, traits).
11811 If `n` is less than the length of of `r`, then the contents of `r` are
11812 returned.
11813 
11814 The range primitives that the resulting range provides depends whether or not `r`
11815 provides them. Except the functions `back` and `popBack`, which also require
11816 the range to have a length as well as `back` and `popBack`
11817 
11818 Params:
11819     r = an input range with a length
11820     e = element to pad the range with
11821     n = the length to pad to
11822 
11823 Returns:
11824     A range containing the elements of the original range with the extra padding
11825 
11826 See Also:
11827     $(REF rightJustifier, std, string)
11828 */
11829 auto padRight(R, E)(R r, E e, size_t n)
11830 if (
11831     isInputRange!R &&
11832     !isInfinite!R &&
11833     !is(CommonType!(ElementType!R, E) == void))
11834 {
11835     static struct Result
11836     {
11837         private:
11838         R data;
11839         E element;
11840         size_t counter;
11841         static if (isBidirectionalRange!R && hasLength!R) size_t backPosition;
11842         size_t maxSize;
11843 
11844         public:
emptyResult11845         bool empty() @property
11846         {
11847             return data.empty && counter >= maxSize;
11848         }
11849 
frontResult11850         auto front() @property
11851         {
11852             assert(!empty, "Attempting to fetch the front of an empty padRight");
11853             return data.empty ? element : data.front;
11854         }
11855 
popFrontResult11856         void popFront()
11857         {
11858             assert(!empty, "Attempting to popFront an empty padRight");
11859             ++counter;
11860 
11861             if (!data.empty)
11862             {
11863                 data.popFront;
11864             }
11865         }
11866 
11867         static if (hasLength!R)
11868         {
lengthResult11869             size_t length() @property
11870             {
11871                 import std.algorithm.comparison : max;
11872                 return max(data.length, maxSize);
11873             }
11874         }
11875 
11876         static if (isForwardRange!R)
11877         {
saveResult11878             auto save() @property
11879             {
11880                 typeof(this) result = this;
11881                 data = data.save;
11882                 return result;
11883             }
11884         }
11885 
11886         static if (isBidirectionalRange!R && hasLength!R)
11887         {
backResult11888             auto back() @property
11889             {
11890                 assert(!empty, "Attempting to fetch the back of an empty padRight");
11891                 return backPosition > data.length ? element : data.back;
11892             }
11893 
popBackResult11894             void popBack()
11895             {
11896                 assert(!empty, "Attempting to popBack an empty padRight");
11897                 if (backPosition > data.length)
11898                 {
11899                     --backPosition;
11900                     --maxSize;
11901                 }
11902                 else
11903                 {
11904                     data.popBack;
11905                 }
11906             }
11907         }
11908 
11909         static if (isRandomAccessRange!R && hasLength!R)
11910         {
opIndexResult11911             E opIndex(size_t index)
11912             {
11913                 assert(index <= this.length, "Index out of bounds");
11914                 return (index > data.length && index <= maxSize) ? element :
11915                     data[index];
11916             }
11917         }
11918 
11919         static if (hasSlicing!R && hasLength!R)
11920         {
opSliceResult11921             auto opSlice(size_t a, size_t b)
11922             {
11923                 assert(
11924                     a <= b,
11925                     "Attempting to slice a padRight with a larger first argument than the second."
11926                 );
11927                 assert(
11928                     b <= length,
11929                     "Attempting to slice using an out of bounds index on a padRight"
11930                 );
11931                 return Result((b <= data.length) ? data[a .. b] : data[a .. data.length],
11932                     element, b - a);
11933             }
11934 
11935             alias opDollar = length;
11936         }
11937 
thisResult11938         this(R r, E e, size_t max)
11939         {
11940             data = r;
11941             element = e;
11942             maxSize = max;
11943             static if (isBidirectionalRange!R && hasLength!R)
11944                 backPosition = max;
11945         }
11946 
11947         @disable this();
11948     }
11949 
11950     return Result(r, e, n);
11951 }
11952 
11953 ///
11954 @safe pure unittest
11955 {
11956     import std.algorithm.comparison : equal;
11957 
11958     assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
11959     assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
11960 
11961     assert("abc".padRight('_', 6).equal("abc___"));
11962 }
11963 
11964 pure @safe unittest
11965 {
11966     import std.algorithm.comparison : equal;
11967     import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
11968     import std.meta : AliasSeq;
11969 
11970     auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
11971     dchar padding = '_';
11972     assert(string_input_range.padRight(padding, 6).equal("abc___"));
11973 
foreach(RangeType;AllDummyRanges)11974     foreach (RangeType; AllDummyRanges)
11975     {
11976         RangeType r1;
11977         assert(r1
11978             .padRight(0, 12)
11979             .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
11980         );
11981 
11982         // test if Result properly uses random access ranges
11983         static if (isRandomAccessRange!RangeType)
11984         {
11985             RangeType r3;
11986             assert(r3.padRight(0, 12)[0] == 1);
11987             assert(r3.padRight(0, 12)[2] == 3);
11988             assert(r3.padRight(0, 12)[11] == 0);
11989         }
11990 
11991         // test if Result properly uses slicing and opDollar
11992         static if (hasSlicing!RangeType)
11993         {
11994             RangeType r4;
11995             assert(r4
11996                 .padRight(0, 12)[0 .. 3]
11997                 .equal([1, 2, 3])
11998             );
11999             assert(r4
12000                 .padRight(0, 12)[2 .. $]
12001                 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
12002             );
12003             assert(r4
12004                 .padRight(0, 12)[0 .. $]
12005                 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
12006             );
12007         }
12008     }
12009 }
12010 
12011 // Test nogc inference
12012 @safe @nogc pure unittest
12013 {
12014     import std.algorithm.comparison : equal;
12015 
12016     static immutable r1 = [1, 2, 3, 4];
12017     static immutable r2 = [1, 2, 3, 4, 0, 0];
12018     assert(r1.padRight(0, 6).equal(r2));
12019 }
12020