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