1 // Written in the D programming language.
2 /**
3 This is a submodule of $(MREF std, algorithm).
4 It contains generic _iteration algorithms.
5 
6 $(SCRIPT inhibitQuickIndex = 1;)
7 $(BOOKTABLE Cheat Sheet,
8 $(TR $(TH Function Name) $(TH Description))
9 $(T2 cache,
10         Eagerly evaluates and caches another range's $(D front).)
11 $(T2 cacheBidirectional,
12         As above, but also provides $(D back) and $(D popBack).)
13 $(T2 chunkBy,
14         $(D chunkBy!((a,b) => a[1] == b[1])([[1, 1], [1, 2], [2, 2], [2, 1]]))
15         returns a range containing 3 subranges: the first with just
16         $(D [1, 1]); the second with the elements $(D [1, 2]) and $(D [2, 2]);
17         and the third with just $(D [2, 1]).)
18 $(T2 cumulativeFold,
19         $(D cumulativeFold!((a, b) => a + b)([1, 2, 3, 4])) returns a
20         lazily-evaluated range containing the successive reduced values `1`,
21         `3`, `6`, `10`.)
22 $(T2 each,
23         $(D each!writeln([1, 2, 3])) eagerly prints the numbers $(D 1), $(D 2)
24         and $(D 3) on their own lines.)
25 $(T2 filter,
26         $(D filter!(a => a > 0)([1, -1, 2, 0, -3])) iterates over elements $(D 1)
27         and $(D 2).)
28 $(T2 filterBidirectional,
29         Similar to $(D filter), but also provides $(D back) and $(D popBack) at
30         a small increase in cost.)
31 $(T2 fold,
32         $(D fold!((a, b) => a + b)([1, 2, 3, 4])) returns $(D 10).)
33 $(T2 group,
34         $(D group([5, 2, 2, 3, 3])) returns a range containing the tuples
35         $(D tuple(5, 1)), $(D tuple(2, 2)), and $(D tuple(3, 2)).)
36 $(T2 joiner,
37         $(D joiner(["hello", "world!"], "; ")) returns a range that iterates
38         over the characters $(D "hello; world!"). No new string is created -
39         the existing inputs are iterated.)
40 $(T2 map,
41         $(D map!(a => a * 2)([1, 2, 3])) lazily returns a range with the numbers
42         $(D 2), $(D 4), $(D 6).)
43 $(T2 permutations,
44         Lazily computes all permutations using Heap's algorithm.)
45 $(T2 reduce,
46         $(D reduce!((a, b) => a + b)([1, 2, 3, 4])) returns $(D 10).
47         This is the old implementation of `fold`.)
48 $(T2 splitter,
49         Lazily splits a range by a separator.)
50 $(T2 sum,
51         Same as $(D fold), but specialized for accurate summation.)
52 $(T2 uniq,
53         Iterates over the unique elements in a range, which is assumed sorted.)
54 )
55 
56 Copyright: Andrei Alexandrescu 2008-.
57 
58 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
59 
60 Authors: $(HTTP erdani.com, Andrei Alexandrescu)
61 
62 Source: $(PHOBOSSRC std/algorithm/_iteration.d)
63 
64 Macros:
65 T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
66  */
67 module std.algorithm.iteration;
68 
69 // FIXME
70 import std.functional; // : unaryFun, binaryFun;
71 import std.range.primitives;
72 import std.traits;
73 
74 private template aggregate(fun...)
75 if (fun.length >= 1)
76 {
77     /* --Intentionally not ddoc--
78      * Aggregates elements in each subrange of the given range of ranges using
79      * the given aggregating function(s).
80      * Params:
81      *  fun = One or more aggregating functions (binary functions that return a
82      *      single _aggregate value of their arguments).
83      *  ror = A range of ranges to be aggregated.
84      *
85      * Returns:
86      * A range representing the aggregated value(s) of each subrange
87      * of the original range. If only one aggregating function is specified,
88      * each element will be the aggregated value itself; if multiple functions
89      * are specified, each element will be a tuple of the aggregated values of
90      * each respective function.
91      */
92     auto aggregate(RoR)(RoR ror)
93         if (isInputRange!RoR && isIterable!(ElementType!RoR))
94     {
95         return ror.map!(reduce!fun);
96     }
97 
98     @safe unittest
99     {
100         import std.algorithm.comparison : equal, max, min;
101 
102         auto data = [[4, 2, 1, 3], [4, 9, -1, 3, 2], [3]];
103 
104         // Single aggregating function
105         auto agg1 = data.aggregate!max;
106         assert(agg1.equal([4, 9, 3]));
107 
108         // Multiple aggregating functions
109         import std.typecons : tuple;
110         auto agg2 = data.aggregate!(max, min);
111         assert(agg2.equal([
112             tuple(4, 1),
113             tuple(9, -1),
114             tuple(3, 3)
115         ]));
116     }
117 }
118 
119 /++
120 $(D cache) eagerly evaluates $(D front) of $(D range)
121 on each construction or call to $(D popFront),
122 to store the result in a cache.
123 The result is then directly returned when $(D front) is called,
124 rather than re-evaluated.
125 
126 This can be a useful function to place in a chain, after functions
127 that have expensive evaluation, as a lazy alternative to $(REF array, std,array).
128 In particular, it can be placed after a call to $(D map), or before a call
129 to $(D filter).
130 
131 $(D cache) may provide
132 $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
133 iteration if needed, but since this comes at an increased cost, it must be explicitly requested via the
134 call to $(D cacheBidirectional). Furthermore, a bidirectional cache will
135 evaluate the "center" element twice, when there is only one element left in
136 the range.
137 
138 $(D cache) does not provide random access primitives,
139 as $(D cache) would be unable to cache the random accesses.
140 If $(D Range) provides slicing primitives,
141 then $(D cache) will provide the same slicing primitives,
142 but $(D hasSlicing!Cache) will not yield true (as the $(REF hasSlicing, std,_range,primitives)
143 trait also checks for random access).
144 
145 Params:
146     range = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
147 
148 Returns:
149     an input range with the cached values of range
150 +/
151 auto cache(Range)(Range range)
152 if (isInputRange!Range)
153 {
154     return _Cache!(Range, false)(range);
155 }
156 
157 /// ditto
158 auto cacheBidirectional(Range)(Range range)
159 if (isBidirectionalRange!Range)
160 {
161     return _Cache!(Range, true)(range);
162 }
163 
164 ///
165 @safe unittest
166 {
167     import std.algorithm.comparison : equal;
168     import std.range, std.stdio;
169     import std.typecons : tuple;
170 
171     ulong counter = 0;
172     double fun(int x)
173     {
174         ++counter;
175         // http://en.wikipedia.org/wiki/Quartic_function
176         return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5;
177     }
178     // Without cache, with array (greedy)
179     auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))()
180                              .filter!(a => a[1] < 0)()
181                              .map!(a => a[0])()
182                              .array();
183 
184     // the values of x that have a negative y are:
185     assert(equal(result1, [-3, -2, 2]));
186 
187     // Check how many times fun was evaluated.
188     // As many times as the number of items in both source and result.
189     assert(counter == iota(-4, 5).length + result1.length);
190 
191     counter = 0;
192     // Without array, with cache (lazy)
193     auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))()
194                              .cache()
195                              .filter!(a => a[1] < 0)()
196                              .map!(a => a[0])();
197 
198     // the values of x that have a negative y are:
199     assert(equal(result2, [-3, -2, 2]));
200 
201     // Check how many times fun was evaluated.
202     // Only as many times as the number of items in source.
203     assert(counter == iota(-4, 5).length);
204 }
205 
206 /++
207 Tip: $(D cache) is eager when evaluating elements. If calling front on the
208 underlying _range has a side effect, it will be observable before calling
209 front on the actual cached _range.
210 
211 Furthermore, care should be taken composing $(D cache) with $(REF take, std,_range).
212 By placing $(D take) before $(D cache), then $(D cache) will be "aware"
213 of when the _range ends, and correctly stop caching elements when needed.
214 If calling front has no side effect though, placing $(D take) after $(D cache)
215 may yield a faster _range.
216 
217 Either way, the resulting ranges will be equivalent, but maybe not at the
218 same cost or side effects.
219 +/
220 @safe unittest
221 {
222     import std.algorithm.comparison : equal;
223     import std.range;
224     int i = 0;
225 
226     auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop);
227     auto r1 = r.take(3).cache();
228     auto r2 = r.cache().take(3);
229 
230     assert(equal(r1, [0, 1, 2]));
231     assert(i == 2); //The last "seen" element was 2. The data in cache has been cleared.
232 
233     assert(equal(r2, [0, 1, 2]));
234     assert(i == 3); //cache has accessed 3. It is still stored internally by cache.
235 }
236 
237 @safe unittest
238 {
239     import std.algorithm.comparison : equal;
240     import std.range;
241     auto a = [1, 2, 3, 4];
242     assert(equal(a.map!(a => (a - 1) * a)().cache(),                      [ 0, 2, 6, 12]));
243     assert(equal(a.map!(a => (a - 1) * a)().cacheBidirectional().retro(), [12, 6, 2,  0]));
244     auto r1 = [1, 2, 3, 4].cache()             [1 .. $];
245     auto r2 = [1, 2, 3, 4].cacheBidirectional()[1 .. $];
246     assert(equal(r1, [2, 3, 4]));
247     assert(equal(r2, [2, 3, 4]));
248 }
249 
250 @safe unittest
251 {
252     import std.algorithm.comparison : equal;
253 
254     //immutable test
255     static struct S
256     {
257         int i;
258         this(int i)
259         {
260             //this.i = i;
261         }
262     }
263     immutable(S)[] s = [S(1), S(2), S(3)];
264     assert(equal(s.cache(),              s));
265     assert(equal(s.cacheBidirectional(), s));
266 }
267 
268 @safe pure nothrow unittest
269 {
270     import std.algorithm.comparison : equal;
271 
272     //safety etc
273     auto a = [1, 2, 3, 4];
274     assert(equal(a.cache(),              a));
275     assert(equal(a.cacheBidirectional(), a));
276 }
277 
278 @safe unittest
279 {
280     char[][] stringbufs = ["hello".dup, "world".dup];
281     auto strings = stringbufs.map!((a)=>a.idup)().cache();
282     assert(strings.front is strings.front);
283 }
284 
285 @safe unittest
286 {
287     import std.range;
288     auto c = [1, 2, 3].cycle().cache();
289     c = c[1 .. $];
290     auto d = c[0 .. 1];
291 }
292 
293 @safe unittest
294 {
295     static struct Range
296     {
297         bool initialized = false;
298         bool front() @property {return initialized = true;}
299         void popFront() {initialized = false;}
300         enum empty = false;
301     }
302     auto r = Range().cache();
303     assert(r.source.initialized == true);
304 }
305 
306 private struct _Cache(R, bool bidir)
307 {
308     import core.exception : RangeError;
309 
310     private
311     {
312         import std.algorithm.internal : algoFormat;
313         import std.meta : AliasSeq;
314 
315         alias E  = ElementType!R;
316         alias UE = Unqual!E;
317 
318         R source;
319 
320         static if (bidir) alias CacheTypes = AliasSeq!(UE, UE);
321         else              alias CacheTypes = AliasSeq!UE;
322         CacheTypes caches;
323 
324         static assert(isAssignable!(UE, E) && is(UE : E),
325             algoFormat(
326                 "Cannot instantiate range with %s because %s elements are not assignable to %s.",
327                 R.stringof,
328                 E.stringof,
329                 UE.stringof
330             )
331         );
332     }
333 
334     this(R range)
335     {
336         source = range;
337         if (!range.empty)
338         {
339              caches[0] = source.front;
340              static if (bidir)
341                  caches[1] = source.back;
342         }
343     }
344 
345     static if (isInfinite!R)
346         enum empty = false;
347     else
348         bool empty() @property
349         {
350             return source.empty;
351         }
352 
353     static if (hasLength!R) auto length() @property
354     {
355         return source.length;
356     }
357 
358     E front() @property
359     {
360         version(assert) if (empty) throw new RangeError();
361         return caches[0];
362     }
363     static if (bidir) E back() @property
364     {
365         version(assert) if (empty) throw new RangeError();
366         return caches[1];
367     }
368 
369     void popFront()
370     {
371         version(assert) if (empty) throw new RangeError();
372         source.popFront();
373         if (!source.empty)
374             caches[0] = source.front;
375         else
376             caches = CacheTypes.init;
377     }
378     static if (bidir) void popBack()
379     {
380         version(assert) if (empty) throw new RangeError();
381         source.popBack();
382         if (!source.empty)
383             caches[1] = source.back;
384         else
385             caches = CacheTypes.init;
386     }
387 
388     static if (isForwardRange!R)
389     {
390         private this(R source, ref CacheTypes caches)
391         {
392             this.source = source;
393             this.caches = caches;
394         }
395         typeof(this) save() @property
396         {
397             return typeof(this)(source.save, caches);
398         }
399     }
400 
401     static if (hasSlicing!R)
402     {
403         enum hasEndSlicing = is(typeof(source[size_t.max .. $]));
404 
405         static if (hasEndSlicing)
406         {
407             private static struct DollarToken{}
408             enum opDollar = DollarToken.init;
409 
410             auto opSlice(size_t low, DollarToken)
411             {
412                 return typeof(this)(source[low .. $]);
413             }
414         }
415 
416         static if (!isInfinite!R)
417         {
418             typeof(this) opSlice(size_t low, size_t high)
419             {
420                 return typeof(this)(source[low .. high]);
421             }
422         }
423         else static if (hasEndSlicing)
424         {
425             auto opSlice(size_t low, size_t high)
426             in
427             {
428                 assert(low <= high, "Bounds error when slicing cache.");
429             }
430             body
431             {
432                 import std.range : takeExactly;
433                 return this[low .. $].takeExactly(high - low);
434             }
435         }
436     }
437 }
438 
439 /**
440 $(D auto map(Range)(Range r) if (isInputRange!(Unqual!Range));)
441 
442 Implements the homonym function (also known as $(D transform)) present
443 in many languages of functional flavor. The call $(D map!(fun)(range))
444 returns a range of which elements are obtained by applying $(D fun(a))
445 left to right for all elements $(D a) in $(D range). The original ranges are
446 not changed. Evaluation is done lazily.
447 
448 Params:
449     fun = one or more transformation functions
450     r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
451 
452 Returns:
453     a range with each fun applied to all the elements. If there is more than one
454     fun, the element type will be $(D Tuple) containing one element for each fun.
455 
456 See_Also:
457     $(HTTP en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function))
458 */
459 template map(fun...)
460 if (fun.length >= 1)
461 {
462     auto map(Range)(Range r) if (isInputRange!(Unqual!Range))
463     {
464         import std.meta : AliasSeq, staticMap;
465 
466         alias RE = ElementType!(Range);
467         static if (fun.length > 1)
468         {
469             import std.functional : adjoin;
470             import std.meta : staticIndexOf;
471 
472             alias _funs = staticMap!(unaryFun, fun);
473             alias _fun = adjoin!_funs;
474 
475             // Once DMD issue #5710 is fixed, this validation loop can be moved into a template.
476             foreach (f; _funs)
477             {
478                 static assert(!is(typeof(f(RE.init)) == void),
479                     "Mapping function(s) must not return void: " ~ _funs.stringof);
480             }
481         }
482         else
483         {
484             alias _fun = unaryFun!fun;
485             alias _funs = AliasSeq!(_fun);
486 
487             // Do the validation separately for single parameters due to DMD issue #15777.
488             static assert(!is(typeof(_fun(RE.init)) == void),
489                 "Mapping function(s) must not return void: " ~ _funs.stringof);
490         }
491 
492         return MapResult!(_fun, Range)(r);
493     }
494 }
495 
496 ///
497 @safe unittest
498 {
499     import std.algorithm.comparison : equal;
500     import std.range : chain;
501     int[] arr1 = [ 1, 2, 3, 4 ];
502     int[] arr2 = [ 5, 6 ];
503     auto squares = map!(a => a * a)(chain(arr1, arr2));
504     assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ]));
505 }
506 
507 /**
508 Multiple functions can be passed to $(D map). In that case, the
509 element type of $(D map) is a tuple containing one element for each
510 function.
511 */
512 @safe unittest
513 {
514     auto sums = [2, 4, 6, 8];
515     auto products = [1, 4, 9, 16];
516 
517     size_t i = 0;
518     foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
519     {
520         assert(result[0] == sums[i]);
521         assert(result[1] == products[i]);
522         ++i;
523     }
524 }
525 
526 /**
527 You may alias $(D map) with some function(s) to a symbol and use
528 it separately:
529 */
530 @safe unittest
531 {
532     import std.algorithm.comparison : equal;
533     import std.conv : to;
534 
535     alias stringize = map!(to!string);
536     assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
537 }
538 
539 @safe unittest
540 {
541     // Verify workaround for DMD #15777
542 
543     import std.algorithm.mutation, std..string;
544     auto foo(string[] args)
545     {
546         return args.map!strip;
547     }
548 }
549 
550 private struct MapResult(alias fun, Range)
551 {
552     alias R = Unqual!Range;
553     R _input;
554 
555     static if (isBidirectionalRange!R)
556     {
557         @property auto ref back()()
558         {
559             assert(!empty, "Attempting to fetch the back of an empty map.");
560             return fun(_input.back);
561         }
562 
563         void popBack()()
564         {
565             assert(!empty, "Attempting to popBack an empty map.");
566             _input.popBack();
567         }
568     }
569 
570     this(R input)
571     {
572         _input = input;
573     }
574 
575     static if (isInfinite!R)
576     {
577         // Propagate infinite-ness.
578         enum bool empty = false;
579     }
580     else
581     {
582         @property bool empty()
583         {
584             return _input.empty;
585         }
586     }
587 
588     void popFront()
589     {
590         assert(!empty, "Attempting to popFront an empty map.");
591         _input.popFront();
592     }
593 
594     @property auto ref front()
595     {
596         assert(!empty, "Attempting to fetch the front of an empty map.");
597         return fun(_input.front);
598     }
599 
600     static if (isRandomAccessRange!R)
601     {
602         static if (is(typeof(_input[ulong.max])))
603             private alias opIndex_t = ulong;
604         else
605             private alias opIndex_t = uint;
606 
607         auto ref opIndex(opIndex_t index)
608         {
609             return fun(_input[index]);
610         }
611     }
612 
613     static if (hasLength!R)
614     {
615         @property auto length()
616         {
617             return _input.length;
618         }
619 
620         alias opDollar = length;
621     }
622 
623     static if (hasSlicing!R)
624     {
625         static if (is(typeof(_input[ulong.max .. ulong.max])))
626             private alias opSlice_t = ulong;
627         else
628             private alias opSlice_t = uint;
629 
630         static if (hasLength!R)
631         {
632             auto opSlice(opSlice_t low, opSlice_t high)
633             {
634                 return typeof(this)(_input[low .. high]);
635             }
636         }
637         else static if (is(typeof(_input[opSlice_t.max .. $])))
638         {
639             struct DollarToken{}
640             enum opDollar = DollarToken.init;
641             auto opSlice(opSlice_t low, DollarToken)
642             {
643                 return typeof(this)(_input[low .. $]);
644             }
645 
646             auto opSlice(opSlice_t low, opSlice_t high)
647             {
648                 import std.range : takeExactly;
649                 return this[low .. $].takeExactly(high - low);
650             }
651         }
652     }
653 
654     static if (isForwardRange!R)
655     {
656         @property auto save()
657         {
658             return typeof(this)(_input.save);
659         }
660     }
661 }
662 
663 @safe unittest
664 {
665     import std.algorithm.comparison : equal;
666     import std.conv : to;
667     import std.functional : adjoin;
668 
669     alias stringize = map!(to!string);
670     assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
671 
672     uint counter;
673     alias count = map!((a) { return counter++; });
674     assert(equal(count([ 10, 2, 30, 4 ]), [ 0, 1, 2, 3 ]));
675 
676     counter = 0;
677     adjoin!((a) { return counter++; }, (a) { return counter++; })(1);
678     alias countAndSquare = map!((a) { return counter++; }, (a) { return counter++; });
679     //assert(equal(countAndSquare([ 10, 2 ]), [ tuple(0u, 100), tuple(1u, 4) ]));
680 }
681 
682 @safe unittest
683 {
684     import std.algorithm.comparison : equal;
685     import std.ascii : toUpper;
686     import std.internal.test.dummyrange;
687     import std.range;
688     import std.typecons : tuple;
689 
690     int[] arr1 = [ 1, 2, 3, 4 ];
691     const int[] arr1Const = arr1;
692     int[] arr2 = [ 5, 6 ];
693     auto squares = map!("a * a")(arr1Const);
694     assert(squares[$ - 1] == 16);
695     assert(equal(squares, [ 1, 4, 9, 16 ][]));
696     assert(equal(map!("a * a")(chain(arr1, arr2)), [ 1, 4, 9, 16, 25, 36 ][]));
697 
698     // Test the caching stuff.
699     assert(squares.back == 16);
700     auto squares2 = squares.save;
701     assert(squares2.back == 16);
702 
703     assert(squares2.front == 1);
704     squares2.popFront();
705     assert(squares2.front == 4);
706     squares2.popBack();
707     assert(squares2.front == 4);
708     assert(squares2.back == 9);
709 
710     assert(equal(map!("a * a")(chain(arr1, arr2)), [ 1, 4, 9, 16, 25, 36 ][]));
711 
712     uint i;
713     foreach (e; map!("a", "a * a")(arr1))
714     {
715         assert(e[0] == ++i);
716         assert(e[1] == i * i);
717     }
718 
719     // Test length.
720     assert(squares.length == 4);
721     assert(map!"a * a"(chain(arr1, arr2)).length == 6);
722 
723     // Test indexing.
724     assert(squares[0] == 1);
725     assert(squares[1] == 4);
726     assert(squares[2] == 9);
727     assert(squares[3] == 16);
728 
729     // Test slicing.
730     auto squareSlice = squares[1 .. squares.length - 1];
731     assert(equal(squareSlice, [4, 9][]));
732     assert(squareSlice.back == 9);
733     assert(squareSlice[1] == 9);
734 
735     // Test on a forward range to make sure it compiles when all the fancy
736     // stuff is disabled.
737     auto fibsSquares = map!"a * a"(recurrence!("a[n-1] + a[n-2]")(1, 1));
738     assert(fibsSquares.front == 1);
739     fibsSquares.popFront();
740     fibsSquares.popFront();
741     assert(fibsSquares.front == 4);
742     fibsSquares.popFront();
743     assert(fibsSquares.front == 9);
744 
745     auto repeatMap = map!"a"(repeat(1));
746     static assert(isInfinite!(typeof(repeatMap)));
747 
748     auto intRange = map!"a"([1,2,3]);
749     static assert(isRandomAccessRange!(typeof(intRange)));
750 
751     foreach (DummyType; AllDummyRanges)
752     {
753         DummyType d;
754         auto m = map!"a * a"(d);
755 
756         static assert(propagatesRangeType!(typeof(m), DummyType));
757         assert(equal(m, [1,4,9,16,25,36,49,64,81,100]));
758     }
759 
760     //Test string access
761     string  s1 = "hello world!";
762     dstring s2 = "日本語";
763     dstring s3 = "hello world!"d;
764     auto ms1 = map!(std.ascii.toUpper)(s1);
765     auto ms2 = map!(std.ascii.toUpper)(s2);
766     auto ms3 = map!(std.ascii.toUpper)(s3);
767     static assert(!is(ms1[0])); //narrow strings can't be indexed
768     assert(ms2[0] == '日');
769     assert(ms3[0] == 'H');
770     static assert(!is(ms1[0 .. 1])); //narrow strings can't be sliced
771     assert(equal(ms2[0 .. 2], "日本"w));
772     assert(equal(ms3[0 .. 2], "HE"));
773 
774     // Issue 5753
775     static void voidFun(int) {}
776     static int nonvoidFun(int) { return 0; }
777     static assert(!__traits(compiles, map!voidFun([1])));
778     static assert(!__traits(compiles, map!(voidFun, voidFun)([1])));
779     static assert(!__traits(compiles, map!(nonvoidFun, voidFun)([1])));
780     static assert(!__traits(compiles, map!(voidFun, nonvoidFun)([1])));
781     static assert(!__traits(compiles, map!(a => voidFun(a))([1])));
782 
783     // Phobos issue #15480
784     auto dd = map!(z => z * z, c => c * c * c)([ 1, 2, 3, 4 ]);
785     assert(dd[0] == tuple(1, 1));
786     assert(dd[1] == tuple(4, 8));
787     assert(dd[2] == tuple(9, 27));
788     assert(dd[3] == tuple(16, 64));
789     assert(dd.length == 4);
790 }
791 
792 @safe unittest
793 {
794     import std.algorithm.comparison : equal;
795     import std.range;
796     auto LL = iota(1L, 4L);
797     auto m = map!"a*a"(LL);
798     assert(equal(m, [1L, 4L, 9L]));
799 }
800 
801 @safe unittest
802 {
803     import std.range : iota;
804 
805     // Issue #10130 - map of iota with const step.
806     const step = 2;
807     assert(map!(i => i)(iota(0, 10, step)).walkLength == 5);
808 
809     // Need these to all by const to repro the float case, due to the
810     // CommonType template used in the float specialization of iota.
811     const floatBegin = 0.0;
812     const floatEnd = 1.0;
813     const floatStep = 0.02;
814     assert(map!(i => i)(iota(floatBegin, floatEnd, floatStep)).walkLength == 50);
815 }
816 
817 @safe unittest
818 {
819     import std.algorithm.comparison : equal;
820     import std.range;
821     //slicing infinites
822     auto rr = iota(0, 5).cycle().map!"a * a"();
823     alias RR = typeof(rr);
824     static assert(hasSlicing!RR);
825     rr = rr[6 .. $]; //Advances 1 cycle and 1 unit
826     assert(equal(rr[0 .. 5], [1, 4, 9, 16, 0]));
827 }
828 
829 @safe unittest
830 {
831     import std.range;
832     struct S {int* p;}
833     auto m = immutable(S).init.repeat().map!"a".save;
834 }
835 
836 // each
837 /**
838 Eagerly iterates over $(D r) and calls $(D pred) over _each element.
839 
840 If no predicate is specified, $(D each) will default to doing nothing
841 but consuming the entire range. $(D .front) will be evaluated, but this
842 can be avoided by explicitly specifying a predicate lambda with a
843 $(D lazy) parameter.
844 
845 $(D each) also supports $(D opApply)-based iterators, so it will work
846 with e.g. $(REF parallel, std,parallelism).
847 
848 Params:
849     pred = predicate to apply to each element of the range
850     r = range or iterable over which each iterates
851 
852 See_Also: $(REF tee, std,range)
853 
854  */
855 template each(alias pred = "a")
856 {
857     import std.meta : AliasSeq;
858     import std.traits : Parameters;
859 
860 private:
861     alias BinaryArgs = AliasSeq!(pred, "i", "a");
862 
863     enum isRangeUnaryIterable(R) =
864         is(typeof(unaryFun!pred(R.init.front)));
865 
866     enum isRangeBinaryIterable(R) =
867         is(typeof(binaryFun!BinaryArgs(0, R.init.front)));
868 
869     enum isRangeIterable(R) =
870         isInputRange!R &&
871         (isRangeUnaryIterable!R || isRangeBinaryIterable!R);
872 
873     enum isForeachUnaryIterable(R) =
874         is(typeof((R r) {
875             foreach (ref a; r)
876                 cast(void) unaryFun!pred(a);
877         }));
878 
879     enum isForeachBinaryIterable(R) =
880         is(typeof((R r) {
881             foreach (ref i, ref a; r)
882                 cast(void) binaryFun!BinaryArgs(i, a);
883         }));
884 
885     enum isForeachIterable(R) =
886         (!isForwardRange!R || isDynamicArray!R) &&
887         (isForeachUnaryIterable!R || isForeachBinaryIterable!R);
888 
889 public:
890     void each(Range)(Range r)
891     if (!isForeachIterable!Range && (
892         isRangeIterable!Range ||
893         __traits(compiles, typeof(r.front).length)))
894     {
895         static if (isRangeIterable!Range)
896         {
897             debug(each) pragma(msg, "Using while for ", Range.stringof);
898             static if (isRangeUnaryIterable!Range)
899             {
900                 while (!r.empty)
901                 {
902                     cast(void) unaryFun!pred(r.front);
903                     r.popFront();
904                 }
905             }
906             else // if (isRangeBinaryIterable!Range)
907             {
908                 size_t i = 0;
909                 while (!r.empty)
910                 {
911                     cast(void) binaryFun!BinaryArgs(i, r.front);
912                     r.popFront();
913                     i++;
914                 }
915             }
916         }
917         else
918         {
919             // range interface with >2 parameters.
920             for (auto range = r; !range.empty; range.popFront())
921                 pred(range.front.expand);
922         }
923     }
924 
925     void each(Iterable)(auto ref Iterable r)
926     if (isForeachIterable!Iterable ||
927         __traits(compiles, Parameters!(Parameters!(r.opApply))))
928     {
929         static if (isForeachIterable!Iterable)
930         {
931             debug(each) pragma(msg, "Using foreach for ", Iterable.stringof);
932             static if (isForeachUnaryIterable!Iterable)
933             {
934                 foreach (ref e; r)
935                     cast(void) unaryFun!pred(e);
936             }
937             else // if (isForeachBinaryIterable!Iterable)
938             {
939                 foreach (ref i, ref e; r)
940                     cast(void) binaryFun!BinaryArgs(i, e);
941             }
942         }
943         else
944         {
945             // opApply with >2 parameters. count the delegate args.
946             // only works if it is not templated (otherwise we cannot count the args)
947             auto dg(Parameters!(Parameters!(r.opApply)) params) {
948                 pred(params);
949                 return 0; // tells opApply to continue iteration
950             }
951             r.opApply(&dg);
952         }
953     }
954 }
955 
956 ///
957 @system unittest
958 {
959     import std.range : iota;
960 
961     long[] arr;
962     iota(5).each!(n => arr ~= n);
963     assert(arr == [0, 1, 2, 3, 4]);
964 
965     // If the range supports it, the value can be mutated in place
966     arr.each!((ref n) => n++);
967     assert(arr == [1, 2, 3, 4, 5]);
968 
969     arr.each!"a++";
970     assert(arr == [2, 3, 4, 5, 6]);
971 
972     // by-ref lambdas are not allowed for non-ref ranges
973     static assert(!is(typeof(arr.map!(n => n).each!((ref n) => n++))));
974 
975     // The default predicate consumes the range
976     auto m = arr.map!(n => n);
977     (&m).each();
978     assert(m.empty);
979 
980     // Indexes are also available for in-place mutations
981     arr[] = 0;
982     arr.each!"a=i"();
983     assert(arr == [0, 1, 2, 3, 4]);
984 
985     // opApply iterators work as well
986     static class S
987     {
988         int x;
989         int opApply(scope int delegate(ref int _x) dg) { return dg(x); }
990     }
991 
992     auto s = new S;
993     s.each!"a++";
994     assert(s.x == 1);
995 }
996 
997 // binary foreach with two ref args
998 @system unittest
999 {
1000     import std.range : lockstep;
1001 
1002     auto a = [ 1, 2, 3 ];
1003     auto b = [ 2, 3, 4 ];
1004 
1005     a.lockstep(b).each!((ref x, ref y) { ++x; ++y; });
1006 
1007     assert(a == [ 2, 3, 4 ]);
1008     assert(b == [ 3, 4, 5 ]);
1009 }
1010 
1011 // #15358: application of `each` with >2 args (opApply)
1012 @system unittest
1013 {
1014     import std.range : lockstep;
1015     auto a = [0,1,2];
1016     auto b = [3,4,5];
1017     auto c = [6,7,8];
1018 
1019     lockstep(a, b, c).each!((ref x, ref y, ref z) { ++x; ++y; ++z; });
1020 
1021     assert(a == [1,2,3]);
1022     assert(b == [4,5,6]);
1023     assert(c == [7,8,9]);
1024 }
1025 
1026 // #15358: application of `each` with >2 args (range interface)
1027 @safe unittest
1028 {
1029     import std.range : zip;
1030     auto a = [0,1,2];
1031     auto b = [3,4,5];
1032     auto c = [6,7,8];
1033 
1034     int[] res;
1035 
1036     zip(a, b, c).each!((x, y, z) { res ~= x + y + z; });
1037 
1038     assert(res == [9, 12, 15]);
1039 }
1040 
1041 // #16255: `each` on opApply doesn't support ref
1042 @safe unittest
1043 {
1044     int[] dynamicArray = [1, 2, 3, 4, 5];
1045     int[5] staticArray = [1, 2, 3, 4, 5];
1046 
1047     dynamicArray.each!((ref x) => x++);
1048     assert(dynamicArray == [2, 3, 4, 5, 6]);
1049 
1050     staticArray.each!((ref x) => x++);
1051     assert(staticArray == [2, 3, 4, 5, 6]);
1052 
1053     staticArray[].each!((ref x) => x++);
1054     assert(staticArray == [3, 4, 5, 6, 7]);
1055 }
1056 
1057 // #16255: `each` on opApply doesn't support ref
1058 @system unittest
1059 {
1060     struct S
1061     {
1062        int x;
1063        int opApply(int delegate(ref int _x) dg) { return dg(x); }
1064     }
1065 
1066     S s;
1067     foreach (ref a; s) ++a;
1068     assert(s.x == 1);
1069     s.each!"++a";
1070     assert(s.x == 2);
1071 }
1072 
1073 // filter
1074 /**
1075 $(D auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));)
1076 
1077 Implements the higher order _filter function. The predicate is passed to
1078 $(REF unaryFun, std,functional), and can either accept a string, or any callable
1079 that can be executed via $(D pred(element)).
1080 
1081 Params:
1082     predicate = Function to apply to each element of range
1083     range = Input range of elements
1084 
1085 Returns:
1086     $(D filter!(predicate)(range)) returns a new range containing only elements $(D x) in $(D range) for
1087     which $(D predicate(x)) returns $(D true).
1088 
1089 See_Also:
1090     $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function))
1091  */
1092 template filter(alias predicate)
1093 if (is(typeof(unaryFun!predicate)))
1094 {
1095     auto filter(Range)(Range range) if (isInputRange!(Unqual!Range))
1096     {
1097         return FilterResult!(unaryFun!predicate, Range)(range);
1098     }
1099 }
1100 
1101 ///
1102 @safe unittest
1103 {
1104     import std.algorithm.comparison : equal;
1105     import std.math : approxEqual;
1106     import std.range;
1107 
1108     int[] arr = [ 1, 2, 3, 4, 5 ];
1109 
1110     // Sum all elements
1111     auto small = filter!(a => a < 3)(arr);
1112     assert(equal(small, [ 1, 2 ]));
1113 
1114     // Sum again, but with Uniform Function Call Syntax (UFCS)
1115     auto sum = arr.filter!(a => a < 3);
1116     assert(equal(sum, [ 1, 2 ]));
1117 
1118     // In combination with chain() to span multiple ranges
1119     int[] a = [ 3, -2, 400 ];
1120     int[] b = [ 100, -101, 102 ];
1121     auto r = chain(a, b).filter!(a => a > 0);
1122     assert(equal(r, [ 3, 400, 100, 102 ]));
1123 
1124     // Mixing convertible types is fair game, too
1125     double[] c = [ 2.5, 3.0 ];
1126     auto r1 = chain(c, a, b).filter!(a => cast(int) a != a);
1127     assert(approxEqual(r1, [ 2.5 ]));
1128 }
1129 
1130 private struct FilterResult(alias pred, Range)
1131 {
1132     alias R = Unqual!Range;
1133     R _input;
1134     private bool _primed;
1135 
1136     private void prime()
1137     {
1138         if (_primed) return;
1139         while (!_input.empty && !pred(_input.front))
1140         {
1141             _input.popFront();
1142         }
1143         _primed = true;
1144     }
1145 
1146     this(R r)
1147     {
1148         _input = r;
1149     }
1150 
1151     private this(R r, bool primed)
1152     {
1153         _input = r;
1154         _primed = primed;
1155     }
1156 
1157     auto opSlice() { return this; }
1158 
1159     static if (isInfinite!Range)
1160     {
1161         enum bool empty = false;
1162     }
1163     else
1164     {
1165         @property bool empty() { prime; return _input.empty; }
1166     }
1167 
1168     void popFront()
1169     {
1170         do
1171         {
1172             _input.popFront();
1173         } while (!_input.empty && !pred(_input.front));
1174         _primed = true;
1175     }
1176 
1177     @property auto ref front()
1178     {
1179         prime;
1180         assert(!empty, "Attempting to fetch the front of an empty filter.");
1181         return _input.front;
1182     }
1183 
1184     static if (isForwardRange!R)
1185     {
1186         @property auto save()
1187         {
1188             return typeof(this)(_input.save, _primed);
1189         }
1190     }
1191 }
1192 
1193 @safe unittest
1194 {
1195     import std.algorithm.comparison : equal;
1196     import std.internal.test.dummyrange;
1197     import std.range;
1198 
1199     auto shouldNotLoop4ever = repeat(1).filter!(x => x % 2 == 0);
1200 
1201     int[] a = [ 3, 4, 2 ];
1202     auto r = filter!("a > 3")(a);
1203     static assert(isForwardRange!(typeof(r)));
1204     assert(equal(r, [ 4 ][]));
1205 
1206     a = [ 1, 22, 3, 42, 5 ];
1207     auto under10 = filter!("a < 10")(a);
1208     assert(equal(under10, [1, 3, 5][]));
1209     static assert(isForwardRange!(typeof(under10)));
1210     under10.front = 4;
1211     assert(equal(under10, [4, 3, 5][]));
1212     under10.front = 40;
1213     assert(equal(under10, [40, 3, 5][]));
1214     under10.front = 1;
1215 
1216     auto infinite = filter!"a > 2"(repeat(3));
1217     static assert(isInfinite!(typeof(infinite)));
1218     static assert(isForwardRange!(typeof(infinite)));
1219 
1220     foreach (DummyType; AllDummyRanges)
1221     {
1222         DummyType d;
1223         auto f = filter!"a & 1"(d);
1224         assert(equal(f, [1,3,5,7,9]));
1225 
1226         static if (isForwardRange!DummyType)
1227         {
1228             static assert(isForwardRange!(typeof(f)));
1229         }
1230     }
1231 
1232     // With delegates
1233     int x = 10;
1234     int overX(int a) { return a > x; }
1235     typeof(filter!overX(a)) getFilter()
1236     {
1237         return filter!overX(a);
1238     }
1239     auto r1 = getFilter();
1240     assert(equal(r1, [22, 42]));
1241 
1242     // With chain
1243     auto nums = [0,1,2,3,4];
1244     assert(equal(filter!overX(chain(a, nums)), [22, 42]));
1245 
1246     // With copying of inner struct Filter to Map
1247     auto arr = [1,2,3,4,5];
1248     auto m = map!"a + 1"(filter!"a < 4"(arr));
1249 }
1250 
1251 @safe unittest
1252 {
1253     import std.algorithm.comparison : equal;
1254 
1255     int[] a = [ 3, 4 ];
1256     const aConst = a;
1257     auto r = filter!("a > 3")(aConst);
1258     assert(equal(r, [ 4 ][]));
1259 
1260     a = [ 1, 22, 3, 42, 5 ];
1261     auto under10 = filter!("a < 10")(a);
1262     assert(equal(under10, [1, 3, 5][]));
1263     assert(equal(under10.save, [1, 3, 5][]));
1264     assert(equal(under10.save, under10));
1265 
1266     // With copying of inner struct Filter to Map
1267     auto arr = [1,2,3,4,5];
1268     auto m = map!"a + 1"(filter!"a < 4"(arr));
1269 }
1270 
1271 @safe unittest
1272 {
1273     import std.algorithm.comparison : equal;
1274     import std.functional : compose, pipe;
1275 
1276     assert(equal(compose!(map!"2 * a", filter!"a & 1")([1,2,3,4,5]),
1277                     [2,6,10]));
1278     assert(equal(pipe!(filter!"a & 1", map!"2 * a")([1,2,3,4,5]),
1279             [2,6,10]));
1280 }
1281 
1282 @safe unittest
1283 {
1284     import std.algorithm.comparison : equal;
1285 
1286     int x = 10;
1287     int underX(int a) { return a < x; }
1288     const(int)[] list = [ 1, 2, 10, 11, 3, 4 ];
1289     assert(equal(filter!underX(list), [ 1, 2, 3, 4 ]));
1290 }
1291 
1292 /**
1293  * $(D auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range));)
1294  *
1295  * Similar to $(D filter), except it defines a
1296  * $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives).
1297  * There is a speed disadvantage - the constructor spends time
1298  * finding the last element in the range that satisfies the filtering
1299  * condition (in addition to finding the first one). The advantage is
1300  * that the filtered range can be spanned from both directions. Also,
1301  * $(REF retro, std,range) can be applied against the filtered range.
1302  *
1303  * The predicate is passed to $(REF unaryFun, std,functional), and can either
1304  * accept a string, or any callable that can be executed via $(D pred(element)).
1305  *
1306  * Params:
1307  *     pred = Function to apply to each element of range
1308  *     r = Bidirectional range of elements
1309  *
1310  * Returns:
1311  *     a new range containing only the elements in r for which pred returns $(D true).
1312  */
1313 template filterBidirectional(alias pred)
1314 {
1315     auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range))
1316     {
1317         return FilterBidiResult!(unaryFun!pred, Range)(r);
1318     }
1319 }
1320 
1321 ///
1322 @safe unittest
1323 {
1324     import std.algorithm.comparison : equal;
1325     import std.range;
1326 
1327     int[] arr = [ 1, 2, 3, 4, 5 ];
1328     auto small = filterBidirectional!("a < 3")(arr);
1329     static assert(isBidirectionalRange!(typeof(small)));
1330     assert(small.back == 2);
1331     assert(equal(small, [ 1, 2 ]));
1332     assert(equal(retro(small), [ 2, 1 ]));
1333     // In combination with chain() to span multiple ranges
1334     int[] a = [ 3, -2, 400 ];
1335     int[] b = [ 100, -101, 102 ];
1336     auto r = filterBidirectional!("a > 0")(chain(a, b));
1337     assert(r.back == 102);
1338 }
1339 
1340 private struct FilterBidiResult(alias pred, Range)
1341 {
1342     alias R = Unqual!Range;
1343     R _input;
1344 
1345     this(R r)
1346     {
1347         _input = r;
1348         while (!_input.empty && !pred(_input.front)) _input.popFront();
1349         while (!_input.empty && !pred(_input.back)) _input.popBack();
1350     }
1351 
1352     @property bool empty() { return _input.empty; }
1353 
1354     void popFront()
1355     {
1356         do
1357         {
1358             _input.popFront();
1359         } while (!_input.empty && !pred(_input.front));
1360     }
1361 
1362     @property auto ref front()
1363     {
1364         assert(!empty, "Attempting to fetch the front of an empty filterBidirectional.");
1365         return _input.front;
1366     }
1367 
1368     void popBack()
1369     {
1370         do
1371         {
1372             _input.popBack();
1373         } while (!_input.empty && !pred(_input.back));
1374     }
1375 
1376     @property auto ref back()
1377     {
1378         assert(!empty, "Attempting to fetch the back of an empty filterBidirectional.");
1379         return _input.back;
1380     }
1381 
1382     @property auto save()
1383     {
1384         return typeof(this)(_input.save);
1385     }
1386 }
1387 
1388 /**
1389 Groups consecutively equivalent elements into a single tuple of the element and
1390 the number of its repetitions.
1391 
1392 Similarly to $(D uniq), $(D group) produces a range that iterates over unique
1393 consecutive elements of the given range. Each element of this range is a tuple
1394 of the element and the number of times it is repeated in the original range.
1395 Equivalence of elements is assessed by using the predicate $(D pred), which
1396 defaults to $(D "a == b").  The predicate is passed to $(REF binaryFun, std,functional),
1397 and can either accept a string, or any callable that can be executed via
1398 $(D pred(element, element)).
1399 
1400 Params:
1401     pred = Binary predicate for determining equivalence of two elements.
1402     r = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
1403         iterate over.
1404 
1405 Returns: A range of elements of type $(D Tuple!(ElementType!R, uint)),
1406 representing each consecutively unique element and its respective number of
1407 occurrences in that run.  This will be an input range if $(D R) is an input
1408 range, and a forward range in all other cases.
1409 
1410 See_Also: $(LREF chunkBy), which chunks an input range into subranges
1411     of equivalent adjacent elements.
1412 */
1413 Group!(pred, Range) group(alias pred = "a == b", Range)(Range r)
1414 {
1415     return typeof(return)(r);
1416 }
1417 
1418 /// ditto
1419 struct Group(alias pred, R)
1420 if (isInputRange!R)
1421 {
1422     import std.typecons : Rebindable, tuple, Tuple;
1423 
1424     private alias comp = binaryFun!pred;
1425 
1426     private alias E = ElementType!R;
1427     static if ((is(E == class) || is(E == interface)) &&
1428                (is(E == const) || is(E == immutable)))
1429     {
1430         private alias MutableE = Rebindable!E;
1431     }
1432     else static if (is(E : Unqual!E))
1433     {
1434         private alias MutableE = Unqual!E;
1435     }
1436     else
1437     {
1438         private alias MutableE = E;
1439     }
1440 
1441     private R _input;
1442     private Tuple!(MutableE, uint) _current;
1443 
1444     ///
1445     this(R input)
1446     {
1447         _input = input;
1448         if (!_input.empty) popFront();
1449     }
1450 
1451     ///
1452     void popFront()
1453     {
1454         if (_input.empty)
1455         {
1456             _current[1] = 0;
1457         }
1458         else
1459         {
1460             _current = tuple(_input.front, 1u);
1461             _input.popFront();
1462             while (!_input.empty && comp(_current[0], _input.front))
1463             {
1464                 ++_current[1];
1465                 _input.popFront();
1466             }
1467         }
1468     }
1469 
1470     static if (isInfinite!R)
1471     {
1472         ///
1473         enum bool empty = false;  // Propagate infiniteness.
1474     }
1475     else
1476     {
1477         ///
1478         @property bool empty()
1479         {
1480             return _current[1] == 0;
1481         }
1482     }
1483 
1484     ///
1485     @property auto ref front()
1486     {
1487         assert(!empty, "Attempting to fetch the front of an empty Group.");
1488         return _current;
1489     }
1490 
1491     static if (isForwardRange!R)
1492     {
1493         ///
1494         @property typeof(this) save() {
1495             typeof(this) ret = this;
1496             ret._input = this._input.save;
1497             ret._current = this._current;
1498             return ret;
1499         }
1500     }
1501 }
1502 
1503 ///
1504 @safe unittest
1505 {
1506     import std.algorithm.comparison : equal;
1507     import std.typecons : tuple, Tuple;
1508 
1509     int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
1510     assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u),
1511         tuple(4, 3u), tuple(5, 1u) ][]));
1512 }
1513 
1514 /**
1515  * Using group, an associative array can be easily generated with the count of each
1516  * unique element in the range.
1517  */
1518 @safe unittest
1519 {
1520     import std.algorithm.sorting : sort;
1521     import std.array : assocArray;
1522 
1523     uint[string] result;
1524     auto range = ["a", "b", "a", "c", "b", "c", "c", "d", "e"];
1525     result = range.sort!((a, b) => a < b)
1526         .group
1527         .assocArray;
1528 
1529     assert(result == ["a": 2U, "b": 2U, "c": 3U, "d": 1U, "e": 1U]);
1530 }
1531 
1532 @safe unittest
1533 {
1534     import std.algorithm.comparison : equal;
1535     import std.internal.test.dummyrange;
1536     import std.typecons : tuple, Tuple;
1537 
1538     int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
1539     assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u),
1540                             tuple(4, 3u), tuple(5, 1u) ][]));
1541     static assert(isForwardRange!(typeof(group(arr))));
1542 
1543     foreach (DummyType; AllDummyRanges)
1544     {
1545         DummyType d;
1546         auto g = group(d);
1547 
1548         static assert(d.rt == RangeType.Input || isForwardRange!(typeof(g)));
1549 
1550         assert(equal(g, [tuple(1, 1u), tuple(2, 1u), tuple(3, 1u), tuple(4, 1u),
1551             tuple(5, 1u), tuple(6, 1u), tuple(7, 1u), tuple(8, 1u),
1552             tuple(9, 1u), tuple(10, 1u)]));
1553     }
1554 }
1555 
1556 @safe unittest
1557 {
1558     // Issue 13857
1559     immutable(int)[] a1 = [1,1,2,2,2,3,4,4,5,6,6,7,8,9,9,9];
1560     auto g1 = group(a1);
1561 
1562     // Issue 13162
1563     immutable(ubyte)[] a2 = [1, 1, 1, 0, 0, 0];
1564     auto g2 = a2.group;
1565 
1566     // Issue 10104
1567     const a3 = [1, 1, 2, 2];
1568     auto g3 = a3.group;
1569 
1570     interface I {}
1571     class C : I {}
1572     const C[] a4 = [new const C()];
1573     auto g4 = a4.group!"a is b";
1574 
1575     immutable I[] a5 = [new immutable C()];
1576     auto g5 = a5.group!"a is b";
1577 
1578     const(int[][]) a6 = [[1], [1]];
1579     auto g6 = a6.group;
1580 }
1581 
1582 // Used by implementation of chunkBy for non-forward input ranges.
1583 private struct ChunkByChunkImpl(alias pred, Range)
1584 if (isInputRange!Range && !isForwardRange!Range)
1585 {
1586     alias fun = binaryFun!pred;
1587 
1588     private Range r;
1589     private ElementType!Range prev;
1590 
1591     this(Range range, ElementType!Range _prev)
1592     {
1593         r = range;
1594         prev = _prev;
1595     }
1596 
1597     @property bool empty()
1598     {
1599         return r.empty || !fun(prev, r.front);
1600     }
1601 
1602     @property ElementType!Range front() { return r.front; }
1603     void popFront() { r.popFront(); }
1604 }
1605 
1606 private template ChunkByImplIsUnary(alias pred, Range)
1607 {
1608     static if (is(typeof(binaryFun!pred(ElementType!Range.init,
1609                                         ElementType!Range.init)) : bool))
1610         enum ChunkByImplIsUnary = false;
1611     else static if (is(typeof(
1612             unaryFun!pred(ElementType!Range.init) ==
1613             unaryFun!pred(ElementType!Range.init))))
1614         enum ChunkByImplIsUnary = true;
1615     else
1616         static assert(0, "chunkBy expects either a binary predicate or "~
1617                          "a unary predicate on range elements of type: "~
1618                          ElementType!Range.stringof);
1619 }
1620 
1621 // Implementation of chunkBy for non-forward input ranges.
1622 private struct ChunkByImpl(alias pred, Range)
1623 if (isInputRange!Range && !isForwardRange!Range)
1624 {
1625     enum bool isUnary = ChunkByImplIsUnary!(pred, Range);
1626 
1627     static if (isUnary)
1628         alias eq = binaryFun!((a, b) => unaryFun!pred(a) == unaryFun!pred(b));
1629     else
1630         alias eq = binaryFun!pred;
1631 
1632     private Range r;
1633     private ElementType!Range _prev;
1634 
1635     this(Range _r)
1636     {
1637         r = _r;
1638         if (!empty)
1639         {
1640             // Check reflexivity if predicate is claimed to be an equivalence
1641             // relation.
1642             assert(eq(r.front, r.front),
1643                    "predicate is not reflexive");
1644 
1645             // _prev's type may be a nested struct, so must be initialized
1646             // directly in the constructor (cannot call savePred()).
1647             _prev = r.front;
1648         }
1649         else
1650         {
1651             // We won't use _prev, but must be initialized.
1652             _prev = typeof(_prev).init;
1653         }
1654     }
1655     @property bool empty() { return r.empty; }
1656 
1657     @property auto front()
1658     {
1659         static if (isUnary)
1660         {
1661             import std.typecons : tuple;
1662             return tuple(unaryFun!pred(_prev),
1663                          ChunkByChunkImpl!(eq, Range)(r, _prev));
1664         }
1665         else
1666         {
1667             return ChunkByChunkImpl!(eq, Range)(r, _prev);
1668         }
1669     }
1670 
1671     void popFront()
1672     {
1673         while (!r.empty)
1674         {
1675             if (!eq(_prev, r.front))
1676             {
1677                 _prev = r.front;
1678                 break;
1679             }
1680             r.popFront();
1681         }
1682     }
1683 }
1684 
1685 // Single-pass implementation of chunkBy for forward ranges.
1686 private struct ChunkByImpl(alias pred, Range)
1687 if (isForwardRange!Range)
1688 {
1689     import std.typecons : RefCounted;
1690 
1691     enum bool isUnary = ChunkByImplIsUnary!(pred, Range);
1692 
1693     static if (isUnary)
1694         alias eq = binaryFun!((a, b) => unaryFun!pred(a) == unaryFun!pred(b));
1695     else
1696         alias eq = binaryFun!pred;
1697 
1698     // Outer range
1699     static struct Impl
1700     {
1701         size_t groupNum;
1702         Range  current;
1703         Range  next;
1704     }
1705 
1706     // Inner range
1707     static struct Group
1708     {
1709         private size_t groupNum;
1710         private Range  start;
1711         private Range  current;
1712 
1713         private RefCounted!Impl mothership;
1714 
1715         this(RefCounted!Impl origin)
1716         {
1717             groupNum = origin.groupNum;
1718 
1719             start = origin.current.save;
1720             current = origin.current.save;
1721             assert(!start.empty);
1722 
1723             mothership = origin;
1724 
1725             // Note: this requires reflexivity.
1726             assert(eq(start.front, current.front),
1727                    "predicate is not reflexive");
1728         }
1729 
1730         @property bool empty() { return groupNum == size_t.max; }
1731         @property auto ref front() { return current.front; }
1732 
1733         void popFront()
1734         {
1735             current.popFront();
1736 
1737             // Note: this requires transitivity.
1738             if (current.empty || !eq(start.front, current.front))
1739             {
1740                 if (groupNum == mothership.groupNum)
1741                 {
1742                     // If parent range hasn't moved on yet, help it along by
1743                     // saving location of start of next Group.
1744                     mothership.next = current.save;
1745                 }
1746 
1747                 groupNum = size_t.max;
1748             }
1749         }
1750 
1751         @property auto save()
1752         {
1753             auto copy = this;
1754             copy.current = current.save;
1755             return copy;
1756         }
1757     }
1758     static assert(isForwardRange!Group);
1759 
1760     private RefCounted!Impl impl;
1761 
1762     this(Range r)
1763     {
1764         impl = RefCounted!Impl(0, r, r.save);
1765     }
1766 
1767     @property bool empty() { return impl.current.empty; }
1768 
1769     @property auto front()
1770     {
1771         static if (isUnary)
1772         {
1773             import std.typecons : tuple;
1774             return tuple(unaryFun!pred(impl.current.front), Group(impl));
1775         }
1776         else
1777         {
1778             return Group(impl);
1779         }
1780     }
1781 
1782     void popFront()
1783     {
1784         // Scan for next group. If we're lucky, one of our Groups would have
1785         // already set .next to the start of the next group, in which case the
1786         // loop is skipped.
1787         while (!impl.next.empty && eq(impl.current.front, impl.next.front))
1788         {
1789             impl.next.popFront();
1790         }
1791 
1792         impl.current = impl.next.save;
1793 
1794         // Indicate to any remaining Groups that we have moved on.
1795         impl.groupNum++;
1796     }
1797 
1798     @property auto save()
1799     {
1800         // Note: the new copy of the range will be detached from any existing
1801         // satellite Groups, and will not benefit from the .next acceleration.
1802         return typeof(this)(impl.current.save);
1803     }
1804 
1805     static assert(isForwardRange!(typeof(this)));
1806 }
1807 
1808 @system unittest
1809 {
1810     import std.algorithm.comparison : equal;
1811 
1812     size_t popCount = 0;
1813     class RefFwdRange
1814     {
1815         int[]  impl;
1816 
1817         @safe nothrow:
1818 
1819         this(int[] data) { impl = data; }
1820         @property bool empty() { return impl.empty; }
1821         @property auto ref front() { return impl.front; }
1822         void popFront()
1823         {
1824             impl.popFront();
1825             popCount++;
1826         }
1827         @property auto save() { return new RefFwdRange(impl); }
1828     }
1829     static assert(isForwardRange!RefFwdRange);
1830 
1831     auto testdata = new RefFwdRange([1, 3, 5, 2, 4, 7, 6, 8, 9]);
1832     auto groups = testdata.chunkBy!((a,b) => (a % 2) == (b % 2));
1833     auto outerSave1 = groups.save;
1834 
1835     // Sanity test
1836     assert(groups.equal!equal([[1, 3, 5], [2, 4], [7], [6, 8], [9]]));
1837     assert(groups.empty);
1838 
1839     // Performance test for single-traversal use case: popFront should not have
1840     // been called more times than there are elements if we traversed the
1841     // segmented range exactly once.
1842     assert(popCount == 9);
1843 
1844     // Outer range .save test
1845     groups = outerSave1.save;
1846     assert(!groups.empty);
1847 
1848     // Inner range .save test
1849     auto grp1 = groups.front.save;
1850     auto grp1b = grp1.save;
1851     assert(grp1b.equal([1, 3, 5]));
1852     assert(grp1.save.equal([1, 3, 5]));
1853 
1854     // Inner range should remain consistent after outer range has moved on.
1855     groups.popFront();
1856     assert(grp1.save.equal([1, 3, 5]));
1857 
1858     // Inner range should not be affected by subsequent inner ranges.
1859     assert(groups.front.equal([2, 4]));
1860     assert(grp1.save.equal([1, 3, 5]));
1861 }
1862 
1863 /**
1864  * Chunks an input range into subranges of equivalent adjacent elements.
1865  * In other languages this is often called `partitionBy`, `groupBy`
1866  * or `sliceWhen`.
1867  *
1868  * Equivalence is defined by the predicate $(D pred), which can be either
1869  * binary, which is passed to $(REF binaryFun, std,functional), or unary, which is
1870  * passed to $(REF unaryFun, std,functional). In the binary form, two _range elements
1871  * $(D a) and $(D b) are considered equivalent if $(D pred(a,b)) is true. In
1872  * unary form, two elements are considered equivalent if $(D pred(a) == pred(b))
1873  * is true.
1874  *
1875  * This predicate must be an equivalence relation, that is, it must be
1876  * reflexive ($(D pred(x,x)) is always true), symmetric
1877  * ($(D pred(x,y) == pred(y,x))), and transitive ($(D pred(x,y) && pred(y,z))
1878  * implies $(D pred(x,z))). If this is not the case, the range returned by
1879  * chunkBy may assert at runtime or behave erratically.
1880  *
1881  * Params:
1882  *  pred = Predicate for determining equivalence.
1883  *  r = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be chunked.
1884  *
1885  * Returns: With a binary predicate, a range of ranges is returned in which
1886  * all elements in a given subrange are equivalent under the given predicate.
1887  * With a unary predicate, a range of tuples is returned, with the tuple
1888  * consisting of the result of the unary predicate for each subrange, and the
1889  * subrange itself.
1890  *
1891  * Notes:
1892  *
1893  * Equivalent elements separated by an intervening non-equivalent element will
1894  * appear in separate subranges; this function only considers adjacent
1895  * equivalence. Elements in the subranges will always appear in the same order
1896  * they appear in the original range.
1897  *
1898  * See_also:
1899  * $(LREF group), which collapses adjacent equivalent elements into a single
1900  * element.
1901  */
1902 auto chunkBy(alias pred, Range)(Range r)
1903 if (isInputRange!Range)
1904 {
1905     return ChunkByImpl!(pred, Range)(r);
1906 }
1907 
1908 /// Showing usage with binary predicate:
1909 /*FIXME: @safe*/ @system unittest
1910 {
1911     import std.algorithm.comparison : equal;
1912 
1913     // Grouping by particular attribute of each element:
1914     auto data = [
1915         [1, 1],
1916         [1, 2],
1917         [2, 2],
1918         [2, 3]
1919     ];
1920 
1921     auto r1 = data.chunkBy!((a,b) => a[0] == b[0]);
1922     assert(r1.equal!equal([
1923         [[1, 1], [1, 2]],
1924         [[2, 2], [2, 3]]
1925     ]));
1926 
1927     auto r2 = data.chunkBy!((a,b) => a[1] == b[1]);
1928     assert(r2.equal!equal([
1929         [[1, 1]],
1930         [[1, 2], [2, 2]],
1931         [[2, 3]]
1932     ]));
1933 }
1934 
1935 version(none) // this example requires support for non-equivalence relations
1936 @safe unittest
1937 {
1938     auto data = [
1939         [1, 1],
1940         [1, 2],
1941         [2, 2],
1942         [2, 3]
1943     ];
1944 
1945     version(none)
1946     {
1947         // Grouping by maximum adjacent difference:
1948         import std.math : abs;
1949         auto r3 = [1, 3, 2, 5, 4, 9, 10].chunkBy!((a, b) => abs(a-b) < 3);
1950         assert(r3.equal!equal([
1951             [1, 3, 2],
1952             [5, 4],
1953             [9, 10]
1954         ]));
1955     }
1956 }
1957 
1958 /// Showing usage with unary predicate:
1959 /* FIXME: pure @safe nothrow*/ @system unittest
1960 {
1961     import std.algorithm.comparison : equal;
1962     import std.range.primitives;
1963     import std.typecons : tuple;
1964 
1965     // Grouping by particular attribute of each element:
1966     auto range =
1967     [
1968         [1, 1],
1969         [1, 1],
1970         [1, 2],
1971         [2, 2],
1972         [2, 3],
1973         [2, 3],
1974         [3, 3]
1975     ];
1976 
1977     auto byX = chunkBy!(a => a[0])(range);
1978     auto expected1 =
1979     [
1980         tuple(1, [[1, 1], [1, 1], [1, 2]]),
1981         tuple(2, [[2, 2], [2, 3], [2, 3]]),
1982         tuple(3, [[3, 3]])
1983     ];
1984     foreach (e; byX)
1985     {
1986         assert(!expected1.empty);
1987         assert(e[0] == expected1.front[0]);
1988         assert(e[1].equal(expected1.front[1]));
1989         expected1.popFront();
1990     }
1991 
1992     auto byY = chunkBy!(a => a[1])(range);
1993     auto expected2 =
1994     [
1995         tuple(1, [[1, 1], [1, 1]]),
1996         tuple(2, [[1, 2], [2, 2]]),
1997         tuple(3, [[2, 3], [2, 3], [3, 3]])
1998     ];
1999     foreach (e; byY)
2000     {
2001         assert(!expected2.empty);
2002         assert(e[0] == expected2.front[0]);
2003         assert(e[1].equal(expected2.front[1]));
2004         expected2.popFront();
2005     }
2006 }
2007 
2008 /*FIXME: pure @safe nothrow*/ @system unittest
2009 {
2010     import std.algorithm.comparison : equal;
2011     import std.typecons : tuple;
2012 
2013     struct Item { int x, y; }
2014 
2015     // Force R to have only an input range API with reference semantics, so
2016     // that we're not unknowingly making use of array semantics outside of the
2017     // range API.
2018     class RefInputRange(R)
2019     {
2020         R data;
2021         this(R _data) pure @safe nothrow { data = _data; }
2022         @property bool empty() pure @safe nothrow { return data.empty; }
2023         @property auto front() pure @safe nothrow { return data.front; }
2024         void popFront() pure @safe nothrow { data.popFront(); }
2025     }
2026     auto refInputRange(R)(R range) { return new RefInputRange!R(range); }
2027 
2028     {
2029         auto arr = [ Item(1,2), Item(1,3), Item(2,3) ];
2030         static assert(isForwardRange!(typeof(arr)));
2031 
2032         auto byX = chunkBy!(a => a.x)(arr);
2033         static assert(isForwardRange!(typeof(byX)));
2034 
2035         auto byX_subrange1 = byX.front[1].save;
2036         auto byX_subrange2 = byX.front[1].save;
2037         static assert(isForwardRange!(typeof(byX_subrange1)));
2038         static assert(isForwardRange!(typeof(byX_subrange2)));
2039 
2040         byX.popFront();
2041         assert(byX_subrange1.equal([ Item(1,2), Item(1,3) ]));
2042         byX_subrange1.popFront();
2043         assert(byX_subrange1.equal([ Item(1,3) ]));
2044         assert(byX_subrange2.equal([ Item(1,2), Item(1,3) ]));
2045 
2046         auto byY = chunkBy!(a => a.y)(arr);
2047         static assert(isForwardRange!(typeof(byY)));
2048 
2049         auto byY2 = byY.save;
2050         static assert(is(typeof(byY) == typeof(byY2)));
2051         byY.popFront();
2052         assert(byY.front[0] == 3);
2053         assert(byY.front[1].equal([ Item(1,3), Item(2,3) ]));
2054         assert(byY2.front[0] == 2);
2055         assert(byY2.front[1].equal([ Item(1,2) ]));
2056     }
2057 
2058     // Test non-forward input ranges.
2059     {
2060         auto range = refInputRange([ Item(1,1), Item(1,2), Item(2,2) ]);
2061         auto byX = chunkBy!(a => a.x)(range);
2062         assert(byX.front[0] == 1);
2063         assert(byX.front[1].equal([ Item(1,1), Item(1,2) ]));
2064         byX.popFront();
2065         assert(byX.front[0] == 2);
2066         assert(byX.front[1].equal([ Item(2,2) ]));
2067         byX.popFront();
2068         assert(byX.empty);
2069         assert(range.empty);
2070 
2071         range = refInputRange([ Item(1,1), Item(1,2), Item(2,2) ]);
2072         auto byY = chunkBy!(a => a.y)(range);
2073         assert(byY.front[0] == 1);
2074         assert(byY.front[1].equal([ Item(1,1) ]));
2075         byY.popFront();
2076         assert(byY.front[0] == 2);
2077         assert(byY.front[1].equal([ Item(1,2), Item(2,2) ]));
2078         byY.popFront();
2079         assert(byY.empty);
2080         assert(range.empty);
2081     }
2082 }
2083 
2084 // Issue 13595
2085 version(none) // This requires support for non-equivalence relations
2086 @system unittest
2087 {
2088     import std.algorithm.comparison : equal;
2089     auto r = [1, 2, 3, 4, 5, 6, 7, 8, 9].chunkBy!((x, y) => ((x*y) % 3) == 0);
2090     assert(r.equal!equal([
2091         [1],
2092         [2, 3, 4],
2093         [5, 6, 7],
2094         [8, 9]
2095     ]));
2096 }
2097 
2098 // Issue 13805
2099 @system unittest
2100 {
2101     [""].map!((s) => s).chunkBy!((x, y) => true);
2102 }
2103 
2104 // joiner
2105 /**
2106 Lazily joins a range of ranges with a separator. The separator itself
2107 is a range. If a separator is not provided, then the ranges are
2108 joined directly without anything in between them (often called `flatten`
2109 in other languages).
2110 
2111 Params:
2112     r = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of input
2113         ranges to be joined.
2114     sep = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) of
2115         element(s) to serve as separators in the joined range.
2116 
2117 Returns:
2118 A range of elements in the joined range. This will be a forward range if
2119 both outer and inner ranges of $(D RoR) are forward ranges; otherwise it will
2120 be only an input range.
2121 
2122 See_also:
2123 $(REF chain, std,range), which chains a sequence of ranges with compatible elements
2124 into a single range.
2125  */
2126 auto joiner(RoR, Separator)(RoR r, Separator sep)
2127 if (isInputRange!RoR && isInputRange!(ElementType!RoR)
2128         && isForwardRange!Separator
2129         && is(ElementType!Separator : ElementType!(ElementType!RoR)))
2130 {
2131     static struct Result
2132     {
2133         private RoR _items;
2134         private ElementType!RoR _current;
2135         private Separator _sep, _currentSep;
2136 
2137         // This is a mixin instead of a function for the following reason (as
2138         // explained by Kenji Hara): "This is necessary from 2.061.  If a
2139         // struct has a nested struct member, it must be directly initialized
2140         // in its constructor to avoid leaving undefined state.  If you change
2141         // setItem to a function, the initialization of _current field is
2142         // wrapped into private member function, then compiler could not detect
2143         // that is correctly initialized while constructing.  To avoid the
2144         // compiler error check, string mixin is used."
2145         private enum setItem =
2146         q{
2147             if (!_items.empty)
2148             {
2149                 // If we're exporting .save, we must not consume any of the
2150                 // subranges, since RoR.save does not guarantee that the states
2151                 // of the subranges are also saved.
2152                 static if (isForwardRange!RoR &&
2153                            isForwardRange!(ElementType!RoR))
2154                     _current = _items.front.save;
2155                 else
2156                     _current = _items.front;
2157             }
2158         };
2159 
2160         private void useSeparator()
2161         {
2162             // Separator must always come after an item.
2163             assert(_currentSep.empty && !_items.empty,
2164                     "joiner: internal error");
2165             _items.popFront();
2166 
2167             // If there are no more items, we're done, since separators are not
2168             // terminators.
2169             if (_items.empty) return;
2170 
2171             if (_sep.empty)
2172             {
2173                 // Advance to the next range in the
2174                 // input
2175                 while (_items.front.empty)
2176                 {
2177                     _items.popFront();
2178                     if (_items.empty) return;
2179                 }
2180                 mixin(setItem);
2181             }
2182             else
2183             {
2184                 _currentSep = _sep.save;
2185                 assert(!_currentSep.empty);
2186             }
2187         }
2188 
2189         private enum useItem =
2190         q{
2191             // FIXME: this will crash if either _currentSep or _current are
2192             // class objects, because .init is null when the ctor invokes this
2193             // mixin.
2194             //assert(_currentSep.empty && _current.empty,
2195             //        "joiner: internal error");
2196 
2197             // Use the input
2198             if (_items.empty) return;
2199             mixin(setItem);
2200             if (_current.empty)
2201             {
2202                 // No data in the current item - toggle to use the separator
2203                 useSeparator();
2204             }
2205         };
2206 
2207         this(RoR items, Separator sep)
2208         {
2209             _items = items;
2210             _sep = sep;
2211 
2212             //mixin(useItem); // _current should be initialized in place
2213             if (_items.empty)
2214                 _current = _current.init;   // set invalid state
2215             else
2216             {
2217                 // If we're exporting .save, we must not consume any of the
2218                 // subranges, since RoR.save does not guarantee that the states
2219                 // of the subranges are also saved.
2220                 static if (isForwardRange!RoR &&
2221                            isForwardRange!(ElementType!RoR))
2222                     _current = _items.front.save;
2223                 else
2224                     _current = _items.front;
2225 
2226                 if (_current.empty)
2227                 {
2228                     // No data in the current item - toggle to use the separator
2229                     useSeparator();
2230                 }
2231             }
2232         }
2233 
2234         @property auto empty()
2235         {
2236             return _items.empty;
2237         }
2238 
2239         @property ElementType!(ElementType!RoR) front()
2240         {
2241             if (!_currentSep.empty) return _currentSep.front;
2242             assert(!_current.empty, "Attempting to fetch the front of an empty joiner.");
2243             return _current.front;
2244         }
2245 
2246         void popFront()
2247         {
2248             assert(!_items.empty, "Attempting to popFront an empty joiner.");
2249             // Using separator?
2250             if (!_currentSep.empty)
2251             {
2252                 _currentSep.popFront();
2253                 if (!_currentSep.empty) return;
2254                 mixin(useItem);
2255             }
2256             else
2257             {
2258                 // we're using the range
2259                 _current.popFront();
2260                 if (!_current.empty) return;
2261                 useSeparator();
2262             }
2263         }
2264 
2265         static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
2266         {
2267             @property auto save()
2268             {
2269                 Result copy = this;
2270                 copy._items = _items.save;
2271                 copy._current = _current.save;
2272                 copy._sep = _sep.save;
2273                 copy._currentSep = _currentSep.save;
2274                 return copy;
2275             }
2276         }
2277     }
2278     return Result(r, sep);
2279 }
2280 
2281 ///
2282 @safe unittest
2283 {
2284     import std.algorithm.comparison : equal;
2285     import std.conv : text;
2286 
2287     assert(["abc", "def"].joiner.equal("abcdef"));
2288     assert(["Mary", "has", "a", "little", "lamb"]
2289         .joiner("...")
2290         .equal("Mary...has...a...little...lamb"));
2291     assert(["", "abc"].joiner("xyz").equal("xyzabc"));
2292     assert([""].joiner("xyz").equal(""));
2293     assert(["", ""].joiner("xyz").equal("xyz"));
2294 }
2295 
2296 @system unittest
2297 {
2298     import std.algorithm.comparison : equal;
2299     import std.range.interfaces;
2300     import std.range.primitives;
2301     // joiner() should work for non-forward ranges too.
2302     auto r = inputRangeObject(["abc", "def"]);
2303     assert(equal(joiner(r, "xyz"), "abcxyzdef"));
2304 }
2305 
2306 @system unittest
2307 {
2308     import std.algorithm.comparison : equal;
2309     import std.range;
2310 
2311     // Related to issue 8061
2312     auto r = joiner([
2313         inputRangeObject("abc"),
2314         inputRangeObject("def"),
2315     ], "-*-");
2316 
2317     assert(equal(r, "abc-*-def"));
2318 
2319     // Test case where separator is specified but is empty.
2320     auto s = joiner([
2321         inputRangeObject("abc"),
2322         inputRangeObject("def"),
2323     ], "");
2324 
2325     assert(equal(s, "abcdef"));
2326 
2327     // Test empty separator with some empty elements
2328     auto t = joiner([
2329         inputRangeObject("abc"),
2330         inputRangeObject(""),
2331         inputRangeObject("def"),
2332         inputRangeObject(""),
2333     ], "");
2334 
2335     assert(equal(t, "abcdef"));
2336 
2337     // Test empty elements with non-empty separator
2338     auto u = joiner([
2339         inputRangeObject(""),
2340         inputRangeObject("abc"),
2341         inputRangeObject(""),
2342         inputRangeObject("def"),
2343         inputRangeObject(""),
2344     ], "+-");
2345 
2346     assert(equal(u, "+-abc+-+-def+-"));
2347 
2348     // Issue 13441: only(x) as separator
2349     string[][] lines = [null];
2350     lines
2351         .joiner(only("b"))
2352         .array();
2353 }
2354 
2355 @safe unittest
2356 {
2357     import std.algorithm.comparison : equal;
2358 
2359     // Transience correctness test
2360     struct TransientRange
2361     {
2362     @safe:
2363         int[][] src;
2364         int[] buf;
2365 
2366         this(int[][] _src)
2367         {
2368             src = _src;
2369             buf.length = 100;
2370         }
2371         @property bool empty() { return src.empty; }
2372         @property int[] front()
2373         {
2374             assert(src.front.length <= buf.length);
2375             buf[0 .. src.front.length] = src.front[0..$];
2376             return buf[0 .. src.front.length];
2377         }
2378         void popFront() { src.popFront(); }
2379     }
2380 
2381     // Test embedded empty elements
2382     auto tr1 = TransientRange([[], [1,2,3], [], [4]]);
2383     assert(equal(joiner(tr1, [0]), [0,1,2,3,0,0,4]));
2384 
2385     // Test trailing empty elements
2386     auto tr2 = TransientRange([[], [1,2,3], []]);
2387     assert(equal(joiner(tr2, [0]), [0,1,2,3,0]));
2388 
2389     // Test no empty elements
2390     auto tr3 = TransientRange([[1,2], [3,4]]);
2391     assert(equal(joiner(tr3, [0,1]), [1,2,0,1,3,4]));
2392 
2393     // Test consecutive empty elements
2394     auto tr4 = TransientRange([[1,2], [], [], [], [3,4]]);
2395     assert(equal(joiner(tr4, [0,1]), [1,2,0,1,0,1,0,1,0,1,3,4]));
2396 
2397     // Test consecutive trailing empty elements
2398     auto tr5 = TransientRange([[1,2], [3,4], [], []]);
2399     assert(equal(joiner(tr5, [0,1]), [1,2,0,1,3,4,0,1,0,1]));
2400 }
2401 
2402 @safe unittest
2403 {
2404     static assert(isInputRange!(typeof(joiner([""], ""))));
2405     static assert(isForwardRange!(typeof(joiner([""], ""))));
2406 }
2407 
2408 /// Ditto
2409 auto joiner(RoR)(RoR r)
2410 if (isInputRange!RoR && isInputRange!(ElementType!RoR))
2411 {
2412     static struct Result
2413     {
2414     private:
2415         RoR _items;
2416         ElementType!RoR _current;
2417         enum prepare =
2418         q{
2419             // Skip over empty subranges.
2420             if (_items.empty) return;
2421             while (_items.front.empty)
2422             {
2423                 _items.popFront();
2424                 if (_items.empty) return;
2425             }
2426             // We cannot export .save method unless we ensure subranges are not
2427             // consumed when a .save'd copy of ourselves is iterated over. So
2428             // we need to .save each subrange we traverse.
2429             static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
2430                 _current = _items.front.save;
2431             else
2432                 _current = _items.front;
2433         };
2434         this(RoR items, ElementType!RoR current)
2435         {
2436             _items = items;
2437             _current = current;
2438         }
2439     public:
2440         this(RoR r)
2441         {
2442             _items = r;
2443             //mixin(prepare); // _current should be initialized in place
2444 
2445             // Skip over empty subranges.
2446             while (!_items.empty && _items.front.empty)
2447                 _items.popFront();
2448 
2449             if (_items.empty)
2450                 _current = _current.init;   // set invalid state
2451             else
2452             {
2453                 // We cannot export .save method unless we ensure subranges are not
2454                 // consumed when a .save'd copy of ourselves is iterated over. So
2455                 // we need to .save each subrange we traverse.
2456                 static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
2457                     _current = _items.front.save;
2458                 else
2459                     _current = _items.front;
2460             }
2461         }
2462         static if (isInfinite!RoR)
2463         {
2464             enum bool empty = false;
2465         }
2466         else
2467         {
2468             @property auto empty()
2469             {
2470                 return _items.empty;
2471             }
2472         }
2473         @property auto ref front()
2474         {
2475             assert(!empty, "Attempting to fetch the front of an empty joiner.");
2476             return _current.front;
2477         }
2478         void popFront()
2479         {
2480             assert(!_current.empty, "Attempting to popFront an empty joiner.");
2481             _current.popFront();
2482             if (_current.empty)
2483             {
2484                 assert(!_items.empty);
2485                 _items.popFront();
2486                 mixin(prepare);
2487             }
2488         }
2489         static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
2490         {
2491             @property auto save()
2492             {
2493                 return Result(_items.save, _current.save);
2494             }
2495         }
2496 
2497         static if (hasAssignableElements!(ElementType!RoR))
2498         {
2499             @property void front(ElementType!(ElementType!RoR) element)
2500             {
2501                 assert(!empty, "Attempting to assign to front of an empty joiner.");
2502                 _current.front = element;
2503             }
2504 
2505             @property void front(ref ElementType!(ElementType!RoR) element)
2506             {
2507                 assert(!empty, "Attempting to assign to front of an empty joiner.");
2508                 _current.front = element;
2509             }
2510         }
2511     }
2512     return Result(r);
2513 }
2514 
2515 @safe unittest
2516 {
2517     import std.algorithm.comparison : equal;
2518     import std.range.interfaces : inputRangeObject;
2519     import std.range : repeat;
2520 
2521     static assert(isInputRange!(typeof(joiner([""]))));
2522     static assert(isForwardRange!(typeof(joiner([""]))));
2523     assert(equal(joiner([""]), ""));
2524     assert(equal(joiner(["", ""]), ""));
2525     assert(equal(joiner(["", "abc"]), "abc"));
2526     assert(equal(joiner(["abc", ""]), "abc"));
2527     assert(equal(joiner(["abc", "def"]), "abcdef"));
2528     assert(equal(joiner(["Mary", "has", "a", "little", "lamb"]),
2529                     "Maryhasalittlelamb"));
2530     assert(equal(joiner(repeat("abc", 3)), "abcabcabc"));
2531 
2532     // joiner allows in-place mutation!
2533     auto a = [ [1, 2, 3], [42, 43] ];
2534     auto j = joiner(a);
2535     j.front = 44;
2536     assert(a == [ [44, 2, 3], [42, 43] ]);
2537 }
2538 
2539 
2540 @system unittest
2541 {
2542     import std.algorithm.comparison : equal;
2543     import std.range.interfaces : inputRangeObject;
2544 
2545     // bugzilla 8240
2546     assert(equal(joiner([inputRangeObject("")]), ""));
2547 
2548     // issue 8792
2549     auto b = [[1], [2], [3]];
2550     auto jb = joiner(b);
2551     auto js = jb.save;
2552     assert(equal(jb, js));
2553 
2554     auto js2 = jb.save;
2555     jb.popFront();
2556     assert(!equal(jb, js));
2557     assert(equal(js2, js));
2558     js.popFront();
2559     assert(equal(jb, js));
2560     assert(!equal(js2, js));
2561 }
2562 
2563 @safe unittest
2564 {
2565     import std.algorithm.comparison : equal;
2566 
2567     struct TransientRange
2568     {
2569     @safe:
2570         int[] _buf;
2571         int[][] _values;
2572         this(int[][] values)
2573         {
2574             _values = values;
2575             _buf = new int[128];
2576         }
2577         @property bool empty()
2578         {
2579             return _values.length == 0;
2580         }
2581         @property auto front()
2582         {
2583             foreach (i; 0 .. _values.front.length)
2584             {
2585                 _buf[i] = _values[0][i];
2586             }
2587             return _buf[0 .. _values.front.length];
2588         }
2589         void popFront()
2590         {
2591             _values = _values[1 .. $];
2592         }
2593     }
2594 
2595     auto rr = TransientRange([[1,2], [3,4,5], [], [6,7]]);
2596 
2597     // Can't use array() or equal() directly because they fail with transient
2598     // .front.
2599     int[] result;
2600     foreach (c; rr.joiner())
2601     {
2602         result ~= c;
2603     }
2604 
2605     assert(equal(result, [1,2,3,4,5,6,7]));
2606 }
2607 
2608 @safe unittest
2609 {
2610     import std.algorithm.comparison : equal;
2611     import std.algorithm.internal : algoFormat;
2612 
2613     struct TransientRange
2614     {
2615     @safe:
2616         dchar[] _buf;
2617         dstring[] _values;
2618         this(dstring[] values)
2619         {
2620             _buf.length = 128;
2621             _values = values;
2622         }
2623         @property bool empty()
2624         {
2625             return _values.length == 0;
2626         }
2627         @property auto front()
2628         {
2629             foreach (i; 0 .. _values.front.length)
2630             {
2631                 _buf[i] = _values[0][i];
2632             }
2633             return _buf[0 .. _values.front.length];
2634         }
2635         void popFront()
2636         {
2637             _values = _values[1 .. $];
2638         }
2639     }
2640 
2641     auto rr = TransientRange(["abc"d, "12"d, "def"d, "34"d]);
2642 
2643     // Can't use array() or equal() directly because they fail with transient
2644     // .front.
2645     dchar[] result;
2646     foreach (c; rr.joiner())
2647     {
2648         result ~= c;
2649     }
2650 
2651     import std.conv : to;
2652     assert(equal(result, "abc12def34"d),
2653         //Convert to string for assert's message
2654         to!string("Unexpected result: '%s'"d.algoFormat(result)));
2655 }
2656 
2657 // Issue 8061
2658 @system unittest
2659 {
2660     import std.conv : to;
2661     import std.range.interfaces;
2662 
2663     auto r = joiner([inputRangeObject("ab"), inputRangeObject("cd")]);
2664     assert(isForwardRange!(typeof(r)));
2665 
2666     auto str = to!string(r);
2667     assert(str == "abcd");
2668 }
2669 
2670 @safe unittest
2671 {
2672     import std.range : repeat;
2673 
2674     class AssignableRange
2675     {
2676     @safe:
2677         int element;
2678         @property int front()
2679         {
2680             return element;
2681         }
2682 
2683         enum empty = false;
2684 
2685         void popFront()
2686         {
2687         }
2688 
2689         @property void front(int newValue)
2690         {
2691             element = newValue;
2692         }
2693     }
2694 
2695     static assert(isInputRange!AssignableRange);
2696     static assert(is(ElementType!AssignableRange == int));
2697     static assert(hasAssignableElements!AssignableRange);
2698     static assert(!hasLvalueElements!AssignableRange);
2699 
2700     auto range = new AssignableRange();
2701     assert(range.element == 0);
2702 
2703     auto joined = joiner(repeat(range));
2704     joined.front = 5;
2705     assert(range.element == 5);
2706     assert(joined.front == 5);
2707 
2708     joined.popFront;
2709     int byRef = 7;
2710     joined.front = byRef;
2711     assert(range.element == byRef);
2712     assert(joined.front == byRef);
2713 }
2714 
2715 /++
2716 Implements the homonym function (also known as $(D accumulate), $(D
2717 compress), $(D inject), or $(D foldl)) present in various programming
2718 languages of functional flavor. There is also $(LREF fold) which does
2719 the same thing but with the opposite parameter order.
2720 The call $(D reduce!(fun)(seed, range)) first assigns $(D seed) to
2721 an internal variable $(D result), also called the accumulator.
2722 Then, for each element $(D x) in $(D range), $(D result = fun(result, x))
2723 gets evaluated. Finally, $(D result) is returned.
2724 The one-argument version $(D reduce!(fun)(range))
2725 works similarly, but it uses the first element of the range as the
2726 seed (the range must be non-empty).
2727 
2728 Returns:
2729     the accumulated $(D result)
2730 
2731 Params:
2732     fun = one or more functions
2733 
2734 See_Also:
2735     $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function))
2736 
2737     $(LREF fold) is functionally equivalent to $(LREF reduce) with the argument order reversed,
2738     and without the need to use $(LREF tuple) for multiple seeds. This makes it easier
2739     to use in UFCS chains.
2740 
2741     $(LREF sum) is similar to $(D reduce!((a, b) => a + b)) that offers
2742     pairwise summing of floating point numbers.
2743 +/
2744 template reduce(fun...)
2745 if (fun.length >= 1)
2746 {
2747     import std.meta : staticMap;
2748 
2749     alias binfuns = staticMap!(binaryFun, fun);
2750     static if (fun.length > 1)
2751         import std.typecons : tuple, isTuple;
2752 
2753     /++
2754     No-seed version. The first element of $(D r) is used as the seed's value.
2755 
2756     For each function $(D f) in $(D fun), the corresponding
2757     seed type $(D S) is $(D Unqual!(typeof(f(e, e)))), where $(D e) is an
2758     element of $(D r): $(D ElementType!R) for ranges,
2759     and $(D ForeachType!R) otherwise.
2760 
2761     Once S has been determined, then $(D S s = e;) and $(D s = f(s, e);)
2762     must both be legal.
2763 
2764     If $(D r) is empty, an $(D Exception) is thrown.
2765 
2766     Params:
2767         r = an iterable value as defined by $(D isIterable)
2768 
2769     Returns:
2770         the final result of the accumulator applied to the iterable
2771     +/
2772     auto reduce(R)(R r)
2773     if (isIterable!R)
2774     {
2775         import std.exception : enforce;
2776         alias E = Select!(isInputRange!R, ElementType!R, ForeachType!R);
2777         alias Args = staticMap!(ReduceSeedType!E, binfuns);
2778 
2779         static if (isInputRange!R)
2780         {
2781             enforce(!r.empty, "Cannot reduce an empty input range w/o an explicit seed value.");
2782             Args result = r.front;
2783             r.popFront();
2784             return reduceImpl!false(r, result);
2785         }
2786         else
2787         {
2788             auto result = Args.init;
2789             return reduceImpl!true(r, result);
2790         }
2791     }
2792 
2793     /++
2794     Seed version. The seed should be a single value if $(D fun) is a
2795     single function. If $(D fun) is multiple functions, then $(D seed)
2796     should be a $(REF Tuple, std,typecons), with one field per function in $(D f).
2797 
2798     For convenience, if the seed is const, or has qualified fields, then
2799     $(D reduce) will operate on an unqualified copy. If this happens
2800     then the returned type will not perfectly match $(D S).
2801 
2802     Use $(D fold) instead of $(D reduce) to use the seed version in a UFCS chain.
2803 
2804     Params:
2805         seed = the initial value of the accumulator
2806         r = an iterable value as defined by $(D isIterable)
2807 
2808     Returns:
2809         the final result of the accumulator applied to the iterable
2810     +/
2811     auto reduce(S, R)(S seed, R r)
2812     if (isIterable!R)
2813     {
2814         static if (fun.length == 1)
2815             return reducePreImpl(r, seed);
2816         else
2817         {
2818             import std.algorithm.internal : algoFormat;
2819             static assert(isTuple!S, algoFormat("Seed %s should be a Tuple", S.stringof));
2820             return reducePreImpl(r, seed.expand);
2821         }
2822     }
2823 
2824     private auto reducePreImpl(R, Args...)(R r, ref Args args)
2825     {
2826         alias Result = staticMap!(Unqual, Args);
2827         static if (is(Result == Args))
2828             alias result = args;
2829         else
2830             Result result = args;
2831         return reduceImpl!false(r, result);
2832     }
2833 
2834     private auto reduceImpl(bool mustInitialize, R, Args...)(R r, ref Args args)
2835     if (isIterable!R)
2836     {
2837         import std.algorithm.internal : algoFormat;
2838         static assert(Args.length == fun.length,
2839             algoFormat("Seed %s does not have the correct amount of fields (should be %s)", Args.stringof, fun.length));
2840         alias E = Select!(isInputRange!R, ElementType!R, ForeachType!R);
2841 
2842         static if (mustInitialize) bool initialized = false;
2843         foreach (/+auto ref+/ E e; r) // @@@4707@@@
2844         {
2845             foreach (i, f; binfuns)
2846             {
2847                 static assert(!is(typeof(f(args[i], e))) || is(typeof(args[i] = f(args[i], e))),
2848                     algoFormat(
2849                         "Incompatible function/seed/element: %s/%s/%s",
2850                         fullyQualifiedName!f,
2851                         Args[i].stringof,
2852                         E.stringof
2853                     )
2854                 );
2855             }
2856 
2857             static if (mustInitialize) if (initialized == false)
2858             {
2859                 import std.conv : emplaceRef;
2860                 foreach (i, f; binfuns)
2861                     emplaceRef!(Args[i])(args[i], e);
2862                 initialized = true;
2863                 continue;
2864             }
2865 
2866             foreach (i, f; binfuns)
2867                 args[i] = f(args[i], e);
2868         }
2869         static if (mustInitialize)
2870         if (!initialized)
2871             throw new Exception("Cannot reduce an empty iterable w/o an explicit seed value.");
2872 
2873         static if (Args.length == 1)
2874             return args[0];
2875         else
2876             return tuple(args);
2877     }
2878 }
2879 
2880 /**
2881 Many aggregate range operations turn out to be solved with $(D reduce)
2882 quickly and easily. The example below illustrates $(D reduce)'s
2883 remarkable power and flexibility.
2884 */
2885 @safe unittest
2886 {
2887     import std.algorithm.comparison : max, min;
2888     import std.math : approxEqual;
2889     import std.range;
2890 
2891     int[] arr = [ 1, 2, 3, 4, 5 ];
2892     // Sum all elements
2893     auto sum = reduce!((a,b) => a + b)(0, arr);
2894     assert(sum == 15);
2895 
2896     // Sum again, using a string predicate with "a" and "b"
2897     sum = reduce!"a + b"(0, arr);
2898     assert(sum == 15);
2899 
2900     // Compute the maximum of all elements
2901     auto largest = reduce!(max)(arr);
2902     assert(largest == 5);
2903 
2904     // Max again, but with Uniform Function Call Syntax (UFCS)
2905     largest = arr.reduce!(max);
2906     assert(largest == 5);
2907 
2908     // Compute the number of odd elements
2909     auto odds = reduce!((a,b) => a + (b & 1))(0, arr);
2910     assert(odds == 3);
2911 
2912     // Compute the sum of squares
2913     auto ssquares = reduce!((a,b) => a + b * b)(0, arr);
2914     assert(ssquares == 55);
2915 
2916     // Chain multiple ranges into seed
2917     int[] a = [ 3, 4 ];
2918     int[] b = [ 100 ];
2919     auto r = reduce!("a + b")(chain(a, b));
2920     assert(r == 107);
2921 
2922     // Mixing convertible types is fair game, too
2923     double[] c = [ 2.5, 3.0 ];
2924     auto r1 = reduce!("a + b")(chain(a, b, c));
2925     assert(approxEqual(r1, 112.5));
2926 
2927     // To minimize nesting of parentheses, Uniform Function Call Syntax can be used
2928     auto r2 = chain(a, b, c).reduce!("a + b");
2929     assert(approxEqual(r2, 112.5));
2930 }
2931 
2932 /**
2933 Sometimes it is very useful to compute multiple aggregates in one pass.
2934 One advantage is that the computation is faster because the looping overhead
2935 is shared. That's why $(D reduce) accepts multiple functions.
2936 If two or more functions are passed, $(D reduce) returns a
2937 $(REF Tuple, std,typecons) object with one member per passed-in function.
2938 The number of seeds must be correspondingly increased.
2939 */
2940 @safe unittest
2941 {
2942     import std.algorithm.comparison : max, min;
2943     import std.math : approxEqual, sqrt;
2944     import std.typecons : tuple, Tuple;
2945 
2946     double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ];
2947     // Compute minimum and maximum in one pass
2948     auto r = reduce!(min, max)(a);
2949     // The type of r is Tuple!(int, int)
2950     assert(approxEqual(r[0], 2));  // minimum
2951     assert(approxEqual(r[1], 11)); // maximum
2952 
2953     // Compute sum and sum of squares in one pass
2954     r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a);
2955     assert(approxEqual(r[0], 35));  // sum
2956     assert(approxEqual(r[1], 233)); // sum of squares
2957     // Compute average and standard deviation from the above
2958     auto avg = r[0] / a.length;
2959     auto stdev = sqrt(r[1] / a.length - avg * avg);
2960 }
2961 
2962 @safe unittest
2963 {
2964     import std.algorithm.comparison : max, min;
2965     import std.range : chain;
2966     import std.typecons : tuple, Tuple;
2967 
2968     double[] a = [ 3, 4 ];
2969     auto r = reduce!("a + b")(0.0, a);
2970     assert(r == 7);
2971     r = reduce!("a + b")(a);
2972     assert(r == 7);
2973     r = reduce!(min)(a);
2974     assert(r == 3);
2975     double[] b = [ 100 ];
2976     auto r1 = reduce!("a + b")(chain(a, b));
2977     assert(r1 == 107);
2978 
2979     // two funs
2980     auto r2 = reduce!("a + b", "a - b")(tuple(0.0, 0.0), a);
2981     assert(r2[0] == 7 && r2[1] == -7);
2982     auto r3 = reduce!("a + b", "a - b")(a);
2983     assert(r3[0] == 7 && r3[1] == -1);
2984 
2985     a = [ 1, 2, 3, 4, 5 ];
2986     // Stringize with commas
2987     string rep = reduce!("a ~ `, ` ~ to!(string)(b)")("", a);
2988     assert(rep[2 .. $] == "1, 2, 3, 4, 5", "["~rep[2 .. $]~"]");
2989 }
2990 
2991 @system unittest
2992 {
2993     import std.algorithm.comparison : max, min;
2994     import std.exception : assertThrown;
2995     import std.range : iota;
2996     import std.typecons : tuple, Tuple;
2997 
2998     // Test the opApply case.
2999     static struct OpApply
3000     {
3001         bool actEmpty;
3002 
3003         int opApply(scope int delegate(ref int) dg)
3004         {
3005             int res;
3006             if (actEmpty) return res;
3007 
3008             foreach (i; 0 .. 100)
3009             {
3010                 res = dg(i);
3011                 if (res) break;
3012             }
3013             return res;
3014         }
3015     }
3016 
3017     OpApply oa;
3018     auto hundredSum = reduce!"a + b"(iota(100));
3019     assert(reduce!"a + b"(5, oa) == hundredSum + 5);
3020     assert(reduce!"a + b"(oa) == hundredSum);
3021     assert(reduce!("a + b", max)(oa) == tuple(hundredSum, 99));
3022     assert(reduce!("a + b", max)(tuple(5, 0), oa) == tuple(hundredSum + 5, 99));
3023 
3024     // Test for throwing on empty range plus no seed.
3025     assertThrown(reduce!"a + b"([1, 2][0 .. 0]));
3026 
3027     oa.actEmpty = true;
3028     assertThrown(reduce!"a + b"(oa));
3029 }
3030 
3031 @safe unittest
3032 {
3033     const float a = 0.0;
3034     const float[] b = [ 1.2, 3, 3.3 ];
3035     float[] c = [ 1.2, 3, 3.3 ];
3036     auto r = reduce!"a + b"(a, b);
3037     r = reduce!"a + b"(a, c);
3038 }
3039 
3040 @safe unittest
3041 {
3042     // Issue #10408 - Two-function reduce of a const array.
3043     import std.algorithm.comparison : max, min;
3044     import std.typecons : tuple, Tuple;
3045 
3046     const numbers = [10, 30, 20];
3047     immutable m = reduce!(min)(numbers);
3048     assert(m == 10);
3049     immutable minmax = reduce!(min, max)(numbers);
3050     assert(minmax == tuple(10, 30));
3051 }
3052 
3053 @safe unittest
3054 {
3055     //10709
3056     import std.typecons : tuple, Tuple;
3057 
3058     enum foo = "a + 0.5 * b";
3059     auto r = [0, 1, 2, 3];
3060     auto r1 = reduce!foo(r);
3061     auto r2 = reduce!(foo, foo)(r);
3062     assert(r1 == 3);
3063     assert(r2 == tuple(3, 3));
3064 }
3065 
3066 @system unittest
3067 {
3068     int i = 0;
3069     static struct OpApply
3070     {
3071         int opApply(int delegate(ref int) dg)
3072         {
3073             int[] a = [1, 2, 3];
3074 
3075             int res = 0;
3076             foreach (ref e; a)
3077             {
3078                 res = dg(e);
3079                 if (res) break;
3080             }
3081             return res;
3082         }
3083     }
3084     //test CTFE and functions with context
3085     int fun(int a, int b) @safe {return a + b + 1;}
3086     auto foo()
3087     {
3088         import std.algorithm.comparison : max;
3089         import std.typecons : tuple, Tuple;
3090 
3091         auto a = reduce!(fun)([1, 2, 3]);
3092         auto b = reduce!(fun, fun)([1, 2, 3]);
3093         auto c = reduce!(fun)(0, [1, 2, 3]);
3094         auto d = reduce!(fun, fun)(tuple(0, 0), [1, 2, 3]);
3095         auto e = reduce!(fun)(0, OpApply());
3096         auto f = reduce!(fun, fun)(tuple(0, 0), OpApply());
3097 
3098         return max(a, b.expand, c, d.expand);
3099     }
3100     auto a = foo();
3101     enum b = foo();
3102 }
3103 
3104 @safe unittest
3105 {
3106     import std.algorithm.comparison : max, min;
3107     import std.typecons : tuple, Tuple;
3108 
3109     //http://forum.dlang.org/post/oghtttkopzjshsuflelk@forum.dlang.org
3110     //Seed is tuple of const.
3111     static auto minmaxElement(alias F = min, alias G = max, R)(in R range)
3112     @safe pure nothrow
3113     if (isInputRange!R)
3114     {
3115         return reduce!(F, G)(tuple(ElementType!R.max,
3116                                    ElementType!R.min), range);
3117     }
3118     assert(minmaxElement([1, 2, 3])== tuple(1, 3));
3119 }
3120 
3121 @safe unittest //12569
3122 {
3123     import std.algorithm.comparison : max, min;
3124     import std.typecons : tuple;
3125     dchar c = 'a';
3126     reduce!(min, max)(tuple(c, c), "hello"); // OK
3127     static assert(!is(typeof(reduce!(min, max)(tuple(c), "hello"))));
3128     static assert(!is(typeof(reduce!(min, max)(tuple(c, c, c), "hello"))));
3129 
3130 
3131     //"Seed dchar should be a Tuple"
3132     static assert(!is(typeof(reduce!(min, max)(c, "hello"))));
3133     //"Seed (dchar) does not have the correct amount of fields (should be 2)"
3134     static assert(!is(typeof(reduce!(min, max)(tuple(c), "hello"))));
3135     //"Seed (dchar, dchar, dchar) does not have the correct amount of fields (should be 2)"
3136     static assert(!is(typeof(reduce!(min, max)(tuple(c, c, c), "hello"))));
3137     //"Incompatable function/seed/element: all(alias pred = "a")/int/dchar"
3138     static assert(!is(typeof(reduce!all(1, "hello"))));
3139     static assert(!is(typeof(reduce!(all, all)(tuple(1, 1), "hello"))));
3140 }
3141 
3142 @safe unittest //13304
3143 {
3144     int[] data;
3145     static assert(is(typeof(reduce!((a, b)=>a+b)(data))));
3146 }
3147 
3148 //Helper for Reduce
3149 private template ReduceSeedType(E)
3150 {
3151     static template ReduceSeedType(alias fun)
3152     {
3153         import std.algorithm.internal : algoFormat;
3154 
3155         alias ReduceSeedType = Unqual!(typeof(fun(lvalueOf!E, lvalueOf!E)));
3156 
3157         //Check the Seed type is useable.
3158         ReduceSeedType s = ReduceSeedType.init;
3159         static assert(is(typeof({ReduceSeedType s = lvalueOf!E;})) &&
3160             is(typeof(lvalueOf!ReduceSeedType = fun(lvalueOf!ReduceSeedType, lvalueOf!E))),
3161             algoFormat(
3162                 "Unable to deduce an acceptable seed type for %s with element type %s.",
3163                 fullyQualifiedName!fun,
3164                 E.stringof
3165             )
3166         );
3167     }
3168 }
3169 
3170 
3171 /++
3172 Implements the homonym function (also known as $(D accumulate), $(D
3173 compress), $(D inject), or $(D foldl)) present in various programming
3174 languages of functional flavor. The call $(D fold!(fun)(range, seed))
3175 first assigns $(D seed) to an internal variable $(D result),
3176 also called the accumulator. Then, for each element $(D x) in $(D
3177 range), $(D result = fun(result, x)) gets evaluated. Finally, $(D
3178 result) is returned. The one-argument version $(D fold!(fun)(range))
3179 works similarly, but it uses the first element of the range as the
3180 seed (the range must be non-empty).
3181 
3182 Returns:
3183     the accumulated $(D result)
3184 
3185 See_Also:
3186     $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function))
3187 
3188     $(LREF sum) is similar to $(D fold!((a, b) => a + b)) that offers
3189     precise summing of floating point numbers.
3190 
3191     This is functionally equivalent to $(LREF reduce) with the argument order reversed,
3192     and without the need to use $(LREF tuple) for multiple seeds.
3193 +/
3194 template fold(fun...)
3195 if (fun.length >= 1)
3196 {
3197     auto fold(R, S...)(R r, S seed)
3198     {
3199         static if (S.length < 2)
3200         {
3201             return reduce!fun(seed, r);
3202         }
3203         else
3204         {
3205             import std.typecons : tuple;
3206             return reduce!fun(tuple(seed), r);
3207         }
3208     }
3209 }
3210 
3211 ///
3212 @safe pure unittest
3213 {
3214     immutable arr = [1, 2, 3, 4, 5];
3215 
3216     // Sum all elements
3217     assert(arr.fold!((a, b) => a + b) == 15);
3218 
3219     // Sum all elements with explicit seed
3220     assert(arr.fold!((a, b) => a + b)(6) == 21);
3221 
3222     import std.algorithm.comparison : min, max;
3223     import std.typecons : tuple;
3224 
3225     // Compute minimum and maximum at the same time
3226     assert(arr.fold!(min, max) == tuple(1, 5));
3227 
3228     // Compute minimum and maximum at the same time with seeds
3229     assert(arr.fold!(min, max)(0, 7) == tuple(0, 7));
3230 
3231     // Can be used in a UFCS chain
3232     assert(arr.map!(a => a + 1).fold!((a, b) => a + b) == 20);
3233 
3234     // Return the last element of any range
3235     assert(arr.fold!((a, b) => b) == 5);
3236 }
3237 
3238 @safe @nogc pure nothrow unittest
3239 {
3240     int[1] arr;
3241     static assert(!is(typeof(arr.fold!())));
3242     static assert(!is(typeof(arr.fold!(a => a))));
3243     static assert(is(typeof(arr.fold!((a, b) => a))));
3244     static assert(is(typeof(arr.fold!((a, b) => a)(1))));
3245 }
3246 
3247 /++
3248 Similar to `fold`, but returns a range containing the successive reduced values.
3249 The call $(D cumulativeFold!(fun)(range, seed)) first assigns `seed` to an
3250 internal variable `result`, also called the accumulator.
3251 The returned range contains the values $(D result = fun(result, x)) lazily
3252 evaluated for each element `x` in `range`. Finally, the last element has the
3253 same value as $(D fold!(fun)(seed, range)).
3254 The one-argument version $(D cumulativeFold!(fun)(range)) works similarly, but
3255 it returns the first element unchanged and uses it as seed for the next
3256 elements.
3257 This function is also known as
3258     $(HTTP en.cppreference.com/w/cpp/algorithm/partial_sum, partial_sum),
3259     $(HTTP docs.python.org/3/library/itertools.html#itertools.accumulate, accumulate),
3260     $(HTTP hackage.haskell.org/package/base-4.8.2.0/docs/Prelude.html#v:scanl, scan),
3261     $(HTTP mathworld.wolfram.com/CumulativeSum.html, Cumulative Sum).
3262 
3263 Params:
3264     fun = one or more functions to use as fold operation
3265 
3266 Returns:
3267     The function returns a range containing the consecutive reduced values. If
3268     there is more than one `fun`, the element type will be $(REF Tuple,
3269     std,typecons) containing one element for each `fun`.
3270 
3271 See_Also:
3272     $(HTTP en.wikipedia.org/wiki/Prefix_sum, Prefix Sum)
3273 +/
3274 template cumulativeFold(fun...)
3275 if (fun.length >= 1)
3276 {
3277     import std.meta : staticMap;
3278     private alias binfuns = staticMap!(binaryFun, fun);
3279 
3280     /++
3281     No-seed version. The first element of `r` is used as the seed's value.
3282     For each function `f` in `fun`, the corresponding seed type `S` is
3283     $(D Unqual!(typeof(f(e, e)))), where `e` is an element of `r`:
3284     `ElementType!R`.
3285     Once `S` has been determined, then $(D S s = e;) and $(D s = f(s, e);) must
3286     both be legal.
3287 
3288     Params:
3289         range = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3290     Returns:
3291         a range containing the consecutive reduced values.
3292     +/
3293     auto cumulativeFold(R)(R range)
3294     if (isInputRange!(Unqual!R))
3295     {
3296         return cumulativeFoldImpl(range);
3297     }
3298 
3299     /++
3300     Seed version. The seed should be a single value if `fun` is a single
3301     function. If `fun` is multiple functions, then `seed` should be a
3302     $(REF Tuple, std,typecons), with one field per function in `f`.
3303     For convenience, if the seed is `const`, or has qualified fields, then
3304     `cumulativeFold` will operate on an unqualified copy. If this happens
3305     then the returned type will not perfectly match `S`.
3306 
3307     Params:
3308         range = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3309         seed = the initial value of the accumulator
3310     Returns:
3311         a range containing the consecutive reduced values.
3312     +/
3313     auto cumulativeFold(R, S)(R range, S seed)
3314     if (isInputRange!(Unqual!R))
3315     {
3316         static if (fun.length == 1)
3317             return cumulativeFoldImpl(range, seed);
3318         else
3319             return cumulativeFoldImpl(range, seed.expand);
3320     }
3321 
3322     private auto cumulativeFoldImpl(R, Args...)(R range, ref Args args)
3323     {
3324         import std.algorithm.internal : algoFormat;
3325 
3326         static assert(Args.length == 0 || Args.length == fun.length,
3327             algoFormat("Seed %s does not have the correct amount of fields (should be %s)",
3328                 Args.stringof, fun.length));
3329 
3330         static if (args.length)
3331             alias State = staticMap!(Unqual, Args);
3332         else
3333             alias State = staticMap!(ReduceSeedType!(ElementType!R), binfuns);
3334 
3335         foreach (i, f; binfuns)
3336         {
3337             static assert(!__traits(compiles, f(args[i], e)) || __traits(compiles,
3338                     { args[i] = f(args[i], e); }()),
3339                 algoFormat("Incompatible function/seed/element: %s/%s/%s",
3340                     fullyQualifiedName!f, Args[i].stringof, E.stringof));
3341         }
3342 
3343         static struct Result
3344         {
3345         private:
3346             R source;
3347             State state;
3348 
3349             this(R range, ref Args args)
3350             {
3351                 source = range;
3352                 if (source.empty)
3353                     return;
3354 
3355                 foreach (i, f; binfuns)
3356                 {
3357                     static if (args.length)
3358                         state[i] = f(args[i], source.front);
3359                     else
3360                         state[i] = source.front;
3361                 }
3362             }
3363 
3364         public:
3365             @property bool empty()
3366             {
3367                 return source.empty;
3368             }
3369 
3370             @property auto front()
3371             {
3372                 assert(!empty, "Attempting to fetch the front of an empty cumulativeFold.");
3373                 static if (fun.length > 1)
3374                 {
3375                     import std.typecons : tuple;
3376                     return tuple(state);
3377                 }
3378                 else
3379                 {
3380                     return state[0];
3381                 }
3382             }
3383 
3384             void popFront()
3385             {
3386                 assert(!empty, "Attempting to popFront an empty cumulativeFold.");
3387                 source.popFront;
3388 
3389                 if (source.empty)
3390                     return;
3391 
3392                 foreach (i, f; binfuns)
3393                     state[i] = f(state[i], source.front);
3394             }
3395 
3396             static if (isForwardRange!R)
3397             {
3398                 @property auto save()
3399                 {
3400                     auto result = this;
3401                     result.source = source.save;
3402                     return result;
3403                 }
3404             }
3405 
3406             static if (hasLength!R)
3407             {
3408                 @property size_t length()
3409                 {
3410                     return source.length;
3411                 }
3412             }
3413         }
3414 
3415         return Result(range, args);
3416     }
3417 }
3418 
3419 ///
3420 @safe unittest
3421 {
3422     import std.algorithm.comparison : max, min;
3423     import std.array : array;
3424     import std.math : approxEqual;
3425     import std.range : chain;
3426 
3427     int[] arr = [1, 2, 3, 4, 5];
3428     // Partial sum of all elements
3429     auto sum = cumulativeFold!((a, b) => a + b)(arr, 0);
3430     assert(sum.array == [1, 3, 6, 10, 15]);
3431 
3432     // Partial sum again, using a string predicate with "a" and "b"
3433     auto sum2 = cumulativeFold!"a + b"(arr, 0);
3434     assert(sum2.array == [1, 3, 6, 10, 15]);
3435 
3436     // Compute the partial maximum of all elements
3437     auto largest = cumulativeFold!max(arr);
3438     assert(largest.array == [1, 2, 3, 4, 5]);
3439 
3440     // Partial max again, but with Uniform Function Call Syntax (UFCS)
3441     largest = arr.cumulativeFold!max;
3442     assert(largest.array == [1, 2, 3, 4, 5]);
3443 
3444     // Partial count of odd elements
3445     auto odds = arr.cumulativeFold!((a, b) => a + (b & 1))(0);
3446     assert(odds.array == [1, 1, 2, 2, 3]);
3447 
3448     // Compute the partial sum of squares
3449     auto ssquares = arr.cumulativeFold!((a, b) => a + b * b)(0);
3450     assert(ssquares.array == [1, 5, 14, 30, 55]);
3451 
3452     // Chain multiple ranges into seed
3453     int[] a = [3, 4];
3454     int[] b = [100];
3455     auto r = cumulativeFold!"a + b"(chain(a, b));
3456     assert(r.array == [3, 7, 107]);
3457 
3458     // Mixing convertible types is fair game, too
3459     double[] c = [2.5, 3.0];
3460     auto r1 = cumulativeFold!"a + b"(chain(a, b, c));
3461     assert(approxEqual(r1, [3, 7, 107, 109.5, 112.5]));
3462 
3463     // To minimize nesting of parentheses, Uniform Function Call Syntax can be used
3464     auto r2 = chain(a, b, c).cumulativeFold!"a + b";
3465     assert(approxEqual(r2, [3, 7, 107, 109.5, 112.5]));
3466 }
3467 
3468 /**
3469 Sometimes it is very useful to compute multiple aggregates in one pass.
3470 One advantage is that the computation is faster because the looping overhead
3471 is shared. That's why `cumulativeFold` accepts multiple functions.
3472 If two or more functions are passed, `cumulativeFold` returns a $(REF Tuple,
3473 std,typecons) object with one member per passed-in function.
3474 The number of seeds must be correspondingly increased.
3475 */
3476 @safe unittest
3477 {
3478     import std.algorithm.comparison : max, min;
3479     import std.algorithm.iteration : map;
3480     import std.math : approxEqual;
3481     import std.typecons : tuple;
3482 
3483     double[] a = [3.0, 4, 7, 11, 3, 2, 5];
3484     // Compute minimum and maximum in one pass
3485     auto r = a.cumulativeFold!(min, max);
3486     // The type of r is Tuple!(int, int)
3487     assert(approxEqual(r.map!"a[0]", [3, 3, 3, 3, 3, 2, 2]));     // minimum
3488     assert(approxEqual(r.map!"a[1]", [3, 4, 7, 11, 11, 11, 11])); // maximum
3489 
3490     // Compute sum and sum of squares in one pass
3491     auto r2 = a.cumulativeFold!("a + b", "a + b * b")(tuple(0.0, 0.0));
3492     assert(approxEqual(r2.map!"a[0]", [3, 7, 14, 25, 28, 30, 35]));      // sum
3493     assert(approxEqual(r2.map!"a[1]", [9, 25, 74, 195, 204, 208, 233])); // sum of squares
3494 }
3495 
3496 @safe unittest
3497 {
3498     import std.algorithm.comparison : equal, max, min;
3499     import std.conv : to;
3500     import std.range : chain;
3501     import std.typecons : tuple;
3502 
3503     double[] a = [3, 4];
3504     auto r = a.cumulativeFold!("a + b")(0.0);
3505     assert(r.equal([3, 7]));
3506     auto r2 = cumulativeFold!("a + b")(a);
3507     assert(r2.equal([3, 7]));
3508     auto r3 = cumulativeFold!(min)(a);
3509     assert(r3.equal([3, 3]));
3510     double[] b = [100];
3511     auto r4 = cumulativeFold!("a + b")(chain(a, b));
3512     assert(r4.equal([3, 7, 107]));
3513 
3514     // two funs
3515     auto r5 = cumulativeFold!("a + b", "a - b")(a, tuple(0.0, 0.0));
3516     assert(r5.equal([tuple(3, -3), tuple(7, -7)]));
3517     auto r6 = cumulativeFold!("a + b", "a - b")(a);
3518     assert(r6.equal([tuple(3, 3), tuple(7, -1)]));
3519 
3520     a = [1, 2, 3, 4, 5];
3521     // Stringize with commas
3522     auto rep = cumulativeFold!("a ~ `, ` ~ to!string(b)")(a, "");
3523     assert(rep.map!"a[2 .. $]".equal(["1", "1, 2", "1, 2, 3", "1, 2, 3, 4", "1, 2, 3, 4, 5"]));
3524 
3525     // Test for empty range
3526     a = [];
3527     assert(a.cumulativeFold!"a + b".empty);
3528     assert(a.cumulativeFold!"a + b"(2.0).empty);
3529 }
3530 
3531 @safe unittest
3532 {
3533     import std.algorithm.comparison : max, min;
3534     import std.array : array;
3535     import std.math : approxEqual;
3536     import std.typecons : tuple;
3537 
3538     const float a = 0.0;
3539     const float[] b = [1.2, 3, 3.3];
3540     float[] c = [1.2, 3, 3.3];
3541 
3542     auto r = cumulativeFold!"a + b"(b, a);
3543     assert(approxEqual(r, [1.2, 4.2, 7.5]));
3544 
3545     auto r2 = cumulativeFold!"a + b"(c, a);
3546     assert(approxEqual(r2, [1.2, 4.2, 7.5]));
3547 
3548     const numbers = [10, 30, 20];
3549     enum m = numbers.cumulativeFold!(min).array;
3550     assert(m == [10, 10, 10]);
3551     enum minmax = numbers.cumulativeFold!(min, max).array;
3552     assert(minmax == [tuple(10, 10), tuple(10, 30), tuple(10, 30)]);
3553 }
3554 
3555 @safe unittest
3556 {
3557     import std.math : approxEqual;
3558     import std.typecons : tuple;
3559 
3560     enum foo = "a + 0.5 * b";
3561     auto r = [0, 1, 2, 3];
3562     auto r1 = r.cumulativeFold!foo;
3563     auto r2 = r.cumulativeFold!(foo, foo);
3564     assert(approxEqual(r1, [0, 0.5, 1.5, 3]));
3565     assert(approxEqual(r2.map!"a[0]", [0, 0.5, 1.5, 3]));
3566     assert(approxEqual(r2.map!"a[1]", [0, 0.5, 1.5, 3]));
3567 }
3568 
3569 @safe unittest
3570 {
3571     import std.algorithm.comparison : equal, max, min;
3572     import std.array : array;
3573     import std.typecons : tuple;
3574 
3575     //Seed is tuple of const.
3576     static auto minmaxElement(alias F = min, alias G = max, R)(in R range)
3577     @safe pure nothrow
3578     if (isInputRange!R)
3579     {
3580         return range.cumulativeFold!(F, G)(tuple(ElementType!R.max, ElementType!R.min));
3581     }
3582 
3583     assert(minmaxElement([1, 2, 3]).equal([tuple(1, 1), tuple(1, 2), tuple(1, 3)]));
3584 }
3585 
3586 @safe unittest //12569
3587 {
3588     import std.algorithm.comparison : equal, max, min;
3589     import std.typecons : tuple;
3590 
3591     dchar c = 'a';
3592 
3593     assert(cumulativeFold!(min, max)("hello", tuple(c, c)).equal([tuple('a', 'h'),
3594         tuple('a', 'h'), tuple('a', 'l'), tuple('a', 'l'), tuple('a', 'o')]));
3595     static assert(!__traits(compiles, cumulativeFold!(min, max)("hello", tuple(c))));
3596     static assert(!__traits(compiles, cumulativeFold!(min, max)("hello", tuple(c, c, c))));
3597 
3598     //"Seed dchar should be a Tuple"
3599     static assert(!__traits(compiles, cumulativeFold!(min, max)("hello", c)));
3600     //"Seed (dchar) does not have the correct amount of fields (should be 2)"
3601     static assert(!__traits(compiles, cumulativeFold!(min, max)("hello", tuple(c))));
3602     //"Seed (dchar, dchar, dchar) does not have the correct amount of fields (should be 2)"
3603     static assert(!__traits(compiles, cumulativeFold!(min, max)("hello", tuple(c, c, c))));
3604     //"Incompatable function/seed/element: all(alias pred = "a")/int/dchar"
3605     static assert(!__traits(compiles, cumulativeFold!all("hello", 1)));
3606     static assert(!__traits(compiles, cumulativeFold!(all, all)("hello", tuple(1, 1))));
3607 }
3608 
3609 @safe unittest //13304
3610 {
3611     int[] data;
3612     assert(data.cumulativeFold!((a, b) => a + b).empty);
3613 }
3614 
3615 @safe unittest
3616 {
3617     import std.algorithm.comparison : equal;
3618     import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
3619         propagatesRangeType, RangeType;
3620 
3621     foreach (DummyType; AllDummyRanges)
3622     {
3623         DummyType d;
3624         auto m = d.cumulativeFold!"a * b";
3625 
3626         static assert(propagatesLength!(typeof(m), DummyType));
3627         static if (DummyType.rt <= RangeType.Forward)
3628             static assert(propagatesRangeType!(typeof(m), DummyType));
3629 
3630         assert(m.equal([1, 2, 6, 24, 120, 720, 5040, 40_320, 362_880, 3_628_800]));
3631     }
3632 }
3633 
3634 // splitter
3635 /**
3636 Lazily splits a range using an element as a separator. This can be used with
3637 any narrow string type or sliceable range type, but is most popular with string
3638 types.
3639 
3640 Two adjacent separators are considered to surround an empty element in
3641 the split range. Use $(D filter!(a => !a.empty)) on the result to compress
3642 empty elements.
3643 
3644 The predicate is passed to $(REF binaryFun, std,functional), and can either accept
3645 a string, or any callable that can be executed via $(D pred(element, s)).
3646 
3647 If the empty range is given, the result is a range with one empty
3648 element. If a range with one separator is given, the result is a range
3649 with two empty elements.
3650 
3651 If splitting a string on whitespace and token compression is desired,
3652 consider using $(D splitter) without specifying a separator (see fourth overload
3653 below).
3654 
3655 Params:
3656     pred = The predicate for comparing each element with the separator,
3657         defaulting to $(D "a == b").
3658     r = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be
3659         split. Must support slicing and $(D .length).
3660     s = The element to be treated as the separator between range segments to be
3661         split.
3662 
3663 Constraints:
3664     The predicate $(D pred) needs to accept an element of $(D r) and the
3665     separator $(D s).
3666 
3667 Returns:
3668     An input range of the subranges of elements between separators. If $(D r)
3669     is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
3670     or $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives),
3671     the returned range will be likewise.
3672 
3673 See_Also:
3674  $(REF _splitter, std,regex) for a version that splits using a regular
3675 expression defined separator.
3676 */
3677 auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
3678 if (is(typeof(binaryFun!pred(r.front, s)) : bool)
3679         && ((hasSlicing!Range && hasLength!Range) || isNarrowString!Range))
3680 {
3681     import std.algorithm.searching : find;
3682     import std.conv : unsigned;
3683 
3684     static struct Result
3685     {
3686     private:
3687         Range _input;
3688         Separator _separator;
3689         // Do we need hasLength!Range? popFront uses _input.length...
3690         enum size_t _unComputed = size_t.max - 1, _atEnd = size_t.max;
3691         size_t _frontLength = _unComputed;
3692         size_t _backLength = _unComputed;
3693 
3694         static if (isNarrowString!Range)
3695         {
3696             size_t _separatorLength;
3697         }
3698         else
3699         {
3700             enum _separatorLength = 1;
3701         }
3702 
3703         static if (isBidirectionalRange!Range)
3704         {
3705             static size_t lastIndexOf(Range haystack, Separator needle)
3706             {
3707                 import std.range : retro;
3708                 auto r = haystack.retro().find!pred(needle);
3709                 return r.retro().length - 1;
3710             }
3711         }
3712 
3713     public:
3714         this(Range input, Separator separator)
3715         {
3716             _input = input;
3717             _separator = separator;
3718 
3719             static if (isNarrowString!Range)
3720             {
3721                 import std.utf : codeLength;
3722 
3723                 _separatorLength = codeLength!(ElementEncodingType!Range)(separator);
3724             }
3725             if (_input.empty)
3726                 _frontLength = _atEnd;
3727         }
3728 
3729         static if (isInfinite!Range)
3730         {
3731             enum bool empty = false;
3732         }
3733         else
3734         {
3735             @property bool empty()
3736             {
3737                 return _frontLength == _atEnd;
3738             }
3739         }
3740 
3741         @property Range front()
3742         {
3743             assert(!empty, "Attempting to fetch the front of an empty splitter.");
3744             if (_frontLength == _unComputed)
3745             {
3746                 auto r = _input.find!pred(_separator);
3747                 _frontLength = _input.length - r.length;
3748             }
3749             return _input[0 .. _frontLength];
3750         }
3751 
3752         void popFront()
3753         {
3754             assert(!empty, "Attempting to popFront an empty splitter.");
3755             if (_frontLength == _unComputed)
3756             {
3757                 front;
3758             }
3759             assert(_frontLength <= _input.length);
3760             if (_frontLength == _input.length)
3761             {
3762                 // no more input and need to fetch => done
3763                 _frontLength = _atEnd;
3764 
3765                 // Probably don't need this, but just for consistency:
3766                 _backLength = _atEnd;
3767             }
3768             else
3769             {
3770                 _input = _input[_frontLength + _separatorLength .. _input.length];
3771                 _frontLength = _unComputed;
3772             }
3773         }
3774 
3775         static if (isForwardRange!Range)
3776         {
3777             @property typeof(this) save()
3778             {
3779                 auto ret = this;
3780                 ret._input = _input.save;
3781                 return ret;
3782             }
3783         }
3784 
3785         static if (isBidirectionalRange!Range)
3786         {
3787             @property Range back()
3788             {
3789                 assert(!empty, "Attempting to fetch the back of an empty splitter.");
3790                 if (_backLength == _unComputed)
3791                 {
3792                     immutable lastIndex = lastIndexOf(_input, _separator);
3793                     if (lastIndex == -1)
3794                     {
3795                         _backLength = _input.length;
3796                     }
3797                     else
3798                     {
3799                         _backLength = _input.length - lastIndex - 1;
3800                     }
3801                 }
3802                 return _input[_input.length - _backLength .. _input.length];
3803             }
3804 
3805             void popBack()
3806             {
3807                 assert(!empty, "Attempting to popBack an empty splitter.");
3808                 if (_backLength == _unComputed)
3809                 {
3810                     // evaluate back to make sure it's computed
3811                     back;
3812                 }
3813                 assert(_backLength <= _input.length);
3814                 if (_backLength == _input.length)
3815                 {
3816                     // no more input and need to fetch => done
3817                     _frontLength = _atEnd;
3818                     _backLength = _atEnd;
3819                 }
3820                 else
3821                 {
3822                     _input = _input[0 .. _input.length - _backLength - _separatorLength];
3823                     _backLength = _unComputed;
3824                 }
3825             }
3826         }
3827     }
3828 
3829     return Result(r, s);
3830 }
3831 
3832 ///
3833 @safe unittest
3834 {
3835     import std.algorithm.comparison : equal;
3836 
3837     assert(equal(splitter("hello  world", ' '), [ "hello", "", "world" ]));
3838     int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
3839     int[][] w = [ [1, 2], [], [3], [4, 5], [] ];
3840     assert(equal(splitter(a, 0), w));
3841     a = [ 0 ];
3842     assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ]));
3843     a = [ 0, 1 ];
3844     assert(equal(splitter(a, 0), [ [], [1] ]));
3845     w = [ [0], [1], [2] ];
3846     assert(equal(splitter!"a.front == b"(w, 1), [ [[0]], [[2]] ]));
3847 }
3848 
3849 @safe unittest
3850 {
3851     import std.algorithm;
3852     import std.array : array;
3853     import std.internal.test.dummyrange;
3854     import std.range : retro;
3855 
3856     assert(equal(splitter("hello  world", ' '), [ "hello", "", "world" ]));
3857     assert(equal(splitter("žlutoučkýřkůň", 'ř'), [ "žlutoučký", "kůň" ]));
3858     int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
3859     int[][] w = [ [1, 2], [], [3], [4, 5], [] ];
3860     static assert(isForwardRange!(typeof(splitter(a, 0))));
3861 
3862     assert(equal(splitter(a, 0), w));
3863     a = null;
3864     assert(equal(splitter(a, 0),  (int[][]).init));
3865     a = [ 0 ];
3866     assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ][]));
3867     a = [ 0, 1 ];
3868     assert(equal(splitter(a, 0), [ [], [1] ][]));
3869 
3870     // Thoroughly exercise the bidirectional stuff.
3871     auto str = "abc abcd abcde ab abcdefg abcdefghij ab ac ar an at ada";
3872     assert(equal(
3873         retro(splitter(str, 'a')),
3874         retro(array(splitter(str, 'a')))
3875     ));
3876 
3877     // Test interleaving front and back.
3878     auto split = splitter(str, 'a');
3879     assert(split.front == "");
3880     assert(split.back == "");
3881     split.popBack();
3882     assert(split.back == "d");
3883     split.popFront();
3884     assert(split.front == "bc ");
3885     assert(split.back == "d");
3886     split.popFront();
3887     split.popBack();
3888     assert(split.back == "t ");
3889     split.popBack();
3890     split.popBack();
3891     split.popFront();
3892     split.popFront();
3893     assert(split.front == "b ");
3894     assert(split.back == "r ");
3895 
3896     foreach (DummyType; AllDummyRanges) {  // Bug 4408
3897         static if (isRandomAccessRange!DummyType)
3898         {
3899             static assert(isBidirectionalRange!DummyType);
3900             DummyType d;
3901             auto s = splitter(d, 5);
3902             assert(equal(s.front, [1,2,3,4]));
3903             assert(equal(s.back, [6,7,8,9,10]));
3904 
3905             auto s2 = splitter(d, [4, 5]);
3906             assert(equal(s2.front, [1,2,3]));
3907         }
3908     }
3909 }
3910 @safe unittest
3911 {
3912     import std.algorithm;
3913     import std.range;
3914     auto L = retro(iota(1L, 10L));
3915     auto s = splitter(L, 5L);
3916     assert(equal(s.front, [9L, 8L, 7L, 6L]));
3917     s.popFront();
3918     assert(equal(s.front, [4L, 3L, 2L, 1L]));
3919     s.popFront();
3920     assert(s.empty);
3921 }
3922 
3923 /**
3924 Similar to the previous overload of $(D splitter), except this one uses another
3925 range as a separator. This can be used with any narrow string type or sliceable
3926 range type, but is most popular with string types. The predicate is passed to
3927 $(REF binaryFun, std,functional), and can either accept a string, or any callable
3928 that can be executed via $(D pred(r.front, s.front)).
3929 
3930 Two adjacent separators are considered to surround an empty element in
3931 the split range. Use $(D filter!(a => !a.empty)) on the result to compress
3932 empty elements.
3933 
3934 Params:
3935     pred = The predicate for comparing each element with the separator,
3936         defaulting to $(D "a == b").
3937     r = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be
3938         split.
3939     s = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
3940         be treated as the separator between segments of $(D r) to be split.
3941 
3942 Constraints:
3943     The predicate $(D pred) needs to accept an element of $(D r) and an
3944     element of $(D s).
3945 
3946 Returns:
3947     An input range of the subranges of elements between separators. If $(D r)
3948     is a forward range or $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives),
3949     the returned range will be likewise.
3950 
3951 See_Also: $(REF _splitter, std,regex) for a version that splits using a regular
3952 expression defined separator.
3953  */
3954 auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
3955 if (is(typeof(binaryFun!pred(r.front, s.front)) : bool)
3956         && (hasSlicing!Range || isNarrowString!Range)
3957         && isForwardRange!Separator
3958         && (hasLength!Separator || isNarrowString!Separator))
3959 {
3960     import std.algorithm.searching : find;
3961     import std.conv : unsigned;
3962 
3963     static struct Result
3964     {
3965     private:
3966         Range _input;
3967         Separator _separator;
3968         // _frontLength == size_t.max means empty
3969         size_t _frontLength = size_t.max;
3970         static if (isBidirectionalRange!Range)
3971             size_t _backLength = size_t.max;
3972 
3973         @property auto separatorLength() { return _separator.length; }
3974 
3975         void ensureFrontLength()
3976         {
3977             if (_frontLength != _frontLength.max) return;
3978             assert(!_input.empty);
3979             // compute front length
3980             _frontLength = (_separator.empty) ? 1 :
3981                            _input.length - find!pred(_input, _separator).length;
3982             static if (isBidirectionalRange!Range)
3983                 if (_frontLength == _input.length) _backLength = _frontLength;
3984         }
3985 
3986         void ensureBackLength()
3987         {
3988             static if (isBidirectionalRange!Range)
3989                 if (_backLength != _backLength.max) return;
3990             assert(!_input.empty);
3991             // compute back length
3992             static if (isBidirectionalRange!Range && isBidirectionalRange!Separator)
3993             {
3994                 import std.range : retro;
3995                 _backLength = _input.length -
3996                     find!pred(retro(_input), retro(_separator)).source.length;
3997             }
3998         }
3999 
4000     public:
4001         this(Range input, Separator separator)
4002         {
4003             _input = input;
4004             _separator = separator;
4005         }
4006 
4007         @property Range front()
4008         {
4009             assert(!empty, "Attempting to fetch the front of an empty splitter.");
4010             ensureFrontLength();
4011             return _input[0 .. _frontLength];
4012         }
4013 
4014         static if (isInfinite!Range)
4015         {
4016             enum bool empty = false;  // Propagate infiniteness
4017         }
4018         else
4019         {
4020             @property bool empty()
4021             {
4022                 return _frontLength == size_t.max && _input.empty;
4023             }
4024         }
4025 
4026         void popFront()
4027         {
4028             assert(!empty, "Attempting to popFront an empty splitter.");
4029             ensureFrontLength();
4030             if (_frontLength == _input.length)
4031             {
4032                 // done, there's no separator in sight
4033                 _input = _input[_frontLength .. _frontLength];
4034                 _frontLength = _frontLength.max;
4035                 static if (isBidirectionalRange!Range)
4036                     _backLength = _backLength.max;
4037                 return;
4038             }
4039             if (_frontLength + separatorLength == _input.length)
4040             {
4041                 // Special case: popping the first-to-last item; there is
4042                 // an empty item right after this.
4043                 _input = _input[_input.length .. _input.length];
4044                 _frontLength = 0;
4045                 static if (isBidirectionalRange!Range)
4046                     _backLength = 0;
4047                 return;
4048             }
4049             // Normal case, pop one item and the separator, get ready for
4050             // reading the next item
4051             _input = _input[_frontLength + separatorLength .. _input.length];
4052             // mark _frontLength as uninitialized
4053             _frontLength = _frontLength.max;
4054         }
4055 
4056         static if (isForwardRange!Range)
4057         {
4058             @property typeof(this) save()
4059             {
4060                 auto ret = this;
4061                 ret._input = _input.save;
4062                 return ret;
4063             }
4064         }
4065     }
4066 
4067     return Result(r, s);
4068 }
4069 
4070 ///
4071 @safe unittest
4072 {
4073     import std.algorithm.comparison : equal;
4074 
4075     assert(equal(splitter("hello  world", "  "), [ "hello", "world" ]));
4076     int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
4077     int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ];
4078     assert(equal(splitter(a, [0, 0]), w));
4079     a = [ 0, 0 ];
4080     assert(equal(splitter(a, [0, 0]), [ (int[]).init, (int[]).init ]));
4081     a = [ 0, 0, 1 ];
4082     assert(equal(splitter(a, [0, 0]), [ [], [1] ]));
4083 }
4084 
4085 @safe unittest
4086 {
4087     import std.algorithm.comparison : equal;
4088     import std.typecons : Tuple;
4089 
4090     alias C = Tuple!(int, "x", int, "y");
4091     auto a = [C(1,0), C(2,0), C(3,1), C(4,0)];
4092     assert(equal(splitter!"a.x == b"(a, [2, 3]), [ [C(1,0)], [C(4,0)] ]));
4093 }
4094 
4095 @safe unittest
4096 {
4097     import std.algorithm.comparison : equal;
4098     import std.array : split;
4099     import std.conv : text;
4100 
4101     auto s = ",abc, de, fg,hi,";
4102     auto sp0 = splitter(s, ',');
4103     assert(equal(sp0, ["", "abc", " de", " fg", "hi", ""][]));
4104 
4105     auto s1 = ", abc, de,  fg, hi, ";
4106     auto sp1 = splitter(s1, ", ");
4107     assert(equal(sp1, ["", "abc", "de", " fg", "hi", ""][]));
4108     static assert(isForwardRange!(typeof(sp1)));
4109 
4110     int[] a = [ 1, 2, 0, 3, 0, 4, 5, 0 ];
4111     int[][] w = [ [1, 2], [3], [4, 5], [] ];
4112     uint i;
4113     foreach (e; splitter(a, 0))
4114     {
4115         assert(i < w.length);
4116         assert(e == w[i++]);
4117     }
4118     assert(i == w.length);
4119     // // Now go back
4120     // auto s2 = splitter(a, 0);
4121 
4122     // foreach (e; retro(s2))
4123     // {
4124     //     assert(i > 0);
4125     //     assert(equal(e, w[--i]), text(e));
4126     // }
4127     // assert(i == 0);
4128 
4129     wstring names = ",peter,paul,jerry,";
4130     auto words = split(names, ",");
4131     assert(walkLength(words) == 5, text(walkLength(words)));
4132 }
4133 
4134 @safe unittest
4135 {
4136     int[][] a = [ [1], [2], [0], [3], [0], [4], [5], [0] ];
4137     int[][][] w = [ [[1], [2]], [[3]], [[4], [5]], [] ];
4138     uint i;
4139     foreach (e; splitter!"a.front == 0"(a, 0))
4140     {
4141         assert(i < w.length);
4142         assert(e == w[i++]);
4143     }
4144     assert(i == w.length);
4145 }
4146 
4147 @safe unittest
4148 {
4149     import std.algorithm.comparison : equal;
4150     auto s6 = ",";
4151     auto sp6 = splitter(s6, ',');
4152     foreach (e; sp6) {}
4153     assert(equal(sp6, ["", ""][]));
4154 }
4155 
4156 @safe unittest
4157 {
4158     import std.algorithm.comparison : equal;
4159 
4160     // Issue 10773
4161     auto s = splitter("abc", "");
4162     assert(s.equal(["a", "b", "c"]));
4163 }
4164 
4165 @safe unittest
4166 {
4167     import std.algorithm.comparison : equal;
4168 
4169     // Test by-reference separator
4170     class RefSep {
4171     @safe:
4172         string _impl;
4173         this(string s) { _impl = s; }
4174         @property empty() { return _impl.empty; }
4175         @property auto front() { return _impl.front; }
4176         void popFront() { _impl = _impl[1..$]; }
4177         @property RefSep save() { return new RefSep(_impl); }
4178         @property auto length() { return _impl.length; }
4179     }
4180     auto sep = new RefSep("->");
4181     auto data = "i->am->pointing";
4182     auto words = splitter(data, sep);
4183     assert(words.equal([ "i", "am", "pointing" ]));
4184 }
4185 
4186 /**
4187 
4188 Similar to the previous overload of $(D splitter), except this one does not use a separator.
4189 Instead, the predicate is an unary function on the input range's element type.
4190 The $(D isTerminator) predicate is passed to $(REF unaryFun, std,functional) and can
4191 either accept a string, or any callable that can be executed via $(D pred(element, s)).
4192 
4193 Two adjacent separators are considered to surround an empty element in
4194 the split range. Use $(D filter!(a => !a.empty)) on the result to compress
4195 empty elements.
4196 
4197 Params:
4198     isTerminator = The predicate for deciding where to split the range.
4199     input = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
4200         be split.
4201 
4202 Constraints:
4203     The predicate $(D isTerminator) needs to accept an element of $(D input).
4204 
4205 Returns:
4206     An input range of the subranges of elements between separators. If $(D input)
4207     is a forward range or $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives),
4208     the returned range will be likewise.
4209 
4210 See_Also: $(REF _splitter, std,regex) for a version that splits using a regular
4211 expression defined separator.
4212  */
4213 auto splitter(alias isTerminator, Range)(Range input)
4214 if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(input.front))))
4215 {
4216     return SplitterResult!(unaryFun!isTerminator, Range)(input);
4217 }
4218 
4219 ///
4220 @safe unittest
4221 {
4222     import std.algorithm.comparison : equal;
4223     import std.range.primitives : front;
4224 
4225     assert(equal(splitter!(a => a == ' ')("hello  world"), [ "hello", "", "world" ]));
4226     int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
4227     int[][] w = [ [1, 2], [], [3], [4, 5], [] ];
4228     assert(equal(splitter!(a => a == 0)(a), w));
4229     a = [ 0 ];
4230     assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ]));
4231     a = [ 0, 1 ];
4232     assert(equal(splitter!(a => a == 0)(a), [ [], [1] ]));
4233     w = [ [0], [1], [2] ];
4234     assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ]));
4235 }
4236 
4237 private struct SplitterResult(alias isTerminator, Range)
4238 {
4239     import std.algorithm.searching : find;
4240     enum fullSlicing = (hasLength!Range && hasSlicing!Range) || isSomeString!Range;
4241 
4242     private Range _input;
4243     private size_t _end = 0;
4244     static if (!fullSlicing)
4245         private Range _next;
4246 
4247     private void findTerminator()
4248     {
4249         static if (fullSlicing)
4250         {
4251             auto r = find!isTerminator(_input.save);
4252             _end = _input.length - r.length;
4253         }
4254         else
4255             for ( _end = 0; !_next.empty ; _next.popFront)
4256             {
4257                 if (isTerminator(_next.front))
4258                     break;
4259                 ++_end;
4260             }
4261     }
4262 
4263     this(Range input)
4264     {
4265         _input = input;
4266         static if (!fullSlicing)
4267             _next = _input.save;
4268 
4269         if (!_input.empty)
4270             findTerminator();
4271         else
4272             _end = size_t.max;
4273     }
4274 
4275     static if (isInfinite!Range)
4276     {
4277         enum bool empty = false;  // Propagate infiniteness.
4278     }
4279     else
4280     {
4281         @property bool empty()
4282         {
4283             return _end == size_t.max;
4284         }
4285     }
4286 
4287     @property auto front()
4288     {
4289         version(assert)
4290         {
4291             import core.exception : RangeError;
4292             if (empty)
4293                 throw new RangeError();
4294         }
4295         static if (fullSlicing)
4296             return _input[0 .. _end];
4297         else
4298         {
4299             import std.range : takeExactly;
4300             return _input.takeExactly(_end);
4301         }
4302     }
4303 
4304     void popFront()
4305     {
4306         version(assert)
4307         {
4308             import core.exception : RangeError;
4309             if (empty)
4310                 throw new RangeError();
4311         }
4312 
4313         static if (fullSlicing)
4314         {
4315             _input = _input[_end .. _input.length];
4316             if (_input.empty)
4317             {
4318                 _end = size_t.max;
4319                 return;
4320             }
4321             _input.popFront();
4322         }
4323         else
4324         {
4325             if (_next.empty)
4326             {
4327                 _input = _next;
4328                 _end = size_t.max;
4329                 return;
4330             }
4331             _next.popFront();
4332             _input = _next.save;
4333         }
4334         findTerminator();
4335     }
4336 
4337     @property typeof(this) save()
4338     {
4339         auto ret = this;
4340         ret._input = _input.save;
4341         static if (!fullSlicing)
4342             ret._next = _next.save;
4343         return ret;
4344     }
4345 }
4346 
4347 @safe unittest
4348 {
4349     import std.algorithm.comparison : equal;
4350     import std.range : iota;
4351 
4352     auto L = iota(1L, 10L);
4353     auto s = splitter(L, [5L, 6L]);
4354     assert(equal(s.front, [1L, 2L, 3L, 4L]));
4355     s.popFront();
4356     assert(equal(s.front, [7L, 8L, 9L]));
4357     s.popFront();
4358     assert(s.empty);
4359 }
4360 
4361 @safe unittest
4362 {
4363     import std.algorithm.comparison : equal;
4364     import std.algorithm.internal : algoFormat;
4365     import std.internal.test.dummyrange;
4366 
4367     void compare(string sentence, string[] witness)
4368     {
4369         auto r = splitter!"a == ' '"(sentence);
4370         assert(equal(r.save, witness), algoFormat("got: %(%s, %) expected: %(%s, %)", r, witness));
4371     }
4372 
4373     compare(" Mary  has a little lamb.   ",
4374             ["", "Mary", "", "has", "a", "little", "lamb.", "", "", ""]);
4375     compare("Mary  has a little lamb.   ",
4376             ["Mary", "", "has", "a", "little", "lamb.", "", "", ""]);
4377     compare("Mary  has a little lamb.",
4378             ["Mary", "", "has", "a", "little", "lamb."]);
4379     compare("", (string[]).init);
4380     compare(" ", ["", ""]);
4381 
4382     static assert(isForwardRange!(typeof(splitter!"a == ' '"("ABC"))));
4383 
4384     foreach (DummyType; AllDummyRanges)
4385     {
4386         static if (isRandomAccessRange!DummyType)
4387         {
4388             auto rangeSplit = splitter!"a == 5"(DummyType.init);
4389             assert(equal(rangeSplit.front, [1,2,3,4]));
4390             rangeSplit.popFront();
4391             assert(equal(rangeSplit.front, [6,7,8,9,10]));
4392         }
4393     }
4394 }
4395 
4396 @safe unittest
4397 {
4398     import std.algorithm.comparison : equal;
4399     import std.algorithm.internal : algoFormat;
4400     import std.range;
4401 
4402     struct Entry
4403     {
4404         int low;
4405         int high;
4406         int[][] result;
4407     }
4408     Entry[] entries = [
4409         Entry(0, 0, []),
4410         Entry(0, 1, [[0]]),
4411         Entry(1, 2, [[], []]),
4412         Entry(2, 7, [[2], [4], [6]]),
4413         Entry(1, 8, [[], [2], [4], [6], []]),
4414     ];
4415     foreach ( entry ; entries )
4416     {
4417         auto a = iota(entry.low, entry.high).filter!"true"();
4418         auto b = splitter!"a%2"(a);
4419         assert(equal!equal(b.save, entry.result), algoFormat("got: %(%s, %) expected: %(%s, %)", b, entry.result));
4420     }
4421 }
4422 
4423 @safe unittest
4424 {
4425     import std.algorithm.comparison : equal;
4426     import std.uni : isWhite;
4427 
4428     //@@@6791@@@
4429     assert(equal(
4430         splitter("là dove terminava quella valle"),
4431         ["là", "dove", "terminava", "quella", "valle"]
4432     ));
4433     assert(equal(
4434         splitter!(std.uni.isWhite)("là dove terminava quella valle"),
4435         ["là", "dove", "terminava", "quella", "valle"]
4436     ));
4437     assert(equal(splitter!"a=='本'"("日本語"), ["日", "語"]));
4438 }
4439 
4440 /++
4441 Lazily splits the string $(D s) into words, using whitespace as the delimiter.
4442 
4443 This function is string specific and, contrary to
4444 $(D splitter!(std.uni.isWhite)), runs of whitespace will be merged together
4445 (no empty tokens will be produced).
4446 
4447 Params:
4448     s = The string to be split.
4449 
4450 Returns:
4451     An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of slices of
4452     the original string split by whitespace.
4453  +/
4454 auto splitter(C)(C[] s)
4455 if (isSomeChar!C)
4456 {
4457     import std.algorithm.searching : find;
4458     static struct Result
4459     {
4460     private:
4461         import core.exception : RangeError;
4462         C[] _s;
4463         size_t _frontLength;
4464 
4465         void getFirst() pure @safe
4466         {
4467             import std.uni : isWhite;
4468 
4469             auto r = find!(isWhite)(_s);
4470             _frontLength = _s.length - r.length;
4471         }
4472 
4473     public:
4474         this(C[] s) pure @safe
4475         {
4476             import std..string : strip;
4477             _s = s.strip();
4478             getFirst();
4479         }
4480 
4481         @property C[] front() pure @safe
4482         {
4483             version(assert) if (empty) throw new RangeError();
4484             return _s[0 .. _frontLength];
4485         }
4486 
4487         void popFront() pure @safe
4488         {
4489             import std..string : stripLeft;
4490             version(assert) if (empty) throw new RangeError();
4491             _s = _s[_frontLength .. $].stripLeft();
4492             getFirst();
4493         }
4494 
4495         @property bool empty() const @safe pure nothrow
4496         {
4497             return _s.empty;
4498         }
4499 
4500         @property inout(Result) save() inout @safe pure nothrow
4501         {
4502             return this;
4503         }
4504     }
4505     return Result(s);
4506 }
4507 
4508 ///
4509 @safe pure unittest
4510 {
4511     import std.algorithm.comparison : equal;
4512     auto a = " a     bcd   ef gh ";
4513     assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][]));
4514 }
4515 
4516 @safe pure unittest
4517 {
4518     import std.algorithm.comparison : equal;
4519     import std.meta : AliasSeq;
4520     foreach (S; AliasSeq!(string, wstring, dstring))
4521     {
4522         import std.conv : to;
4523         S a = " a     bcd   ef gh ";
4524         assert(equal(splitter(a), [to!S("a"), to!S("bcd"), to!S("ef"), to!S("gh")]));
4525         a = "";
4526         assert(splitter(a).empty);
4527     }
4528 
4529     immutable string s = " a     bcd   ef gh ";
4530     assert(equal(splitter(s), ["a", "bcd", "ef", "gh"][]));
4531 }
4532 
4533 @safe unittest
4534 {
4535     import std.conv : to;
4536     import std..string : strip;
4537 
4538     // TDPL example, page 8
4539     uint[string] dictionary;
4540     char[][3] lines;
4541     lines[0] = "line one".dup;
4542     lines[1] = "line \ttwo".dup;
4543     lines[2] = "yah            last   line\ryah".dup;
4544     foreach (line; lines)
4545     {
4546        foreach (word; splitter(strip(line)))
4547        {
4548             if (word in dictionary) continue; // Nothing to do
4549             auto newID = dictionary.length;
4550             dictionary[to!string(word)] = cast(uint) newID;
4551         }
4552     }
4553     assert(dictionary.length == 5);
4554     assert(dictionary["line"]== 0);
4555     assert(dictionary["one"]== 1);
4556     assert(dictionary["two"]== 2);
4557     assert(dictionary["yah"]== 3);
4558     assert(dictionary["last"]== 4);
4559 }
4560 
4561 @safe unittest
4562 {
4563     import std.algorithm.comparison : equal;
4564     import std.algorithm.internal : algoFormat;
4565     import std.array : split;
4566     import std.conv : text;
4567 
4568     // Check consistency:
4569     // All flavors of split should produce the same results
4570     foreach (input; [(int[]).init,
4571                      [0],
4572                      [0, 1, 0],
4573                      [1, 1, 0, 0, 1, 1],
4574                     ])
4575     {
4576         foreach (s; [0, 1])
4577         {
4578             auto result = split(input, s);
4579 
4580             assert(equal(result, split(input, [s])), algoFormat(`"[%(%s,%)]"`, split(input, [s])));
4581             //assert(equal(result, split(input, [s].filter!"true"())));                          //Not yet implemented
4582             assert(equal(result, split!((a) => a == s)(input)), text(split!((a) => a == s)(input)));
4583 
4584             //assert(equal!equal(result, split(input.filter!"true"(), s)));                      //Not yet implemented
4585             //assert(equal!equal(result, split(input.filter!"true"(), [s])));                    //Not yet implemented
4586             //assert(equal!equal(result, split(input.filter!"true"(), [s].filter!"true"())));    //Not yet implemented
4587             assert(equal!equal(result, split!((a) => a == s)(input.filter!"true"())));
4588 
4589             assert(equal(result, splitter(input, s)));
4590             assert(equal(result, splitter(input, [s])));
4591             //assert(equal(result, splitter(input, [s].filter!"true"())));                       //Not yet implemented
4592             assert(equal(result, splitter!((a) => a == s)(input)));
4593 
4594             //assert(equal!equal(result, splitter(input.filter!"true"(), s)));                   //Not yet implemented
4595             //assert(equal!equal(result, splitter(input.filter!"true"(), [s])));                 //Not yet implemented
4596             //assert(equal!equal(result, splitter(input.filter!"true"(), [s].filter!"true"()))); //Not yet implemented
4597             assert(equal!equal(result, splitter!((a) => a == s)(input.filter!"true"())));
4598         }
4599     }
4600     foreach (input; [string.init,
4601                      " ",
4602                      "  hello ",
4603                      "hello   hello",
4604                      " hello   what heck   this ?  "
4605                     ])
4606     {
4607         foreach (s; [' ', 'h'])
4608         {
4609             auto result = split(input, s);
4610 
4611             assert(equal(result, split(input, [s])));
4612             //assert(equal(result, split(input, [s].filter!"true"())));                          //Not yet implemented
4613             assert(equal(result, split!((a) => a == s)(input)));
4614 
4615             //assert(equal!equal(result, split(input.filter!"true"(), s)));                      //Not yet implemented
4616             //assert(equal!equal(result, split(input.filter!"true"(), [s])));                    //Not yet implemented
4617             //assert(equal!equal(result, split(input.filter!"true"(), [s].filter!"true"())));    //Not yet implemented
4618             assert(equal!equal(result, split!((a) => a == s)(input.filter!"true"())));
4619 
4620             assert(equal(result, splitter(input, s)));
4621             assert(equal(result, splitter(input, [s])));
4622             //assert(equal(result, splitter(input, [s].filter!"true"())));                       //Not yet implemented
4623             assert(equal(result, splitter!((a) => a == s)(input)));
4624 
4625             //assert(equal!equal(result, splitter(input.filter!"true"(), s)));                   //Not yet implemented
4626             //assert(equal!equal(result, splitter(input.filter!"true"(), [s])));                 //Not yet implemented
4627             //assert(equal!equal(result, splitter(input.filter!"true"(), [s].filter!"true"()))); //Not yet implemented
4628             assert(equal!equal(result, splitter!((a) => a == s)(input.filter!"true"())));
4629         }
4630     }
4631 }
4632 
4633 // sum
4634 /**
4635 Sums elements of $(D r), which must be a finite
4636 $(REF_ALTTEXT input range, isInputRange, std,range,primitives). Although
4637 conceptually $(D sum(r)) is equivalent to $(LREF fold)!((a, b) => a +
4638 b)(r, 0), $(D sum) uses specialized algorithms to maximize accuracy,
4639 as follows.
4640 
4641 $(UL
4642 $(LI If $(D $(REF ElementType, std,range,primitives)!R) is a floating-point
4643 type and $(D R) is a
4644 $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives) with
4645 length and slicing, then $(D sum) uses the
4646 $(HTTP en.wikipedia.org/wiki/Pairwise_summation, pairwise summation)
4647 algorithm.)
4648 $(LI If $(D ElementType!R) is a floating-point type and $(D R) is a
4649 finite input range (but not a random-access range with slicing), then
4650 $(D sum) uses the $(HTTP en.wikipedia.org/wiki/Kahan_summation,
4651 Kahan summation) algorithm.)
4652 $(LI In all other cases, a simple element by element addition is done.)
4653 )
4654 
4655 For floating point inputs, calculations are made in
4656 $(DDLINK spec/type, Types, $(D real))
4657 precision for $(D real) inputs and in $(D double) precision otherwise
4658 (Note this is a special case that deviates from $(D fold)'s behavior,
4659 which would have kept $(D float) precision for a $(D float) range).
4660 For all other types, the calculations are done in the same type obtained
4661 from from adding two elements of the range, which may be a different
4662 type from the elements themselves (for example, in case of
4663 $(DDSUBLINK spec/type,integer-promotions, integral promotion)).
4664 
4665 A seed may be passed to $(D sum). Not only will this seed be used as an initial
4666 value, but its type will override all the above, and determine the algorithm
4667 and precision used for summation.
4668 
4669 Note that these specialized summing algorithms execute more primitive operations
4670 than vanilla summation. Therefore, if in certain cases maximum speed is required
4671 at expense of precision, one can use $(D fold!((a, b) => a + b)(r, 0)), which
4672 is not specialized for summation.
4673 
4674 Params:
4675     seed = the initial value of the summation
4676     r = a finite input range
4677 
4678 Returns:
4679     The sum of all the elements in the range r.
4680  */
4681 auto sum(R)(R r)
4682 if (isInputRange!R && !isInfinite!R && is(typeof(r.front + r.front)))
4683 {
4684     alias E = Unqual!(ElementType!R);
4685     static if (isFloatingPoint!E)
4686         alias Seed = typeof(E.init  + 0.0); //biggest of double/real
4687     else
4688         alias Seed = typeof(r.front + r.front);
4689     return sum(r, Unqual!Seed(0));
4690 }
4691 /// ditto
4692 auto sum(R, E)(R r, E seed)
4693 if (isInputRange!R && !isInfinite!R && is(typeof(seed = seed + r.front)))
4694 {
4695     static if (isFloatingPoint!E)
4696     {
4697         static if (hasLength!R && hasSlicing!R)
4698         {
4699             if (r.empty) return seed;
4700             return seed + sumPairwise!E(r);
4701         }
4702         else
4703             return sumKahan!E(seed, r);
4704     }
4705     else
4706     {
4707         return reduce!"a + b"(seed, r);
4708     }
4709 }
4710 
4711 // Pairwise summation http://en.wikipedia.org/wiki/Pairwise_summation
4712 private auto sumPairwise(F, R)(R data)
4713 if (isInputRange!R && !isInfinite!R)
4714 {
4715     import core.bitop : bsf;
4716     // Works for r with at least length < 2^^(64 + log2(16)), in keeping with the use of size_t
4717     // elsewhere in std.algorithm and std.range on 64 bit platforms. The 16 in log2(16) comes
4718     // from the manual unrolling in sumPairWise16
4719     F[64] store = void;
4720     size_t idx = 0;
4721 
4722     void collapseStore(T)(T k)
4723     {
4724         auto lastToKeep = idx - cast(uint) bsf(k+1);
4725         while (idx > lastToKeep)
4726         {
4727             store[idx - 1] += store[idx];
4728             --idx;
4729         }
4730     }
4731 
4732     static if (hasLength!R)
4733     {
4734         foreach (k; 0 .. data.length / 16)
4735         {
4736             static if (isRandomAccessRange!R && hasSlicing!R)
4737             {
4738                 store[idx] = sumPairwise16!F(data);
4739                 data = data[16 .. data.length];
4740             }
4741             else store[idx] = sumPairwiseN!(16, false, F)(data);
4742 
4743             collapseStore(k);
4744             ++idx;
4745         }
4746 
4747         size_t i = 0;
4748         foreach (el; data)
4749         {
4750             store[idx] = el;
4751             collapseStore(i);
4752             ++idx;
4753             ++i;
4754         }
4755     }
4756     else
4757     {
4758         size_t k = 0;
4759         while (!data.empty)
4760         {
4761             store[idx] = sumPairwiseN!(16, true, F)(data);
4762             collapseStore(k);
4763             ++idx;
4764             ++k;
4765         }
4766     }
4767 
4768     F s = store[idx - 1];
4769     foreach_reverse (j; 0 .. idx - 1)
4770         s += store[j];
4771 
4772     return s;
4773 }
4774 
4775 private auto sumPairwise16(F, R)(R r)
4776 if (isRandomAccessRange!R)
4777 {
4778     return (((cast(F) r[ 0] + r[ 1]) + (cast(F) r[ 2] + r[ 3]))
4779           + ((cast(F) r[ 4] + r[ 5]) + (cast(F) r[ 6] + r[ 7])))
4780          + (((cast(F) r[ 8] + r[ 9]) + (cast(F) r[10] + r[11]))
4781           + ((cast(F) r[12] + r[13]) + (cast(F) r[14] + r[15])));
4782 }
4783 
4784 private auto sumPair(bool needEmptyChecks, F, R)(ref R r)
4785 if (isForwardRange!R && !isRandomAccessRange!R)
4786 {
4787     static if (needEmptyChecks) if (r.empty) return F(0);
4788     F s0 = r.front;
4789     r.popFront();
4790     static if (needEmptyChecks) if (r.empty) return s0;
4791     s0 += r.front;
4792     r.popFront();
4793     return s0;
4794 }
4795 
4796 private auto sumPairwiseN(size_t N, bool needEmptyChecks, F, R)(ref R r)
4797 if (isForwardRange!R && !isRandomAccessRange!R)
4798 {
4799     import std.math : isPowerOf2;
4800     static assert(isPowerOf2(N));
4801     static if (N == 2) return sumPair!(needEmptyChecks, F)(r);
4802     else return sumPairwiseN!(N/2, needEmptyChecks, F)(r)
4803         + sumPairwiseN!(N/2, needEmptyChecks, F)(r);
4804 }
4805 
4806 // Kahan algo http://en.wikipedia.org/wiki/Kahan_summation_algorithm
4807 private auto sumKahan(Result, R)(Result result, R r)
4808 {
4809     static assert(isFloatingPoint!Result && isMutable!Result);
4810     Result c = 0;
4811     for (; !r.empty; r.popFront())
4812     {
4813         immutable y = r.front - c;
4814         immutable t = result + y;
4815         c = (t - result) - y;
4816         result = t;
4817     }
4818     return result;
4819 }
4820 
4821 /// Ditto
4822 @safe pure nothrow unittest
4823 {
4824     import std.range;
4825 
4826     //simple integral sumation
4827     assert(sum([ 1, 2, 3, 4]) == 10);
4828 
4829     //with integral promotion
4830     assert(sum([false, true, true, false, true]) == 3);
4831     assert(sum(ubyte.max.repeat(100)) == 25500);
4832 
4833     //The result may overflow
4834     assert(uint.max.repeat(3).sum()           ==  4294967293U );
4835     //But a seed can be used to change the sumation primitive
4836     assert(uint.max.repeat(3).sum(ulong.init) == 12884901885UL);
4837 
4838     //Floating point sumation
4839     assert(sum([1.0, 2.0, 3.0, 4.0]) == 10);
4840 
4841     //Floating point operations have double precision minimum
4842     static assert(is(typeof(sum([1F, 2F, 3F, 4F])) == double));
4843     assert(sum([1F, 2, 3, 4]) == 10);
4844 
4845     //Force pair-wise floating point sumation on large integers
4846     import std.math : approxEqual;
4847     assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0)
4848                .approxEqual((ulong.max / 2) * 4096.0 + 4096^^2 / 2));
4849 }
4850 
4851 @safe pure nothrow unittest
4852 {
4853     static assert(is(typeof(sum([cast( byte) 1])) ==  int));
4854     static assert(is(typeof(sum([cast(ubyte) 1])) ==  int));
4855     static assert(is(typeof(sum([  1,   2,   3,   4])) ==  int));
4856     static assert(is(typeof(sum([ 1U,  2U,  3U,  4U])) == uint));
4857     static assert(is(typeof(sum([ 1L,  2L,  3L,  4L])) ==  long));
4858     static assert(is(typeof(sum([1UL, 2UL, 3UL, 4UL])) == ulong));
4859 
4860     int[] empty;
4861     assert(sum(empty) == 0);
4862     assert(sum([42]) == 42);
4863     assert(sum([42, 43]) == 42 + 43);
4864     assert(sum([42, 43, 44]) == 42 + 43 + 44);
4865     assert(sum([42, 43, 44, 45]) == 42 + 43 + 44 + 45);
4866 }
4867 
4868 @safe pure nothrow unittest
4869 {
4870     static assert(is(typeof(sum([1.0, 2.0, 3.0, 4.0])) == double));
4871     static assert(is(typeof(sum([ 1F,  2F,  3F,  4F])) == double));
4872     const(float[]) a = [1F, 2F, 3F, 4F];
4873     static assert(is(typeof(sum(a)) == double));
4874     const(float)[] b = [1F, 2F, 3F, 4F];
4875     static assert(is(typeof(sum(a)) == double));
4876 
4877     double[] empty;
4878     assert(sum(empty) == 0);
4879     assert(sum([42.]) == 42);
4880     assert(sum([42., 43.]) == 42 + 43);
4881     assert(sum([42., 43., 44.]) == 42 + 43 + 44);
4882     assert(sum([42., 43., 44., 45.5]) == 42 + 43 + 44 + 45.5);
4883 }
4884 
4885 @safe pure nothrow unittest
4886 {
4887     import std.container;
4888     static assert(is(typeof(sum(SList!float()[])) == double));
4889     static assert(is(typeof(sum(SList!double()[])) == double));
4890     static assert(is(typeof(sum(SList!real()[])) == real));
4891 
4892     assert(sum(SList!double()[]) == 0);
4893     assert(sum(SList!double(1)[]) == 1);
4894     assert(sum(SList!double(1, 2)[]) == 1 + 2);
4895     assert(sum(SList!double(1, 2, 3)[]) == 1 + 2 + 3);
4896     assert(sum(SList!double(1, 2, 3, 4)[]) == 10);
4897 }
4898 
4899 @safe pure nothrow unittest // 12434
4900 {
4901     immutable a = [10, 20];
4902     auto s1 = sum(a);             // Error
4903     auto s2 = a.map!(x => x).sum; // Error
4904 }
4905 
4906 @system unittest
4907 {
4908     import std.bigint;
4909     import std.range;
4910 
4911     immutable BigInt[] a = BigInt("1_000_000_000_000_000_000").repeat(10).array();
4912     immutable ulong[]  b = (ulong.max/2).repeat(10).array();
4913     auto sa = a.sum();
4914     auto sb = b.sum(BigInt(0)); //reduce ulongs into bigint
4915     assert(sa == BigInt("10_000_000_000_000_000_000"));
4916     assert(sb == (BigInt(ulong.max/2) * 10));
4917 }
4918 
4919 @safe pure nothrow @nogc unittest
4920 {
4921     import std.range;
4922     foreach (n; iota(50))
4923         assert(repeat(1.0, n).sum == n);
4924 }
4925 
4926 // uniq
4927 /**
4928 Lazily iterates unique consecutive elements of the given range (functionality
4929 akin to the $(HTTP wikipedia.org/wiki/_Uniq, _uniq) system
4930 utility). Equivalence of elements is assessed by using the predicate
4931 $(D pred), by default $(D "a == b"). The predicate is passed to
4932 $(REF binaryFun, std,functional), and can either accept a string, or any callable
4933 that can be executed via $(D pred(element, element)). If the given range is
4934 bidirectional, $(D uniq) also yields a
4935 $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives).
4936 
4937 Params:
4938     pred = Predicate for determining equivalence between range elements.
4939     r = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of
4940         elements to filter.
4941 
4942 Returns:
4943     An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of
4944     consecutively unique elements in the original range. If $(D r) is also a
4945     forward range or bidirectional range, the returned range will be likewise.
4946 */
4947 auto uniq(alias pred = "a == b", Range)(Range r)
4948 if (isInputRange!Range && is(typeof(binaryFun!pred(r.front, r.front)) == bool))
4949 {
4950     return UniqResult!(binaryFun!pred, Range)(r);
4951 }
4952 
4953 ///
4954 @safe unittest
4955 {
4956     import std.algorithm.comparison : equal;
4957     import std.algorithm.mutation : copy;
4958 
4959     int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
4960     assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][]));
4961 
4962     // Filter duplicates in-place using copy
4963     arr.length -= arr.uniq().copy(arr).length;
4964     assert(arr == [ 1, 2, 3, 4, 5 ]);
4965 
4966     // Note that uniqueness is only determined consecutively; duplicated
4967     // elements separated by an intervening different element will not be
4968     // eliminated:
4969     assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1]));
4970 }
4971 
4972 private struct UniqResult(alias pred, Range)
4973 {
4974     Range _input;
4975 
4976     this(Range input)
4977     {
4978         _input = input;
4979     }
4980 
4981     auto opSlice()
4982     {
4983         return this;
4984     }
4985 
4986     void popFront()
4987     {
4988         assert(!empty, "Attempting to popFront an empty uniq.");
4989         auto last = _input.front;
4990         do
4991         {
4992             _input.popFront();
4993         }
4994         while (!_input.empty && pred(last, _input.front));
4995     }
4996 
4997     @property ElementType!Range front()
4998     {
4999         assert(!empty, "Attempting to fetch the front of an empty uniq.");
5000         return _input.front;
5001     }
5002 
5003     static if (isBidirectionalRange!Range)
5004     {
5005         void popBack()
5006         {
5007             assert(!empty, "Attempting to popBack an empty uniq.");
5008             auto last = _input.back;
5009             do
5010             {
5011                 _input.popBack();
5012             }
5013             while (!_input.empty && pred(last, _input.back));
5014         }
5015 
5016         @property ElementType!Range back()
5017         {
5018             assert(!empty, "Attempting to fetch the back of an empty uniq.");
5019             return _input.back;
5020         }
5021     }
5022 
5023     static if (isInfinite!Range)
5024     {
5025         enum bool empty = false;  // Propagate infiniteness.
5026     }
5027     else
5028     {
5029         @property bool empty() { return _input.empty; }
5030     }
5031 
5032     static if (isForwardRange!Range)
5033     {
5034         @property typeof(this) save() {
5035             return typeof(this)(_input.save);
5036         }
5037     }
5038 }
5039 
5040 @safe unittest
5041 {
5042     import std.algorithm.comparison : equal;
5043     import std.internal.test.dummyrange;
5044     import std.range;
5045 
5046     int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
5047     auto r = uniq(arr);
5048     static assert(isForwardRange!(typeof(r)));
5049 
5050     assert(equal(r, [ 1, 2, 3, 4, 5 ][]));
5051     assert(equal(retro(r), retro([ 1, 2, 3, 4, 5 ][])));
5052 
5053     foreach (DummyType; AllDummyRanges)
5054     {
5055         DummyType d;
5056         auto u = uniq(d);
5057         assert(equal(u, [1,2,3,4,5,6,7,8,9,10]));
5058 
5059         static assert(d.rt == RangeType.Input || isForwardRange!(typeof(u)));
5060 
5061         static if (d.rt >= RangeType.Bidirectional)
5062         {
5063             assert(equal(retro(u), [10,9,8,7,6,5,4,3,2,1]));
5064         }
5065     }
5066 }
5067 
5068 @safe unittest // https://issues.dlang.org/show_bug.cgi?id=17264
5069 {
5070     import std.algorithm.comparison : equal;
5071 
5072     const(int)[] var = [0, 1, 1, 2];
5073     assert(var.uniq.equal([0, 1, 2]));
5074 }
5075 
5076 /**
5077 Lazily computes all _permutations of $(D r) using $(HTTP
5078 en.wikipedia.org/wiki/Heap%27s_algorithm, Heap's algorithm).
5079 
5080 Returns:
5081 A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
5082 the elements of which are an $(REF indexed, std,range) view into $(D r).
5083 
5084 See_Also:
5085 $(REF nextPermutation, std,algorithm,sorting).
5086 */
5087 Permutations!Range permutations(Range)(Range r)
5088 if (isRandomAccessRange!Range && hasLength!Range)
5089 {
5090     return typeof(return)(r);
5091 }
5092 
5093 /// ditto
5094 struct Permutations(Range)
5095 if (isRandomAccessRange!Range && hasLength!Range)
5096 {
5097     private size_t[] _indices, _state;
5098     private Range _r;
5099     private bool _empty;
5100 
5101     // Explicitly undocumented. It will be removed in June 2017. @@@DEPRECATED_2017-06@@@
5102     deprecated("Private variable. Use front()")
5103     @property size_t[] indices() pure nothrow @nogc @safe { return _indices; }
5104 
5105     // Explicitly undocumented. It will be removed in June 2017. @@@DEPRECATED_2017-06@@@
5106     deprecated("Private variable. Don't set it manually")
5107     @property void indices(size_t[] indices) pure nothrow @nogc @safe { _indices = indices; }
5108 
5109     // Explicitly undocumented. It will be removed in June 2017. @@@DEPRECATED_2017-06@@@
5110     deprecated("Private variable. Use front()")
5111     @property size_t[] state() pure nothrow @nogc @safe { return _state; }
5112 
5113     // Explicitly undocumented. It will be removed in June 2017. @@@DEPRECATED_2017-06@@@
5114     deprecated("Private variable. Don't set it manually")
5115     @property void state(size_t[] state) pure nothrow @nogc @safe { state = state; }
5116 
5117     // Explicitly undocumented. It will be removed in June 2017. @@@DEPRECATED_2017-06@@@
5118     deprecated("Private variable. Access will be forbidden.")
5119     @property Range r() pure nothrow @nogc @safe { return _r; }
5120 
5121     // Explicitly undocumented. It will be removed in June 2017. @@@DEPRECATED_2017-06@@@
5122     deprecated("Private variable. Don't set it manually")
5123     @property void r(Range r) pure nothrow @nogc @safe { _r = r; }
5124 
5125     ///
5126     this(Range r)
5127     {
5128         import std.array : array;
5129         import std.range : iota;
5130 
5131         this._r = r;
5132         _state = r.length ? new size_t[r.length-1] : null;
5133         _indices = iota(size_t(r.length)).array;
5134         _empty = r.length == 0;
5135     }
5136 
5137     ///
5138     @property bool empty() const pure nothrow @safe @nogc
5139     {
5140         return _empty;
5141     }
5142 
5143     ///
5144     @property auto front()
5145     {
5146         import std.range : indexed;
5147         return _r.indexed(_indices);
5148     }
5149 
5150     ///
5151     void popFront()
5152     {
5153         void next(int n)
5154         {
5155             import std.algorithm.mutation : swap;
5156 
5157             if (n > _indices.length)
5158             {
5159                 _empty = true;
5160                 return;
5161             }
5162 
5163             if (n % 2 == 1)
5164                 swap(_indices[0], _indices[n-1]);
5165             else
5166                 swap(_indices[_state[n-2]], _indices[n-1]);
5167 
5168             if (++_state[n-2] == n)
5169             {
5170                 _state[n-2] = 0;
5171                 next(n+1);
5172             }
5173         }
5174 
5175         next(2);
5176     }
5177 }
5178 
5179 ///
5180 @safe unittest
5181 {
5182     import std.algorithm.comparison : equal;
5183     import std.range : iota;
5184     assert(equal!equal(iota(3).permutations,
5185         [[0, 1, 2],
5186          [1, 0, 2],
5187          [2, 0, 1],
5188          [0, 2, 1],
5189          [1, 2, 0],
5190          [2, 1, 0]]));
5191 }