History

gcc-9.1

Wolfgang Thaller committed 7 years ago

Commit 6fbf4221 parent ec13cc931387 files · +2442466 −1054331Browse files

Showing the changes to gcc/libphobos/src/std/algorithm (8 of 31387 files). Show all

Unified · Split

8 files
  1. gcc/libphobos/src/std/algorithm/comparison.d +2159 −0
  2. gcc/libphobos/src/std/algorithm/internal.d +77 −0
  3. gcc/libphobos/src/std/algorithm/iteration.d +5187 −0
  4. gcc/libphobos/src/std/algorithm/mutation.d +2909 −0
  5. gcc/libphobos/src/std/algorithm/package.d +198 −0
  6. gcc/libphobos/src/std/algorithm/searching.d +4600 −0
  7. gcc/libphobos/src/std/algorithm/setops.d +1521 −0
  8. gcc/libphobos/src/std/algorithm/sorting.d +4468 −0
gcc/libphobos/src/std/algorithm/comparison.d+2159−0
@@ -0,0 +1,2159 @@
1+// Written in the D programming language.
2+/**
3+This is a submodule of $(MREF std, algorithm).
4+It contains generic _comparison algorithms.
5+
6+$(SCRIPT inhibitQuickIndex = 1;)
7+$(BOOKTABLE Cheat Sheet,
8+$(TR $(TH Function Name) $(TH Description))
9+$(T2 among,
10+ Checks if a value is among a set of values, e.g.
11+ $(D if (v.among(1, 2, 3)) // `v` is 1, 2 or 3))
12+$(T2 castSwitch,
13+ $(D (new A()).castSwitch((A a)=>1,(B b)=>2)) returns $(D 1).)
14+$(T2 clamp,
15+ $(D clamp(1, 3, 6)) returns $(D 3). $(D clamp(4, 3, 6)) returns $(D 4).)
16+$(T2 cmp,
17+ $(D cmp("abc", "abcd")) is $(D -1), $(D cmp("abc", "aba")) is $(D 1),
18+ and $(D cmp("abc", "abc")) is $(D 0).)
19+$(T2 either,
20+ Return first parameter $(D p) that passes an $(D if (p)) test, e.g.
21+ $(D either(0, 42, 43)) returns $(D 42).)
22+$(T2 equal,
23+ Compares ranges for element-by-element equality, e.g.
24+ $(D equal([1, 2, 3], [1.0, 2.0, 3.0])) returns $(D true).)
25+$(T2 isPermutation,
26+ $(D isPermutation([1, 2], [2, 1])) returns $(D true).)
27+$(T2 isSameLength,
28+ $(D isSameLength([1, 2, 3], [4, 5, 6])) returns $(D true).)
29+$(T2 levenshteinDistance,
30+ $(D levenshteinDistance("kitten", "sitting")) returns $(D 3) by using
31+ the $(LINK2 https://en.wikipedia.org/wiki/Levenshtein_distance,
32+ Levenshtein distance _algorithm).)
33+$(T2 levenshteinDistanceAndPath,
34+ $(D levenshteinDistanceAndPath("kitten", "sitting")) returns
35+ $(D tuple(3, "snnnsni")) by using the
36+ $(LINK2 https://en.wikipedia.org/wiki/Levenshtein_distance,
37+ Levenshtein distance _algorithm).)
38+$(T2 max,
39+ $(D max(3, 4, 2)) returns $(D 4).)
40+$(T2 min,
41+ $(D min(3, 4, 2)) returns $(D 2).)
42+$(T2 mismatch,
43+ $(D mismatch("oh hi", "ohayo")) returns $(D tuple(" hi", "ayo")).)
44+$(T2 predSwitch,
45+ $(D 2.predSwitch(1, "one", 2, "two", 3, "three")) returns $(D "two").)
46+)
47+
48+Copyright: Andrei Alexandrescu 2008-.
49+
50+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
51+
52+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
53+
54+Source: $(PHOBOSSRC std/algorithm/_comparison.d)
55+
56+Macros:
57+T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
58+ */
59+module std.algorithm.comparison;
60+
61+// FIXME
62+import std.functional; // : unaryFun, binaryFun;
63+import std.range.primitives;
64+import std.traits;
65+// FIXME
66+import std.meta : allSatisfy;
67+import std.typecons; // : tuple, Tuple, Flag, Yes;
68+
69+/**
70+Find $(D value) _among $(D values), returning the 1-based index
71+of the first matching value in $(D values), or $(D 0) if $(D value)
72+is not _among $(D values). The predicate $(D pred) is used to
73+compare values, and uses equality by default.
74+
75+Params:
76+ pred = The predicate used to compare the values.
77+ value = The value to search for.
78+ values = The values to compare the value to.
79+
80+Returns:
81+ 0 if value was not found among the values, otherwise the index of the
82+ found value plus one is returned.
83+
84+See_Also:
85+$(REF_ALTTEXT find, find, std,algorithm,searching) and $(REF_ALTTEXT canFind, canFind, std,algorithm,searching) for finding a value in a
86+range.
87+*/
88+uint among(alias pred = (a, b) => a == b, Value, Values...)
89+ (Value value, Values values)
90+if (Values.length != 0)
91+{
92+ foreach (uint i, ref v; values)
93+ {
94+ import std.functional : binaryFun;
95+ if (binaryFun!pred(value, v)) return i + 1;
96+ }
97+ return 0;
98+}
99+
100+/// Ditto
101+template among(values...)
102+if (isExpressionTuple!values)
103+{
104+ uint among(Value)(Value value)
105+ if (!is(CommonType!(Value, values) == void))
106+ {
107+ switch (value)
108+ {
109+ foreach (uint i, v; values)
110+ case v:
111+ return i + 1;
112+ default:
113+ return 0;
114+ }
115+ }
116+}
117+
118+///
119+@safe unittest
120+{
121+ assert(3.among(1, 42, 24, 3, 2));
122+
123+ if (auto pos = "bar".among("foo", "bar", "baz"))
124+ assert(pos == 2);
125+ else
126+ assert(false);
127+
128+ // 42 is larger than 24
129+ assert(42.among!((lhs, rhs) => lhs > rhs)(43, 24, 100) == 2);
130+}
131+
132+/**
133+Alternatively, $(D values) can be passed at compile-time, allowing for a more
134+efficient search, but one that only supports matching on equality:
135+*/
136+@safe unittest
137+{
138+ assert(3.among!(2, 3, 4));
139+ assert("bar".among!("foo", "bar", "baz") == 2);
140+}
141+
142+@safe unittest
143+{
144+ import std.meta : AliasSeq;
145+
146+ if (auto pos = 3.among(1, 2, 3))
147+ assert(pos == 3);
148+ else
149+ assert(false);
150+ assert(!4.among(1, 2, 3));
151+
152+ auto position = "hello".among("hello", "world");
153+ assert(position);
154+ assert(position == 1);
155+
156+ alias values = AliasSeq!("foo", "bar", "baz");
157+ auto arr = [values];
158+ assert(arr[0 .. "foo".among(values)] == ["foo"]);
159+ assert(arr[0 .. "bar".among(values)] == ["foo", "bar"]);
160+ assert(arr[0 .. "baz".among(values)] == arr);
161+ assert("foobar".among(values) == 0);
162+
163+ if (auto pos = 3.among!(1, 2, 3))
164+ assert(pos == 3);
165+ else
166+ assert(false);
167+ assert(!4.among!(1, 2, 3));
168+
169+ position = "hello".among!("hello", "world");
170+ assert(position);
171+ assert(position == 1);
172+
173+ static assert(!__traits(compiles, "a".among!("a", 42)));
174+ static assert(!__traits(compiles, (Object.init).among!(42, "a")));
175+}
176+
177+// Used in castSwitch to find the first choice that overshadows the last choice
178+// in a tuple.
179+private template indexOfFirstOvershadowingChoiceOnLast(choices...)
180+{
181+ alias firstParameterTypes = Parameters!(choices[0]);
182+ alias lastParameterTypes = Parameters!(choices[$ - 1]);
183+
184+ static if (lastParameterTypes.length == 0)
185+ {
186+ // If the last is null-typed choice, check if the first is null-typed.
187+ enum isOvershadowing = firstParameterTypes.length == 0;
188+ }
189+ else static if (firstParameterTypes.length == 1)
190+ {
191+ // If the both first and last are not null-typed, check for overshadowing.
192+ enum isOvershadowing =
193+ is(firstParameterTypes[0] == Object) // Object overshadows all other classes!(this is needed for interfaces)
194+ || is(lastParameterTypes[0] : firstParameterTypes[0]);
195+ }
196+ else
197+ {
198+ // If the first is null typed and the last is not - the is no overshadowing.
199+ enum isOvershadowing = false;
200+ }
201+
202+ static if (isOvershadowing)
203+ {
204+ enum indexOfFirstOvershadowingChoiceOnLast = 0;
205+ }
206+ else
207+ {
208+ enum indexOfFirstOvershadowingChoiceOnLast =
209+ 1 + indexOfFirstOvershadowingChoiceOnLast!(choices[1..$]);
210+ }
211+}
212+
213+/**
214+Executes and returns one of a collection of handlers based on the type of the
215+switch object.
216+
217+The first choice that $(D switchObject) can be casted to the type
218+of argument it accepts will be called with $(D switchObject) casted to that
219+type, and the value it'll return will be returned by $(D castSwitch).
220+
221+If a choice's return type is void, the choice must throw an exception, unless
222+all the choices are void. In that case, castSwitch itself will return void.
223+
224+Throws: If none of the choice matches, a $(D SwitchError) will be thrown. $(D
225+SwitchError) will also be thrown if not all the choices are void and a void
226+choice was executed without throwing anything.
227+
228+Params:
229+ choices = The $(D choices) needs to be composed of function or delegate
230+ handlers that accept one argument. There can also be a choice that
231+ accepts zero arguments. That choice will be invoked if the $(D
232+ switchObject) is null.
233+ switchObject = the object against which the tests are being made.
234+
235+Returns:
236+ The value of the selected choice.
237+
238+Note: $(D castSwitch) can only be used with object types.
239+*/
240+auto castSwitch(choices...)(Object switchObject)
241+{
242+ import core.exception : SwitchError;
243+ import std.format : format;
244+
245+ // Check to see if all handlers return void.
246+ enum areAllHandlersVoidResult = {
247+ bool result = true;
248+ foreach (index, choice; choices)
249+ {
250+ result &= is(ReturnType!choice == void);
251+ }
252+ return result;
253+ }();
254+
255+ if (switchObject !is null)
256+ {
257+
258+ // Checking for exact matches:
259+ const classInfo = typeid(switchObject);
260+ foreach (index, choice; choices)
261+ {
262+ static assert(isCallable!choice,
263+ "A choice handler must be callable");
264+
265+ alias choiceParameterTypes = Parameters!choice;
266+ static assert(choiceParameterTypes.length <= 1,
267+ "A choice handler can not have more than one argument.");
268+
269+ static if (choiceParameterTypes.length == 1)
270+ {
271+ alias CastClass = choiceParameterTypes[0];
272+ static assert(is(CastClass == class) || is(CastClass == interface),
273+ "A choice handler can have only class or interface typed argument.");
274+
275+ // Check for overshadowing:
276+ immutable indexOfOvershadowingChoice =
277+ indexOfFirstOvershadowingChoiceOnLast!(choices[0 .. index + 1]);
278+ static assert(indexOfOvershadowingChoice == index,
279+ "choice number %d(type %s) is overshadowed by choice number %d(type %s)".format(
280+ index + 1, CastClass.stringof, indexOfOvershadowingChoice + 1,
281+ Parameters!(choices[indexOfOvershadowingChoice])[0].stringof));
282+
283+ if (classInfo == typeid(CastClass))
284+ {
285+ static if (is(ReturnType!(choice) == void))
286+ {
287+ choice(cast(CastClass) switchObject);
288+ static if (areAllHandlersVoidResult)
289+ {
290+ return;
291+ }
292+ else
293+ {
294+ throw new SwitchError("Handlers that return void should throw");
295+ }
296+ }
297+ else
298+ {
299+ return choice(cast(CastClass) switchObject);
300+ }
301+ }
302+ }
303+ }
304+
305+ // Checking for derived matches:
306+ foreach (choice; choices)
307+ {
308+ alias choiceParameterTypes = Parameters!choice;
309+ static if (choiceParameterTypes.length == 1)
310+ {
311+ if (auto castedObject = cast(choiceParameterTypes[0]) switchObject)
312+ {
313+ static if (is(ReturnType!(choice) == void))
314+ {
315+ choice(castedObject);
316+ static if (areAllHandlersVoidResult)
317+ {
318+ return;
319+ }
320+ else
321+ {
322+ throw new SwitchError("Handlers that return void should throw");
323+ }
324+ }
325+ else
326+ {
327+ return choice(castedObject);
328+ }
329+ }
330+ }
331+ }
332+ }
333+ else // If switchObject is null:
334+ {
335+ // Checking for null matches:
336+ foreach (index, choice; choices)
337+ {
338+ static if (Parameters!(choice).length == 0)
339+ {
340+ immutable indexOfOvershadowingChoice =
341+ indexOfFirstOvershadowingChoiceOnLast!(choices[0 .. index + 1]);
342+
343+ // Check for overshadowing:
344+ static assert(indexOfOvershadowingChoice == index,
345+ "choice number %d(null reference) is overshadowed by choice number %d(null reference)".format(
346+ index + 1, indexOfOvershadowingChoice + 1));
347+
348+ if (switchObject is null)
349+ {
350+ static if (is(ReturnType!(choice) == void))
351+ {
352+ choice();
353+ static if (areAllHandlersVoidResult)
354+ {
355+ return;
356+ }
357+ else
358+ {
359+ throw new SwitchError("Handlers that return void should throw");
360+ }
361+ }
362+ else
363+ {
364+ return choice();
365+ }
366+ }
367+ }
368+ }
369+ }
370+
371+ // In case nothing matched:
372+ throw new SwitchError("Input not matched by any choice");
373+}
374+
375+///
376+@system unittest
377+{
378+ import std.algorithm.iteration : map;
379+ import std.format : format;
380+
381+ class A
382+ {
383+ int a;
384+ this(int a) {this.a = a;}
385+ @property int i() { return a; }
386+ }
387+ interface I { }
388+ class B : I { }
389+
390+ Object[] arr = [new A(1), new B(), null];
391+
392+ auto results = arr.map!(castSwitch!(
393+ (A a) => "A with a value of %d".format(a.a),
394+ (I i) => "derived from I",
395+ () => "null reference",
396+ ))();
397+
398+ // A is handled directly:
399+ assert(results[0] == "A with a value of 1");
400+ // B has no handler - it is handled by the handler of I:
401+ assert(results[1] == "derived from I");
402+ // null is handled by the null handler:
403+ assert(results[2] == "null reference");
404+}
405+
406+/// Using with void handlers:
407+@system unittest
408+{
409+ import std.exception : assertThrown;
410+
411+ class A { }
412+ class B { }
413+ // Void handlers are allowed if they throw:
414+ assertThrown!Exception(
415+ new B().castSwitch!(
416+ (A a) => 1,
417+ (B d) { throw new Exception("B is not allowed!"); }
418+ )()
419+ );
420+
421+ // Void handlers are also allowed if all the handlers are void:
422+ new A().castSwitch!(
423+ (A a) { },
424+ (B b) { assert(false); },
425+ )();
426+}
427+
428+@system unittest
429+{
430+ import core.exception : SwitchError;
431+ import std.exception : assertThrown;
432+
433+ interface I { }
434+ class A : I { }
435+ class B { }
436+
437+ // Nothing matches:
438+ assertThrown!SwitchError((new A()).castSwitch!(
439+ (B b) => 1,
440+ () => 2,
441+ )());
442+
443+ // Choices with multiple arguments are not allowed:
444+ static assert(!__traits(compiles,
445+ (new A()).castSwitch!(
446+ (A a, B b) => 0,
447+ )()));
448+
449+ // Only callable handlers allowed:
450+ static assert(!__traits(compiles,
451+ (new A()).castSwitch!(
452+ 1234,
453+ )()));
454+
455+ // Only object arguments allowed:
456+ static assert(!__traits(compiles,
457+ (new A()).castSwitch!(
458+ (int x) => 0,
459+ )()));
460+
461+ // Object overshadows regular classes:
462+ static assert(!__traits(compiles,
463+ (new A()).castSwitch!(
464+ (Object o) => 0,
465+ (A a) => 1,
466+ )()));
467+
468+ // Object overshadows interfaces:
469+ static assert(!__traits(compiles,
470+ (new A()).castSwitch!(
471+ (Object o) => 0,
472+ (I i) => 1,
473+ )()));
474+
475+ // No multiple null handlers allowed:
476+ static assert(!__traits(compiles,
477+ (new A()).castSwitch!(
478+ () => 0,
479+ () => 1,
480+ )()));
481+
482+ // No non-throwing void handlers allowed(when there are non-void handlers):
483+ assertThrown!SwitchError((new A()).castSwitch!(
484+ (A a) {},
485+ (B b) => 2,
486+ )());
487+
488+ // All-void handlers work for the null case:
489+ null.castSwitch!(
490+ (Object o) { assert(false); },
491+ () { },
492+ )();
493+
494+ // Throwing void handlers work for the null case:
495+ assertThrown!Exception(null.castSwitch!(
496+ (Object o) => 1,
497+ () { throw new Exception("null"); },
498+ )());
499+}
500+
501+@system unittest
502+{
503+ interface I { }
504+ class B : I { }
505+ class C : I { }
506+
507+ assert((new B()).castSwitch!(
508+ (B b) => "class B",
509+ (I i) => "derived from I",
510+ ) == "class B");
511+
512+ assert((new C()).castSwitch!(
513+ (B b) => "class B",
514+ (I i) => "derived from I",
515+ ) == "derived from I");
516+}
517+
518+/** Clamps a value into the given bounds.
519+
520+This functions is equivalent to $(D max(lower, min(upper,val))).
521+
522+Params:
523+ val = The value to _clamp.
524+ lower = The _lower bound of the _clamp.
525+ upper = The _upper bound of the _clamp.
526+
527+Returns:
528+ Returns $(D val), if it is between $(D lower) and $(D upper).
529+ Otherwise returns the nearest of the two.
530+
531+*/
532+auto clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
533+in
534+{
535+ import std.functional : greaterThan;
536+ assert(!lower.greaterThan(upper));
537+}
538+body
539+{
540+ return max(lower, min(upper, val));
541+}
542+
543+///
544+@safe unittest
545+{
546+ assert(clamp(2, 1, 3) == 2);
547+ assert(clamp(0, 1, 3) == 1);
548+ assert(clamp(4, 1, 3) == 3);
549+
550+ assert(clamp(1, 1, 1) == 1);
551+
552+ assert(clamp(5, -1, 2u) == 2);
553+}
554+
555+@safe unittest
556+{
557+ int a = 1;
558+ short b = 6;
559+ double c = 2;
560+ static assert(is(typeof(clamp(c,a,b)) == double));
561+ assert(clamp(c, a, b) == c);
562+ assert(clamp(a-c, a, b) == a);
563+ assert(clamp(b+c, a, b) == b);
564+ // mixed sign
565+ a = -5;
566+ uint f = 5;
567+ static assert(is(typeof(clamp(f, a, b)) == int));
568+ assert(clamp(f, a, b) == f);
569+ // similar type deduction for (u)long
570+ static assert(is(typeof(clamp(-1L, -2L, 2UL)) == long));
571+
572+ // user-defined types
573+ import std.datetime : Date;
574+ assert(clamp(Date(1982, 1, 4), Date(1012, 12, 21), Date(2012, 12, 21)) == Date(1982, 1, 4));
575+ assert(clamp(Date(1982, 1, 4), Date.min, Date.max) == Date(1982, 1, 4));
576+ // UFCS style
577+ assert(Date(1982, 1, 4).clamp(Date.min, Date.max) == Date(1982, 1, 4));
578+
579+}
580+
581+// cmp
582+/**********************************
583+Performs three-way lexicographical comparison on two
584+$(REF_ALTTEXT input ranges, isInputRange, std,range,primitives)
585+according to predicate $(D pred). Iterating $(D r1) and $(D r2) in
586+lockstep, $(D cmp) compares each element $(D e1) of $(D r1) with the
587+corresponding element $(D e2) in $(D r2). If one of the ranges has been
588+finished, $(D cmp) returns a negative value if $(D r1) has fewer
589+elements than $(D r2), a positive value if $(D r1) has more elements
590+than $(D r2), and $(D 0) if the ranges have the same number of
591+elements.
592+
593+If the ranges are strings, $(D cmp) performs UTF decoding
594+appropriately and compares the ranges one code point at a time.
595+
596+Params:
597+ pred = The predicate used for comparison.
598+ r1 = The first range.
599+ r2 = The second range.
600+
601+Returns:
602+ 0 if both ranges compare equal. -1 if the first differing element of $(D
603+ r1) is less than the corresponding element of $(D r2) according to $(D
604+ pred). 1 if the first differing element of $(D r2) is less than the
605+ corresponding element of $(D r1) according to $(D pred).
606+
607+*/
608+int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2)
609+if (isInputRange!R1 && isInputRange!R2 && !(isSomeString!R1 && isSomeString!R2))
610+{
611+ for (;; r1.popFront(), r2.popFront())
612+ {
613+ if (r1.empty) return -cast(int)!r2.empty;
614+ if (r2.empty) return !r1.empty;
615+ auto a = r1.front, b = r2.front;
616+ if (binaryFun!pred(a, b)) return -1;
617+ if (binaryFun!pred(b, a)) return 1;
618+ }
619+}
620+
621+/// ditto
622+int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2)
623+if (isSomeString!R1 && isSomeString!R2)
624+{
625+ import core.stdc.string : memcmp;
626+ import std.utf : decode;
627+
628+ static if (is(typeof(pred) : string))
629+ enum isLessThan = pred == "a < b";
630+ else
631+ enum isLessThan = false;
632+
633+ // For speed only
634+ static int threeWay(size_t a, size_t b)
635+ {
636+ static if (size_t.sizeof == int.sizeof && isLessThan)
637+ return a - b;
638+ else
639+ return binaryFun!pred(b, a) ? 1 : binaryFun!pred(a, b) ? -1 : 0;
640+ }
641+ // For speed only
642+ // @@@BUG@@@ overloading should be allowed for nested functions
643+ static int threeWayInt(int a, int b)
644+ {
645+ static if (isLessThan)
646+ return a - b;
647+ else
648+ return binaryFun!pred(b, a) ? 1 : binaryFun!pred(a, b) ? -1 : 0;
649+ }
650+
651+ static if (typeof(r1[0]).sizeof == typeof(r2[0]).sizeof && isLessThan)
652+ {
653+ static if (typeof(r1[0]).sizeof == 1)
654+ {
655+ immutable len = min(r1.length, r2.length);
656+ immutable result = __ctfe ?
657+ {
658+ foreach (i; 0 .. len)
659+ {
660+ if (r1[i] != r2[i])
661+ return threeWayInt(r1[i], r2[i]);
662+ }
663+ return 0;
664+ }()
665+ : () @trusted { return memcmp(r1.ptr, r2.ptr, len); }();
666+ if (result) return result;
667+ }
668+ else
669+ {
670+ auto p1 = r1.ptr, p2 = r2.ptr,
671+ pEnd = p1 + min(r1.length, r2.length);
672+ for (; p1 != pEnd; ++p1, ++p2)
673+ {
674+ if (*p1 != *p2) return threeWayInt(cast(int) *p1, cast(int) *p2);
675+ }
676+ }
677+ return threeWay(r1.length, r2.length);
678+ }
679+ else
680+ {
681+ for (size_t i1, i2;;)
682+ {
683+ if (i1 == r1.length) return threeWay(i2, r2.length);
684+ if (i2 == r2.length) return threeWay(r1.length, i1);
685+ immutable c1 = decode(r1, i1),
686+ c2 = decode(r2, i2);
687+ if (c1 != c2) return threeWayInt(cast(int) c1, cast(int) c2);
688+ }
689+ }
690+}
691+
692+///
693+@safe unittest
694+{
695+ int result;
696+
697+ result = cmp("abc", "abc");
698+ assert(result == 0);
699+ result = cmp("", "");
700+ assert(result == 0);
701+ result = cmp("abc", "abcd");
702+ assert(result < 0);
703+ result = cmp("abcd", "abc");
704+ assert(result > 0);
705+ result = cmp("abc"d, "abd");
706+ assert(result < 0);
707+ result = cmp("bbc", "abc"w);
708+ assert(result > 0);
709+ result = cmp("aaa", "aaaa"d);
710+ assert(result < 0);
711+ result = cmp("aaaa", "aaa"d);
712+ assert(result > 0);
713+ result = cmp("aaa", "aaa"d);
714+ assert(result == 0);
715+ result = cmp(cast(int[])[], cast(int[])[]);
716+ assert(result == 0);
717+ result = cmp([1, 2, 3], [1, 2, 3]);
718+ assert(result == 0);
719+ result = cmp([1, 3, 2], [1, 2, 3]);
720+ assert(result > 0);
721+ result = cmp([1, 2, 3], [1L, 2, 3, 4]);
722+ assert(result < 0);
723+ result = cmp([1L, 2, 3], [1, 2]);
724+ assert(result > 0);
725+}
726+
727+// equal
728+/**
729+Compares two ranges for equality, as defined by predicate $(D pred)
730+(which is $(D ==) by default).
731+*/
732+template equal(alias pred = "a == b")
733+{
734+ enum isEmptyRange(R) =
735+ isInputRange!R && __traits(compiles, {static assert(R.empty);});
736+
737+ enum hasFixedLength(T) = hasLength!T || isNarrowString!T;
738+
739+ /++
740+ Compares two ranges for equality. The ranges may have
741+ different element types, as long as $(D pred(r1.front, r2.front))
742+ evaluates to $(D bool).
743+ Performs $(BIGOH min(r1.length, r2.length)) evaluations of $(D pred).
744+
745+ Params:
746+ r1 = The first range to be compared.
747+ r2 = The second range to be compared.
748+
749+ Returns:
750+ $(D true) if and only if the two ranges compare _equal element
751+ for element, according to binary predicate $(D pred).
752+
753+ See_Also:
754+ $(HTTP sgi.com/tech/stl/_equal.html, STL's _equal)
755+ +/
756+ bool equal(Range1, Range2)(Range1 r1, Range2 r2)
757+ if (isInputRange!Range1 && isInputRange!Range2 &&
758+ is(typeof(binaryFun!pred(r1.front, r2.front))))
759+ {
760+ static assert(!(isInfinite!Range1 && isInfinite!Range2),
761+ "Both ranges are known to be infinite");
762+
763+ //No pred calls necessary
764+ static if (isEmptyRange!Range1 || isEmptyRange!Range2)
765+ {
766+ return r1.empty && r2.empty;
767+ }
768+ else static if ((isInfinite!Range1 && hasFixedLength!Range2) ||
769+ (hasFixedLength!Range1 && isInfinite!Range2))
770+ {
771+ return false;
772+ }
773+ //Detect default pred and compatible dynamic array
774+ else static if (is(typeof(pred) == string) && pred == "a == b" &&
775+ isArray!Range1 && isArray!Range2 && is(typeof(r1 == r2)))
776+ {
777+ return r1 == r2;
778+ }
779+ // if one of the arguments is a string and the other isn't, then auto-decoding
780+ // can be avoided if they have the same ElementEncodingType
781+ else static if (is(typeof(pred) == string) && pred == "a == b" &&
782+ isAutodecodableString!Range1 != isAutodecodableString!Range2 &&
783+ is(ElementEncodingType!Range1 == ElementEncodingType!Range2))
784+ {
785+ import std.utf : byCodeUnit;
786+
787+ static if (isAutodecodableString!Range1)
788+ {
789+ return equal(r1.byCodeUnit, r2);
790+ }
791+ else
792+ {
793+ return equal(r2.byCodeUnit, r1);
794+ }
795+ }
796+ //Try a fast implementation when the ranges have comparable lengths
797+ else static if (hasLength!Range1 && hasLength!Range2 && is(typeof(r1.length == r2.length)))
798+ {
799+ immutable len1 = r1.length;
800+ immutable len2 = r2.length;
801+ if (len1 != len2) return false; //Short circuit return
802+
803+ //Lengths are the same, so we need to do an actual comparison
804+ //Good news is we can squeeze out a bit of performance by not checking if r2 is empty
805+ for (; !r1.empty; r1.popFront(), r2.popFront())
806+ {
807+ if (!binaryFun!(pred)(r1.front, r2.front)) return false;
808+ }
809+ return true;
810+ }
811+ else
812+ {
813+ //Generic case, we have to walk both ranges making sure neither is empty
814+ for (; !r1.empty; r1.popFront(), r2.popFront())
815+ {
816+ if (r2.empty) return false;
817+ if (!binaryFun!(pred)(r1.front, r2.front)) return false;
818+ }
819+ static if (!isInfinite!Range1)
820+ return r2.empty;
821+ }
822+ }
823+}
824+
825+///
826+@safe unittest
827+{
828+ import std.algorithm.comparison : equal;
829+ import std.math : approxEqual;
830+
831+ int[] a = [ 1, 2, 4, 3 ];
832+ assert(!equal(a, a[1..$]));
833+ assert(equal(a, a));
834+ assert(equal!((a, b) => a == b)(a, a));
835+
836+ // different types
837+ double[] b = [ 1.0, 2, 4, 3];
838+ assert(!equal(a, b[1..$]));
839+ assert(equal(a, b));
840+
841+ // predicated: ensure that two vectors are approximately equal
842+ double[] c = [ 1.005, 2, 4, 3];
843+ assert(equal!approxEqual(b, c));
844+}
845+
846+/++
847+Tip: $(D equal) can itself be used as a predicate to other functions.
848+This can be very useful when the element type of a range is itself a
849+range. In particular, $(D equal) can be its own predicate, allowing
850+range of range (of range...) comparisons.
851+ +/
852+@safe unittest
853+{
854+ import std.algorithm.comparison : equal;
855+ import std.range : iota, chunks;
856+ assert(equal!(equal!equal)(
857+ [[[0, 1], [2, 3]], [[4, 5], [6, 7]]],
858+ iota(0, 8).chunks(2).chunks(2)
859+ ));
860+}
861+
862+@safe unittest
863+{
864+ import std.algorithm.iteration : map;
865+ import std.internal.test.dummyrange : ReferenceForwardRange,
866+ ReferenceInputRange, ReferenceInfiniteForwardRange;
867+ import std.math : approxEqual;
868+
869+ // various strings
870+ assert(equal("æøå", "æøå")); //UTF8 vs UTF8
871+ assert(!equal("???", "æøå")); //UTF8 vs UTF8
872+ assert(equal("æøå"w, "æøå"d)); //UTF16 vs UTF32
873+ assert(!equal("???"w, "æøå"d));//UTF16 vs UTF32
874+ assert(equal("æøå"d, "æøå"d)); //UTF32 vs UTF32
875+ assert(!equal("???"d, "æøå"d));//UTF32 vs UTF32
876+ assert(!equal("hello", "world"));
877+
878+ // same strings, but "explicit non default" comparison (to test the non optimized array comparison)
879+ assert( equal!("a == b")("æøå", "æøå")); //UTF8 vs UTF8
880+ assert(!equal!("a == b")("???", "æøå")); //UTF8 vs UTF8
881+ assert( equal!("a == b")("æøå"w, "æøå"d)); //UTF16 vs UTF32
882+ assert(!equal!("a == b")("???"w, "æøå"d));//UTF16 vs UTF32
883+ assert( equal!("a == b")("æøå"d, "æøå"d)); //UTF32 vs UTF32
884+ assert(!equal!("a == b")("???"d, "æøå"d));//UTF32 vs UTF32
885+ assert(!equal!("a == b")("hello", "world"));
886+
887+ //Array of string
888+ assert(equal(["hello", "world"], ["hello", "world"]));
889+ assert(!equal(["hello", "world"], ["hello"]));
890+ assert(!equal(["hello", "world"], ["hello", "Bob!"]));
891+
892+ //Should not compile, because "string == dstring" is illegal
893+ static assert(!is(typeof(equal(["hello", "world"], ["hello"d, "world"d]))));
894+ //However, arrays of non-matching string can be compared using equal!equal. Neat-o!
895+ equal!equal(["hello", "world"], ["hello"d, "world"d]);
896+
897+ //Tests, with more fancy map ranges
898+ int[] a = [ 1, 2, 4, 3 ];
899+ assert(equal([2, 4, 8, 6], map!"a*2"(a)));
900+ double[] b = [ 1.0, 2, 4, 3];
901+ double[] c = [ 1.005, 2, 4, 3];
902+ assert(equal!approxEqual(map!"a*2"(b), map!"a*2"(c)));
903+ assert(!equal([2, 4, 1, 3], map!"a*2"(a)));
904+ assert(!equal([2, 4, 1], map!"a*2"(a)));
905+ assert(!equal!approxEqual(map!"a*3"(b), map!"a*2"(c)));
906+
907+ //Tests with some fancy reference ranges.
908+ ReferenceInputRange!int cir = new ReferenceInputRange!int([1, 2, 4, 3]);
909+ ReferenceForwardRange!int cfr = new ReferenceForwardRange!int([1, 2, 4, 3]);
910+ assert(equal(cir, a));
911+ cir = new ReferenceInputRange!int([1, 2, 4, 3]);
912+ assert(equal(cir, cfr.save));
913+ assert(equal(cfr.save, cfr.save));
914+ cir = new ReferenceInputRange!int([1, 2, 8, 1]);
915+ assert(!equal(cir, cfr));
916+
917+ //Test with an infinite range
918+ auto ifr = new ReferenceInfiniteForwardRange!int;
919+ assert(!equal(a, ifr));
920+ assert(!equal(ifr, a));
921+ //Test InputRange without length
922+ assert(!equal(ifr, cir));
923+ assert(!equal(cir, ifr));
924+}
925+
926+@safe pure unittest
927+{
928+ import std.utf : byChar, byWchar, byDchar;
929+
930+ assert(equal("æøå".byChar, "æøå"));
931+ assert(equal("æøå", "æøå".byChar));
932+ assert(equal("æøå".byWchar, "æøå"w));
933+ assert(equal("æøå"w, "æøå".byWchar));
934+ assert(equal("æøå".byDchar, "æøå"d));
935+ assert(equal("æøå"d, "æøå".byDchar));
936+}
937+
938+@safe pure unittest
939+{
940+ struct R(bool _empty) {
941+ enum empty = _empty;
942+ @property char front(){assert(0);}
943+ void popFront(){assert(0);}
944+ }
945+ alias I = R!false;
946+ static assert(!__traits(compiles, I().equal(I())));
947+ // strings have fixed length so don't need to compare elements
948+ assert(!I().equal("foo"));
949+ assert(!"bar".equal(I()));
950+
951+ alias E = R!true;
952+ assert(E().equal(E()));
953+ assert(E().equal(""));
954+ assert("".equal(E()));
955+ assert(!E().equal("foo"));
956+ assert(!"bar".equal(E()));
957+}
958+
959+// MaxType
960+private template MaxType(T...)
961+if (T.length >= 1)
962+{
963+ static if (T.length == 1)
964+ {
965+ alias MaxType = T[0];
966+ }
967+ else static if (T.length == 2)
968+ {
969+ static if (!is(typeof(T[0].min)))
970+ alias MaxType = CommonType!T;
971+ else static if (T[1].max > T[0].max)
972+ alias MaxType = T[1];
973+ else
974+ alias MaxType = T[0];
975+ }
976+ else
977+ {
978+ alias MaxType = MaxType!(MaxType!(T[0 .. ($+1)/2]), MaxType!(T[($+1)/2 .. $]));
979+ }
980+}
981+
982+// levenshteinDistance
983+/**
984+Encodes $(HTTP realityinteractive.com/rgrzywinski/archives/000249.html,
985+edit operations) necessary to transform one sequence into
986+another. Given sequences $(D s) (source) and $(D t) (target), a
987+sequence of $(D EditOp) encodes the steps that need to be taken to
988+convert $(D s) into $(D t). For example, if $(D s = "cat") and $(D
989+"cars"), the minimal sequence that transforms $(D s) into $(D t) is:
990+skip two characters, replace 't' with 'r', and insert an 's'. Working
991+with edit operations is useful in applications such as spell-checkers
992+(to find the closest word to a given misspelled word), approximate
993+searches, diff-style programs that compute the difference between
994+files, efficient encoding of patches, DNA sequence analysis, and
995+plagiarism detection.
996+*/
997+
998+enum EditOp : char
999+{
1000+ /** Current items are equal; no editing is necessary. */
1001+ none = 'n',
1002+ /** Substitute current item in target with current item in source. */
1003+ substitute = 's',
1004+ /** Insert current item from the source into the target. */
1005+ insert = 'i',
1006+ /** Remove current item from the target. */
1007+ remove = 'r'
1008+}
1009+
1010+///
1011+@safe unittest
1012+{
1013+ with(EditOp)
1014+ {
1015+ assert(levenshteinDistanceAndPath("foo", "foobar")[1] == [none, none, none, insert, insert, insert]);
1016+ assert(levenshteinDistanceAndPath("banana", "fazan")[1] == [substitute, none, substitute, none, none, remove]);
1017+ }
1018+}
1019+
1020+private struct Levenshtein(Range, alias equals, CostType = size_t)
1021+{
1022+ EditOp[] path()
1023+ {
1024+ import std.algorithm.mutation : reverse;
1025+
1026+ EditOp[] result;
1027+ size_t i = rows - 1, j = cols - 1;
1028+ // restore the path
1029+ while (i || j)
1030+ {
1031+ auto cIns = j == 0 ? CostType.max : matrix(i,j - 1);
1032+ auto cDel = i == 0 ? CostType.max : matrix(i - 1,j);
1033+ auto cSub = i == 0 || j == 0
1034+ ? CostType.max
1035+ : matrix(i - 1,j - 1);
1036+ switch (min_index(cSub, cIns, cDel))
1037+ {
1038+ case 0:
1039+ result ~= matrix(i - 1,j - 1) == matrix(i,j)
1040+ ? EditOp.none
1041+ : EditOp.substitute;
1042+ --i;
1043+ --j;
1044+ break;
1045+ case 1:
1046+ result ~= EditOp.insert;
1047+ --j;
1048+ break;
1049+ default:
1050+ result ~= EditOp.remove;
1051+ --i;
1052+ break;
1053+ }
1054+ }
1055+ reverse(result);
1056+ return result;
1057+ }
1058+
1059+ ~this() {
1060+ FreeMatrix();
1061+ }
1062+
1063+private:
1064+ CostType _deletionIncrement = 1,
1065+ _insertionIncrement = 1,
1066+ _substitutionIncrement = 1;
1067+ CostType[] _matrix;
1068+ size_t rows, cols;
1069+
1070+ // Treat _matrix as a rectangular array
1071+ ref CostType matrix(size_t row, size_t col) { return _matrix[row * cols + col]; }
1072+
1073+ void AllocMatrix(size_t r, size_t c) @trusted {
1074+ import core.checkedint : mulu;
1075+ bool overflow;
1076+ const rc = mulu(r, c, overflow);
1077+ if (overflow) assert(0);
1078+ rows = r;
1079+ cols = c;
1080+ if (_matrix.length < rc)
1081+ {
1082+ import core.exception : onOutOfMemoryError;
1083+ import core.stdc.stdlib : realloc;
1084+ const nbytes = mulu(rc, _matrix[0].sizeof, overflow);
1085+ if (overflow) assert(0);
1086+ auto m = cast(CostType *) realloc(_matrix.ptr, nbytes);
1087+ if (!m)
1088+ onOutOfMemoryError();
1089+ _matrix = m[0 .. r * c];
1090+ InitMatrix();
1091+ }
1092+ }
1093+
1094+ void FreeMatrix() @trusted {
1095+ import core.stdc.stdlib : free;
1096+
1097+ free(_matrix.ptr);
1098+ _matrix = null;
1099+ }
1100+
1101+ void InitMatrix() {
1102+ foreach (r; 0 .. rows)
1103+ matrix(r,0) = r * _deletionIncrement;
1104+ foreach (c; 0 .. cols)
1105+ matrix(0,c) = c * _insertionIncrement;
1106+ }
1107+
1108+ static uint min_index(CostType i0, CostType i1, CostType i2)
1109+ {
1110+ if (i0 <= i1)
1111+ {
1112+ return i0 <= i2 ? 0 : 2;
1113+ }
1114+ else
1115+ {
1116+ return i1 <= i2 ? 1 : 2;
1117+ }
1118+ }
1119+
1120+ CostType distanceWithPath(Range s, Range t)
1121+ {
1122+ auto slen = walkLength(s.save), tlen = walkLength(t.save);
1123+ AllocMatrix(slen + 1, tlen + 1);
1124+ foreach (i; 1 .. rows)
1125+ {
1126+ auto sfront = s.front;
1127+ auto tt = t.save;
1128+ foreach (j; 1 .. cols)
1129+ {
1130+ auto cSub = matrix(i - 1,j - 1)
1131+ + (equals(sfront, tt.front) ? 0 : _substitutionIncrement);
1132+ tt.popFront();
1133+ auto cIns = matrix(i,j - 1) + _insertionIncrement;
1134+ auto cDel = matrix(i - 1,j) + _deletionIncrement;
1135+ switch (min_index(cSub, cIns, cDel))
1136+ {
1137+ case 0:
1138+ matrix(i,j) = cSub;
1139+ break;
1140+ case 1:
1141+ matrix(i,j) = cIns;
1142+ break;
1143+ default:
1144+ matrix(i,j) = cDel;
1145+ break;
1146+ }
1147+ }
1148+ s.popFront();
1149+ }
1150+ return matrix(slen,tlen);
1151+ }
1152+
1153+ CostType distanceLowMem(Range s, Range t, CostType slen, CostType tlen)
1154+ {
1155+ CostType lastdiag, olddiag;
1156+ AllocMatrix(slen + 1, 1);
1157+ foreach (y; 1 .. slen + 1)
1158+ {
1159+ _matrix[y] = y;
1160+ }
1161+ foreach (x; 1 .. tlen + 1)
1162+ {
1163+ auto tfront = t.front;
1164+ auto ss = s.save;
1165+ _matrix[0] = x;
1166+ lastdiag = x - 1;
1167+ foreach (y; 1 .. rows)
1168+ {
1169+ olddiag = _matrix[y];
1170+ auto cSub = lastdiag + (equals(ss.front, tfront) ? 0 : _substitutionIncrement);
1171+ ss.popFront();
1172+ auto cIns = _matrix[y - 1] + _insertionIncrement;
1173+ auto cDel = _matrix[y] + _deletionIncrement;
1174+ switch (min_index(cSub, cIns, cDel))
1175+ {
1176+ case 0:
1177+ _matrix[y] = cSub;
1178+ break;
1179+ case 1:
1180+ _matrix[y] = cIns;
1181+ break;
1182+ default:
1183+ _matrix[y] = cDel;
1184+ break;
1185+ }
1186+ lastdiag = olddiag;
1187+ }
1188+ t.popFront();
1189+ }
1190+ return _matrix[slen];
1191+ }
1192+}
1193+
1194+/**
1195+Returns the $(HTTP wikipedia.org/wiki/Levenshtein_distance, Levenshtein
1196+distance) between $(D s) and $(D t). The Levenshtein distance computes
1197+the minimal amount of edit operations necessary to transform $(D s)
1198+into $(D t). Performs $(BIGOH s.length * t.length) evaluations of $(D
1199+equals) and occupies $(BIGOH s.length * t.length) storage.
1200+
1201+Params:
1202+ equals = The binary predicate to compare the elements of the two ranges.
1203+ s = The original range.
1204+ t = The transformation target
1205+
1206+Returns:
1207+ The minimal number of edits to transform s into t.
1208+
1209+Does not allocate GC memory.
1210+*/
1211+size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2)
1212+ (Range1 s, Range2 t)
1213+if (isForwardRange!(Range1) && isForwardRange!(Range2))
1214+{
1215+ alias eq = binaryFun!(equals);
1216+
1217+ for (;;)
1218+ {
1219+ if (s.empty) return t.walkLength;
1220+ if (t.empty) return s.walkLength;
1221+ if (eq(s.front, t.front))
1222+ {
1223+ s.popFront();
1224+ t.popFront();
1225+ continue;
1226+ }
1227+ static if (isBidirectionalRange!(Range1) && isBidirectionalRange!(Range2))
1228+ {
1229+ if (eq(s.back, t.back))
1230+ {
1231+ s.popBack();
1232+ t.popBack();
1233+ continue;
1234+ }
1235+ }
1236+ break;
1237+ }
1238+
1239+ auto slen = walkLength(s.save);
1240+ auto tlen = walkLength(t.save);
1241+
1242+ if (slen == 1 && tlen == 1)
1243+ {
1244+ return eq(s.front, t.front) ? 0 : 1;
1245+ }
1246+
1247+ if (slen > tlen)
1248+ {
1249+ Levenshtein!(Range1, eq, size_t) lev;
1250+ return lev.distanceLowMem(s, t, slen, tlen);
1251+ }
1252+ else
1253+ {
1254+ Levenshtein!(Range2, eq, size_t) lev;
1255+ return lev.distanceLowMem(t, s, tlen, slen);
1256+ }
1257+}
1258+
1259+///
1260+@safe unittest
1261+{
1262+ import std.algorithm.iteration : filter;
1263+ import std.uni : toUpper;
1264+
1265+ assert(levenshteinDistance("cat", "rat") == 1);
1266+ assert(levenshteinDistance("parks", "spark") == 2);
1267+ assert(levenshteinDistance("abcde", "abcde") == 0);
1268+ assert(levenshteinDistance("abcde", "abCde") == 1);
1269+ assert(levenshteinDistance("kitten", "sitting") == 3);
1270+ assert(levenshteinDistance!((a, b) => toUpper(a) == toUpper(b))
1271+ ("parks", "SPARK") == 2);
1272+ assert(levenshteinDistance("parks".filter!"true", "spark".filter!"true") == 2);
1273+ assert(levenshteinDistance("ID", "I♥D") == 1);
1274+}
1275+
1276+@safe @nogc nothrow unittest
1277+{
1278+ assert(levenshteinDistance("cat"d, "rat"d) == 1);
1279+}
1280+
1281+/// ditto
1282+size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2)
1283+ (auto ref Range1 s, auto ref Range2 t)
1284+if (isConvertibleToString!Range1 || isConvertibleToString!Range2)
1285+{
1286+ import std.meta : staticMap;
1287+ alias Types = staticMap!(convertToString, Range1, Range2);
1288+ return levenshteinDistance!(equals, Types)(s, t);
1289+}
1290+
1291+@safe unittest
1292+{
1293+ static struct S { string s; alias s this; }
1294+ assert(levenshteinDistance(S("cat"), S("rat")) == 1);
1295+ assert(levenshteinDistance("cat", S("rat")) == 1);
1296+ assert(levenshteinDistance(S("cat"), "rat") == 1);
1297+}
1298+
1299+@safe @nogc nothrow unittest
1300+{
1301+ static struct S { dstring s; alias s this; }
1302+ assert(levenshteinDistance(S("cat"d), S("rat"d)) == 1);
1303+ assert(levenshteinDistance("cat"d, S("rat"d)) == 1);
1304+ assert(levenshteinDistance(S("cat"d), "rat"d) == 1);
1305+}
1306+
1307+/**
1308+Returns the Levenshtein distance and the edit path between $(D s) and
1309+$(D t).
1310+
1311+Params:
1312+ equals = The binary predicate to compare the elements of the two ranges.
1313+ s = The original range.
1314+ t = The transformation target
1315+
1316+Returns:
1317+ Tuple with the first element being the minimal amount of edits to transform s into t and
1318+ the second element being the sequence of edits to effect this transformation.
1319+
1320+Allocates GC memory for the returned EditOp[] array.
1321+*/
1322+Tuple!(size_t, EditOp[])
1323+levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2)
1324+ (Range1 s, Range2 t)
1325+if (isForwardRange!(Range1) && isForwardRange!(Range2))
1326+{
1327+ Levenshtein!(Range1, binaryFun!(equals)) lev;
1328+ auto d = lev.distanceWithPath(s, t);
1329+ return tuple(d, lev.path());
1330+}
1331+
1332+///
1333+@safe unittest
1334+{
1335+ string a = "Saturday", b = "Sundays";
1336+ auto p = levenshteinDistanceAndPath(a, b);
1337+ assert(p[0] == 4);
1338+ assert(equal(p[1], "nrrnsnnni"));
1339+}
1340+
1341+@safe unittest
1342+{
1343+ assert(levenshteinDistance("a", "a") == 0);
1344+ assert(levenshteinDistance("a", "b") == 1);
1345+ assert(levenshteinDistance("aa", "ab") == 1);
1346+ assert(levenshteinDistance("aa", "abc") == 2);
1347+ assert(levenshteinDistance("Saturday", "Sunday") == 3);
1348+ assert(levenshteinDistance("kitten", "sitting") == 3);
1349+}
1350+
1351+/// ditto
1352+Tuple!(size_t, EditOp[])
1353+levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2)
1354+ (auto ref Range1 s, auto ref Range2 t)
1355+if (isConvertibleToString!Range1 || isConvertibleToString!Range2)
1356+{
1357+ import std.meta : staticMap;
1358+ alias Types = staticMap!(convertToString, Range1, Range2);
1359+ return levenshteinDistanceAndPath!(equals, Types)(s, t);
1360+}
1361+
1362+@safe unittest
1363+{
1364+ static struct S { string s; alias s this; }
1365+ assert(levenshteinDistanceAndPath(S("cat"), S("rat"))[0] == 1);
1366+ assert(levenshteinDistanceAndPath("cat", S("rat"))[0] == 1);
1367+ assert(levenshteinDistanceAndPath(S("cat"), "rat")[0] == 1);
1368+}
1369+
1370+// max
1371+/**
1372+Iterates the passed arguments and return the maximum value.
1373+
1374+Params:
1375+ args = The values to select the maximum from. At least two arguments must
1376+ be passed.
1377+
1378+Returns:
1379+ The maximum of the passed-in args. The type of the returned value is
1380+ the type among the passed arguments that is able to store the largest value.
1381+
1382+See_Also:
1383+ $(REF maxElement, std,algorithm,searching)
1384+*/
1385+MaxType!T max(T...)(T args)
1386+if (T.length >= 2)
1387+{
1388+ //Get "a"
1389+ static if (T.length <= 2)
1390+ alias a = args[0];
1391+ else
1392+ auto a = max(args[0 .. ($+1)/2]);
1393+ alias T0 = typeof(a);
1394+
1395+ //Get "b"
1396+ static if (T.length <= 3)
1397+ alias b = args[$-1];
1398+ else
1399+ auto b = max(args[($+1)/2 .. $]);
1400+ alias T1 = typeof(b);
1401+
1402+ import std.algorithm.internal : algoFormat;
1403+ static assert(is(typeof(a < b)),
1404+ algoFormat("Invalid arguments: Cannot compare types %s and %s.", T0.stringof, T1.stringof));
1405+
1406+ //Do the "max" proper with a and b
1407+ import std.functional : lessThan;
1408+ immutable chooseB = lessThan!(T0, T1)(a, b);
1409+ return cast(typeof(return)) (chooseB ? b : a);
1410+}
1411+
1412+///
1413+@safe unittest
1414+{
1415+ int a = 5;
1416+ short b = 6;
1417+ double c = 2;
1418+ auto d = max(a, b);
1419+ assert(is(typeof(d) == int));
1420+ assert(d == 6);
1421+ auto e = min(a, b, c);
1422+ assert(is(typeof(e) == double));
1423+ assert(e == 2);
1424+}
1425+
1426+@safe unittest
1427+{
1428+ int a = 5;
1429+ short b = 6;
1430+ double c = 2;
1431+ auto d = max(a, b);
1432+ static assert(is(typeof(d) == int));
1433+ assert(d == 6);
1434+ auto e = max(a, b, c);
1435+ static assert(is(typeof(e) == double));
1436+ assert(e == 6);
1437+ // mixed sign
1438+ a = -5;
1439+ uint f = 5;
1440+ static assert(is(typeof(max(a, f)) == uint));
1441+ assert(max(a, f) == 5);
1442+
1443+ //Test user-defined types
1444+ import std.datetime : Date;
1445+ assert(max(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(2012, 12, 21));
1446+ assert(max(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(2012, 12, 21));
1447+ assert(max(Date(1982, 1, 4), Date.min) == Date(1982, 1, 4));
1448+ assert(max(Date.min, Date(1982, 1, 4)) == Date(1982, 1, 4));
1449+ assert(max(Date(1982, 1, 4), Date.max) == Date.max);
1450+ assert(max(Date.max, Date(1982, 1, 4)) == Date.max);
1451+ assert(max(Date.min, Date.max) == Date.max);
1452+ assert(max(Date.max, Date.min) == Date.max);
1453+}
1454+
1455+// MinType
1456+private template MinType(T...)
1457+if (T.length >= 1)
1458+{
1459+ static if (T.length == 1)
1460+ {
1461+ alias MinType = T[0];
1462+ }
1463+ else static if (T.length == 2)
1464+ {
1465+ static if (!is(typeof(T[0].min)))
1466+ alias MinType = CommonType!T;
1467+ else
1468+ {
1469+ enum hasMostNegative = is(typeof(mostNegative!(T[0]))) &&
1470+ is(typeof(mostNegative!(T[1])));
1471+ static if (hasMostNegative && mostNegative!(T[1]) < mostNegative!(T[0]))
1472+ alias MinType = T[1];
1473+ else static if (hasMostNegative && mostNegative!(T[1]) > mostNegative!(T[0]))
1474+ alias MinType = T[0];
1475+ else static if (T[1].max < T[0].max)
1476+ alias MinType = T[1];
1477+ else
1478+ alias MinType = T[0];
1479+ }
1480+ }
1481+ else
1482+ {
1483+ alias MinType = MinType!(MinType!(T[0 .. ($+1)/2]), MinType!(T[($+1)/2 .. $]));
1484+ }
1485+}
1486+
1487+// min
1488+/**
1489+Iterates the passed arguments and returns the minimum value.
1490+
1491+Params: args = The values to select the minimum from. At least two arguments
1492+ must be passed, and they must be comparable with `<`.
1493+Returns: The minimum of the passed-in values.
1494+See_Also:
1495+ $(REF minElement, std,algorithm,searching)
1496+*/
1497+MinType!T min(T...)(T args)
1498+if (T.length >= 2)
1499+{
1500+ //Get "a"
1501+ static if (T.length <= 2)
1502+ alias a = args[0];
1503+ else
1504+ auto a = min(args[0 .. ($+1)/2]);
1505+ alias T0 = typeof(a);
1506+
1507+ //Get "b"
1508+ static if (T.length <= 3)
1509+ alias b = args[$-1];
1510+ else
1511+ auto b = min(args[($+1)/2 .. $]);
1512+ alias T1 = typeof(b);
1513+
1514+ import std.algorithm.internal : algoFormat;
1515+ static assert(is(typeof(a < b)),
1516+ algoFormat("Invalid arguments: Cannot compare types %s and %s.", T0.stringof, T1.stringof));
1517+
1518+ //Do the "min" proper with a and b
1519+ import std.functional : lessThan;
1520+ immutable chooseA = lessThan!(T0, T1)(a, b);
1521+ return cast(typeof(return)) (chooseA ? a : b);
1522+}
1523+
1524+///
1525+@safe unittest
1526+{
1527+ int a = 5;
1528+ short b = 6;
1529+ double c = 2;
1530+ auto d = min(a, b);
1531+ static assert(is(typeof(d) == int));
1532+ assert(d == 5);
1533+ auto e = min(a, b, c);
1534+ static assert(is(typeof(e) == double));
1535+ assert(e == 2);
1536+
1537+ // With arguments of mixed signedness, the return type is the one that can
1538+ // store the lowest values.
1539+ a = -10;
1540+ uint f = 10;
1541+ static assert(is(typeof(min(a, f)) == int));
1542+ assert(min(a, f) == -10);
1543+
1544+ // User-defined types that support comparison with < are supported.
1545+ import std.datetime;
1546+ assert(min(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(1982, 1, 4));
1547+ assert(min(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(1982, 1, 4));
1548+ assert(min(Date(1982, 1, 4), Date.min) == Date.min);
1549+ assert(min(Date.min, Date(1982, 1, 4)) == Date.min);
1550+ assert(min(Date(1982, 1, 4), Date.max) == Date(1982, 1, 4));
1551+ assert(min(Date.max, Date(1982, 1, 4)) == Date(1982, 1, 4));
1552+ assert(min(Date.min, Date.max) == Date.min);
1553+ assert(min(Date.max, Date.min) == Date.min);
1554+}
1555+
1556+// mismatch
1557+/**
1558+Sequentially compares elements in $(D r1) and $(D r2) in lockstep, and
1559+stops at the first mismatch (according to $(D pred), by default
1560+equality). Returns a tuple with the reduced ranges that start with the
1561+two mismatched values. Performs $(BIGOH min(r1.length, r2.length))
1562+evaluations of $(D pred).
1563+
1564+See_Also:
1565+ $(HTTP sgi.com/tech/stl/_mismatch.html, STL's _mismatch)
1566+*/
1567+Tuple!(Range1, Range2)
1568+mismatch(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2)
1569+if (isInputRange!(Range1) && isInputRange!(Range2))
1570+{
1571+ for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront())
1572+ {
1573+ if (!binaryFun!(pred)(r1.front, r2.front)) break;
1574+ }
1575+ return tuple(r1, r2);
1576+}
1577+
1578+///
1579+@safe unittest
1580+{
1581+ int[] x = [ 1, 5, 2, 7, 4, 3 ];
1582+ double[] y = [ 1.0, 5, 2, 7.3, 4, 8 ];
1583+ auto m = mismatch(x, y);
1584+ assert(m[0] == x[3 .. $]);
1585+ assert(m[1] == y[3 .. $]);
1586+}
1587+
1588+@safe unittest
1589+{
1590+ int[] a = [ 1, 2, 3 ];
1591+ int[] b = [ 1, 2, 4, 5 ];
1592+ auto mm = mismatch(a, b);
1593+ assert(mm[0] == [3]);
1594+ assert(mm[1] == [4, 5]);
1595+}
1596+
1597+/**
1598+Returns one of a collection of expressions based on the value of the switch
1599+expression.
1600+
1601+$(D choices) needs to be composed of pairs of test expressions and return
1602+expressions. Each test-expression is compared with $(D switchExpression) using
1603+$(D pred)($(D switchExpression) is the first argument) and if that yields true
1604+- the return expression is returned.
1605+
1606+Both the test and the return expressions are lazily evaluated.
1607+
1608+Params:
1609+
1610+switchExpression = The first argument for the predicate.
1611+
1612+choices = Pairs of test expressions and return expressions. The test
1613+expressions will be the second argument for the predicate, and the return
1614+expression will be returned if the predicate yields true with $(D
1615+switchExpression) and the test expression as arguments. May also have a
1616+default return expression, that needs to be the last expression without a test
1617+expression before it. A return expression may be of void type only if it
1618+always throws.
1619+
1620+Returns: The return expression associated with the first test expression that
1621+made the predicate yield true, or the default return expression if no test
1622+expression matched.
1623+
1624+Throws: If there is no default return expression and the predicate does not
1625+yield true with any test expression - $(D SwitchError) is thrown. $(D
1626+SwitchError) is also thrown if a void return expression was executed without
1627+throwing anything.
1628+*/
1629+auto predSwitch(alias pred = "a == b", T, R ...)(T switchExpression, lazy R choices)
1630+{
1631+ import core.exception : SwitchError;
1632+ alias predicate = binaryFun!(pred);
1633+
1634+ foreach (index, ChoiceType; R)
1635+ {
1636+ //The even places in `choices` are for the predicate.
1637+ static if (index % 2 == 1)
1638+ {
1639+ if (predicate(switchExpression, choices[index - 1]()))
1640+ {
1641+ static if (is(typeof(choices[index]()) == void))
1642+ {
1643+ choices[index]();
1644+ throw new SwitchError("Choices that return void should throw");
1645+ }
1646+ else
1647+ {
1648+ return choices[index]();
1649+ }
1650+ }
1651+ }
1652+ }
1653+
1654+ //In case nothing matched:
1655+ static if (R.length % 2 == 1) //If there is a default return expression:
1656+ {
1657+ static if (is(typeof(choices[$ - 1]()) == void))
1658+ {
1659+ choices[$ - 1]();
1660+ throw new SwitchError("Choices that return void should throw");
1661+ }
1662+ else
1663+ {
1664+ return choices[$ - 1]();
1665+ }
1666+ }
1667+ else //If there is no default return expression:
1668+ {
1669+ throw new SwitchError("Input not matched by any pattern");
1670+ }
1671+}
1672+
1673+///
1674+@safe unittest
1675+{
1676+ string res = 2.predSwitch!"a < b"(
1677+ 1, "less than 1",
1678+ 5, "less than 5",
1679+ 10, "less than 10",
1680+ "greater or equal to 10");
1681+
1682+ assert(res == "less than 5");
1683+
1684+ //The arguments are lazy, which allows us to use predSwitch to create
1685+ //recursive functions:
1686+ int factorial(int n)
1687+ {
1688+ return n.predSwitch!"a <= b"(
1689+ -1, {throw new Exception("Can not calculate n! for n < 0");}(),
1690+ 0, 1, // 0! = 1
1691+ n * factorial(n - 1) // n! = n * (n - 1)! for n >= 0
1692+ );
1693+ }
1694+ assert(factorial(3) == 6);
1695+
1696+ //Void return expressions are allowed if they always throw:
1697+ import std.exception : assertThrown;
1698+ assertThrown!Exception(factorial(-9));
1699+}
1700+
1701+@system unittest
1702+{
1703+ import core.exception : SwitchError;
1704+ import std.exception : assertThrown;
1705+
1706+ //Nothing matches - with default return expression:
1707+ assert(20.predSwitch!"a < b"(
1708+ 1, "less than 1",
1709+ 5, "less than 5",
1710+ 10, "less than 10",
1711+ "greater or equal to 10") == "greater or equal to 10");
1712+
1713+ //Nothing matches - without default return expression:
1714+ assertThrown!SwitchError(20.predSwitch!"a < b"(
1715+ 1, "less than 1",
1716+ 5, "less than 5",
1717+ 10, "less than 10",
1718+ ));
1719+
1720+ //Using the default predicate:
1721+ assert(2.predSwitch(
1722+ 1, "one",
1723+ 2, "two",
1724+ 3, "three",
1725+ ) == "two");
1726+
1727+ //Void return expressions must always throw:
1728+ assertThrown!SwitchError(1.predSwitch(
1729+ 0, "zero",
1730+ 1, {}(), //A void return expression that doesn't throw
1731+ 2, "two",
1732+ ));
1733+}
1734+
1735+/**
1736+Checks if the two ranges have the same number of elements. This function is
1737+optimized to always take advantage of the $(D length) member of either range
1738+if it exists.
1739+
1740+If both ranges have a length member, this function is $(BIGOH 1). Otherwise,
1741+this function is $(BIGOH min(r1.length, r2.length)).
1742+
1743+Params:
1744+ r1 = a finite $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1745+ r2 = a finite $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1746+
1747+Returns:
1748+ $(D true) if both ranges have the same length, $(D false) otherwise.
1749+*/
1750+bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
1751+if (isInputRange!Range1 &&
1752+ isInputRange!Range2 &&
1753+ !isInfinite!Range1 &&
1754+ !isInfinite!Range2)
1755+{
1756+ static if (hasLength!(Range1) && hasLength!(Range2))
1757+ {
1758+ return r1.length == r2.length;
1759+ }
1760+ else static if (hasLength!(Range1) && !hasLength!(Range2))
1761+ {
1762+ size_t length;
1763+
1764+ while (!r2.empty)
1765+ {
1766+ r2.popFront;
1767+
1768+ if (++length > r1.length)
1769+ {
1770+ return false;
1771+ }
1772+ }
1773+
1774+ return !(length < r1.length);
1775+ }
1776+ else static if (!hasLength!(Range1) && hasLength!(Range2))
1777+ {
1778+ size_t length;
1779+
1780+ while (!r1.empty)
1781+ {
1782+ r1.popFront;
1783+
1784+ if (++length > r2.length)
1785+ {
1786+ return false;
1787+ }
1788+ }
1789+
1790+ return !(length < r2.length);
1791+ }
1792+ else
1793+ {
1794+ while (!r1.empty)
1795+ {
1796+ if (r2.empty)
1797+ {
1798+ return false;
1799+ }
1800+
1801+ r1.popFront;
1802+ r2.popFront;
1803+ }
1804+
1805+ return r2.empty;
1806+ }
1807+}
1808+
1809+///
1810+@safe nothrow pure unittest
1811+{
1812+ assert(isSameLength([1, 2, 3], [4, 5, 6]));
1813+ assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3]));
1814+ assert(isSameLength("abc", "xyz"));
1815+
1816+ int[] a;
1817+ int[] b;
1818+ assert(isSameLength(a, b));
1819+
1820+ assert(!isSameLength([1, 2, 3], [4, 5]));
1821+ assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]));
1822+ assert(!isSameLength("abcd", "xyz"));
1823+}
1824+
1825+// Test CTFE
1826+@safe pure unittest
1827+{
1828+ enum result1 = isSameLength([1, 2, 3], [4, 5, 6]);
1829+ static assert(result1);
1830+
1831+ enum result2 = isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]);
1832+ static assert(!result2);
1833+}
1834+
1835+@safe nothrow pure unittest
1836+{
1837+ import std.internal.test.dummyrange;
1838+
1839+ auto r1 = new ReferenceInputRange!int([1, 2, 3]);
1840+ auto r2 = new ReferenceInputRange!int([4, 5, 6]);
1841+ assert(isSameLength(r1, r2));
1842+
1843+ auto r3 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1844+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r4;
1845+ assert(isSameLength(r3, r4));
1846+
1847+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r5;
1848+ auto r6 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1849+ assert(isSameLength(r5, r6));
1850+
1851+ auto r7 = new ReferenceInputRange!int([1, 2]);
1852+ auto r8 = new ReferenceInputRange!int([4, 5, 6]);
1853+ assert(!isSameLength(r7, r8));
1854+
1855+ auto r9 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]);
1856+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r10;
1857+ assert(!isSameLength(r9, r10));
1858+
1859+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r11;
1860+ auto r12 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]);
1861+ assert(!isSameLength(r11, r12));
1862+}
1863+
1864+/// For convenience
1865+alias AllocateGC = Flag!"allocateGC";
1866+
1867+/**
1868+Checks if both ranges are permutations of each other.
1869+
1870+This function can allocate if the $(D Yes.allocateGC) flag is passed. This has
1871+the benefit of have better complexity than the $(D Yes.allocateGC) option. However,
1872+this option is only available for ranges whose equality can be determined via each
1873+element's $(D toHash) method. If customized equality is needed, then the $(D pred)
1874+template parameter can be passed, and the function will automatically switch to
1875+the non-allocating algorithm. See $(REF binaryFun, std,functional) for more details on
1876+how to define $(D pred).
1877+
1878+Non-allocating forward range option: $(BIGOH n^2)
1879+Non-allocating forward range option with custom $(D pred): $(BIGOH n^2)
1880+Allocating forward range option: amortized $(BIGOH r1.length) + $(BIGOH r2.length)
1881+
1882+Params:
1883+ pred = an optional parameter to change how equality is defined
1884+ allocate_gc = $(D Yes.allocateGC)/$(D No.allocateGC)
1885+ r1 = A finite $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
1886+ r2 = A finite $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
1887+
1888+Returns:
1889+ $(D true) if all of the elements in $(D r1) appear the same number of times in $(D r2).
1890+ Otherwise, returns $(D false).
1891+*/
1892+
1893+bool isPermutation(AllocateGC allocate_gc, Range1, Range2)
1894+(Range1 r1, Range2 r2)
1895+if (allocate_gc == Yes.allocateGC &&
1896+ isForwardRange!Range1 &&
1897+ isForwardRange!Range2 &&
1898+ !isInfinite!Range1 &&
1899+ !isInfinite!Range2)
1900+{
1901+ alias E1 = Unqual!(ElementType!Range1);
1902+ alias E2 = Unqual!(ElementType!Range2);
1903+
1904+ if (!isSameLength(r1.save, r2.save))
1905+ {
1906+ return false;
1907+ }
1908+
1909+ // Skip the elements at the beginning where r1.front == r2.front,
1910+ // they are in the same order and don't need to be counted.
1911+ while (!r1.empty && !r2.empty && r1.front == r2.front)
1912+ {
1913+ r1.popFront();
1914+ r2.popFront();
1915+ }
1916+
1917+ if (r1.empty && r2.empty)
1918+ {
1919+ return true;
1920+ }
1921+
1922+ int[CommonType!(E1, E2)] counts;
1923+
1924+ foreach (item; r1)
1925+ {
1926+ ++counts[item];
1927+ }
1928+
1929+ foreach (item; r2)
1930+ {
1931+ if (--counts[item] < 0)
1932+ {
1933+ return false;
1934+ }
1935+ }
1936+
1937+ return true;
1938+}
1939+
1940+/// ditto
1941+bool isPermutation(alias pred = "a == b", Range1, Range2)
1942+(Range1 r1, Range2 r2)
1943+if (is(typeof(binaryFun!(pred))) &&
1944+ isForwardRange!Range1 &&
1945+ isForwardRange!Range2 &&
1946+ !isInfinite!Range1 &&
1947+ !isInfinite!Range2)
1948+{
1949+ import std.algorithm.searching : count;
1950+
1951+ alias predEquals = binaryFun!(pred);
1952+ alias E1 = Unqual!(ElementType!Range1);
1953+ alias E2 = Unqual!(ElementType!Range2);
1954+
1955+ if (!isSameLength(r1.save, r2.save))
1956+ {
1957+ return false;
1958+ }
1959+
1960+ // Skip the elements at the beginning where r1.front == r2.front,
1961+ // they are in the same order and don't need to be counted.
1962+ while (!r1.empty && !r2.empty && predEquals(r1.front, r2.front))
1963+ {
1964+ r1.popFront();
1965+ r2.popFront();
1966+ }
1967+
1968+ if (r1.empty && r2.empty)
1969+ {
1970+ return true;
1971+ }
1972+
1973+ size_t r1_count;
1974+ size_t r2_count;
1975+
1976+ // At each element item, when computing the count of item, scan it while
1977+ // also keeping track of the scanning index. If the first occurrence
1978+ // of item in the scanning loop has an index smaller than the current index,
1979+ // then you know that the element has been seen before
1980+ size_t index;
1981+ outloop: for (auto r1s1 = r1.save; !r1s1.empty; r1s1.popFront, index++)
1982+ {
1983+ auto item = r1s1.front;
1984+ r1_count = 0;
1985+ r2_count = 0;
1986+
1987+ size_t i;
1988+ for (auto r1s2 = r1.save; !r1s2.empty; r1s2.popFront, i++)
1989+ {
1990+ auto e = r1s2.front;
1991+ if (predEquals(e, item) && i < index)
1992+ {
1993+ continue outloop;
1994+ }
1995+ else if (predEquals(e, item))
1996+ {
1997+ ++r1_count;
1998+ }
1999+ }
2000+
2001+ r2_count = r2.save.count!pred(item);
2002+
2003+ if (r1_count != r2_count)
2004+ {
2005+ return false;
2006+ }
2007+ }
2008+
2009+ return true;
2010+}
2011+
2012+///
2013+@safe pure unittest
2014+{
2015+ import std.typecons : Yes;
2016+
2017+ assert(isPermutation([1, 2, 3], [3, 2, 1]));
2018+ assert(isPermutation([1.1, 2.3, 3.5], [2.3, 3.5, 1.1]));
2019+ assert(isPermutation("abc", "bca"));
2020+
2021+ assert(!isPermutation([1, 2], [3, 4]));
2022+ assert(!isPermutation([1, 1, 2, 3], [1, 2, 2, 3]));
2023+ assert(!isPermutation([1, 1], [1, 1, 1]));
2024+
2025+ // Faster, but allocates GC handled memory
2026+ assert(isPermutation!(Yes.allocateGC)([1.1, 2.3, 3.5], [2.3, 3.5, 1.1]));
2027+ assert(!isPermutation!(Yes.allocateGC)([1, 2], [3, 4]));
2028+}
2029+
2030+// Test @nogc inference
2031+@safe @nogc pure unittest
2032+{
2033+ static immutable arr1 = [1, 2, 3];
2034+ static immutable arr2 = [3, 2, 1];
2035+ assert(isPermutation(arr1, arr2));
2036+
2037+ static immutable arr3 = [1, 1, 2, 3];
2038+ static immutable arr4 = [1, 2, 2, 3];
2039+ assert(!isPermutation(arr3, arr4));
2040+}
2041+
2042+@safe pure unittest
2043+{
2044+ import std.internal.test.dummyrange;
2045+
2046+ auto r1 = new ReferenceForwardRange!int([1, 2, 3, 4]);
2047+ auto r2 = new ReferenceForwardRange!int([1, 2, 4, 3]);
2048+ assert(isPermutation(r1, r2));
2049+
2050+ auto r3 = new ReferenceForwardRange!int([1, 2, 3, 4]);
2051+ auto r4 = new ReferenceForwardRange!int([4, 2, 1, 3]);
2052+ assert(isPermutation!(Yes.allocateGC)(r3, r4));
2053+
2054+ auto r5 = new ReferenceForwardRange!int([1, 2, 3]);
2055+ auto r6 = new ReferenceForwardRange!int([4, 2, 1, 3]);
2056+ assert(!isPermutation(r5, r6));
2057+
2058+ auto r7 = new ReferenceForwardRange!int([4, 2, 1, 3]);
2059+ auto r8 = new ReferenceForwardRange!int([1, 2, 3]);
2060+ assert(!isPermutation!(Yes.allocateGC)(r7, r8));
2061+
2062+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r9;
2063+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r10;
2064+ assert(isPermutation(r9, r10));
2065+
2066+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r11;
2067+ DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r12;
2068+ assert(isPermutation!(Yes.allocateGC)(r11, r12));
2069+
2070+ alias mytuple = Tuple!(int, int);
2071+
2072+ assert(isPermutation!"a[0] == b[0]"(
2073+ [mytuple(1, 4), mytuple(2, 5)],
2074+ [mytuple(2, 3), mytuple(1, 2)]
2075+ ));
2076+}
2077+
2078+/**
2079+Get the _first argument `a` that passes an `if (unaryFun!pred(a))` test. If
2080+no argument passes the test, return the last argument.
2081+
2082+Similar to behaviour of the `or` operator in dynamic languages such as Lisp's
2083+`(or ...)` and Python's `a or b or ...` except that the last argument is
2084+returned upon no match.
2085+
2086+Simplifies logic, for instance, in parsing rules where a set of alternative
2087+matchers are tried. The _first one that matches returns it match result,
2088+typically as an abstract syntax tree (AST).
2089+
2090+Bugs:
2091+Lazy parameters are currently, too restrictively, inferred by DMD to
2092+always throw even though they don't need to be. This makes it impossible to
2093+currently mark `either` as `nothrow`. See issue at $(BUGZILLA 12647).
2094+
2095+Returns:
2096+ The _first argument that passes the test `pred`.
2097+*/
2098+CommonType!(T, Ts) either(alias pred = a => a, T, Ts...)(T first, lazy Ts alternatives)
2099+if (alternatives.length >= 1 &&
2100+ !is(CommonType!(T, Ts) == void) &&
2101+ allSatisfy!(ifTestable, T, Ts))
2102+{
2103+ alias predFun = unaryFun!pred;
2104+
2105+ if (predFun(first)) return first;
2106+
2107+ foreach (e; alternatives[0 .. $ - 1])
2108+ if (predFun(e)) return e;
2109+
2110+ return alternatives[$ - 1];
2111+}
2112+
2113+///
2114+@safe pure unittest
2115+{
2116+ const a = 1;
2117+ const b = 2;
2118+ auto ab = either(a, b);
2119+ static assert(is(typeof(ab) == const(int)));
2120+ assert(ab == a);
2121+
2122+ auto c = 2;
2123+ const d = 3;
2124+ auto cd = either!(a => a == 3)(c, d); // use predicate
2125+ static assert(is(typeof(cd) == int));
2126+ assert(cd == d);
2127+
2128+ auto e = 0;
2129+ const f = 2;
2130+ auto ef = either(e, f);
2131+ static assert(is(typeof(ef) == int));
2132+ assert(ef == f);
2133+
2134+ immutable p = 1;
2135+ immutable q = 2;
2136+ auto pq = either(p, q);
2137+ static assert(is(typeof(pq) == immutable(int)));
2138+ assert(pq == p);
2139+
2140+ assert(either(3, 4) == 3);
2141+ assert(either(0, 4) == 4);
2142+ assert(either(0, 0) == 0);
2143+ assert(either("", "a") == "");
2144+
2145+ string r = null;
2146+ assert(either(r, "a") == "a");
2147+ assert(either("a", "") == "a");
2148+
2149+ immutable s = [1, 2];
2150+ assert(either(s, s) == s);
2151+
2152+ assert(either([0, 1], [1, 2]) == [0, 1]);
2153+ assert(either([0, 1], [1]) == [0, 1]);
2154+ assert(either("a", "b") == "a");
2155+
2156+ static assert(!__traits(compiles, either(1, "a")));
2157+ static assert(!__traits(compiles, either(1.0, "a")));
2158+ static assert(!__traits(compiles, either('a', "a")));
2159+}
gcc/libphobos/src/std/algorithm/internal.d+77−0
@@ -0,0 +1,77 @@
1+// Written in the D programming language.
2+
3+/// Helper functions for std.algorithm package.
4+module std.algorithm.internal;
5+
6+
7+// Same as std.string.format, but "self-importing".
8+// Helps reduce code and imports, particularly in static asserts.
9+// Also helps with missing imports errors.
10+package template algoFormat()
11+{
12+ import std.format : format;
13+ alias algoFormat = format;
14+}
15+
16+// Internal random array generators
17+version (unittest)
18+{
19+ package enum size_t maxArraySize = 50;
20+ package enum size_t minArraySize = maxArraySize - 1;
21+
22+ package string[] rndstuff(T : string)()
23+ {
24+ import std.random : Random, unpredictableSeed, uniform;
25+
26+ static Random rnd;
27+ static bool first = true;
28+ if (first)
29+ {
30+ rnd = Random(unpredictableSeed);
31+ first = false;
32+ }
33+ string[] result =
34+ new string[uniform(minArraySize, maxArraySize, rnd)];
35+ string alpha = "abcdefghijABCDEFGHIJ";
36+ foreach (ref s; result)
37+ {
38+ foreach (i; 0 .. uniform(0u, 20u, rnd))
39+ {
40+ auto j = uniform(0, alpha.length - 1, rnd);
41+ s ~= alpha[j];
42+ }
43+ }
44+ return result;
45+ }
46+
47+ package int[] rndstuff(T : int)()
48+ {
49+ import std.random : Random, unpredictableSeed, uniform;
50+
51+ static Random rnd;
52+ static bool first = true;
53+ if (first)
54+ {
55+ rnd = Random(unpredictableSeed);
56+ first = false;
57+ }
58+ int[] result = new int[uniform(minArraySize, maxArraySize, rnd)];
59+ foreach (ref i; result)
60+ {
61+ i = uniform(-100, 100, rnd);
62+ }
63+ return result;
64+ }
65+
66+ package double[] rndstuff(T : double)()
67+ {
68+ double[] result;
69+ foreach (i; rndstuff!(int)())
70+ {
71+ result ~= i / 50.0;
72+ }
73+ return result;
74+ }
75+}
76+
77+package(std) T* addressOf(T)(ref T val) { return &val; }
gcc/libphobos/src/std/algorithm/iteration.d+5187−0
@@ -0,0 +1,5187 @@
1+// Written in the D programming language.
2+/**
3+This is a submodule of $(MREF std, algorithm).
4+It contains generic _iteration algorithms.
5+
6+$(SCRIPT inhibitQuickIndex = 1;)
7+$(BOOKTABLE Cheat Sheet,
8+$(TR $(TH Function Name) $(TH Description))
9+$(T2 cache,
10+ Eagerly evaluates and caches another range's $(D front).)
11+$(T2 cacheBidirectional,
12+ As above, but also provides $(D back) and $(D popBack).)
13+$(T2 chunkBy,
14+ $(D chunkBy!((a,b) => a[1] == b[1])([[1, 1], [1, 2], [2, 2], [2, 1]]))
15+ returns a range containing 3 subranges: the first with just
16+ $(D [1, 1]); the second with the elements $(D [1, 2]) and $(D [2, 2]);
17+ and the third with just $(D [2, 1]).)
18+$(T2 cumulativeFold,
19+ $(D cumulativeFold!((a, b) => a + b)([1, 2, 3, 4])) returns a
20+ lazily-evaluated range containing the successive reduced values `1`,
21+ `3`, `6`, `10`.)
22+$(T2 each,
23+ $(D each!writeln([1, 2, 3])) eagerly prints the numbers $(D 1), $(D 2)
24+ and $(D 3) on their own lines.)
25+$(T2 filter,
26+ $(D filter!(a => a > 0)([1, -1, 2, 0, -3])) iterates over elements $(D 1)
27+ and $(D 2).)
28+$(T2 filterBidirectional,
29+ Similar to $(D filter), but also provides $(D back) and $(D popBack) at
30+ a small increase in cost.)
31+$(T2 fold,
32+ $(D fold!((a, b) => a + b)([1, 2, 3, 4])) returns $(D 10).)
33+$(T2 group,
34+ $(D group([5, 2, 2, 3, 3])) returns a range containing the tuples
35+ $(D tuple(5, 1)), $(D tuple(2, 2)), and $(D tuple(3, 2)).)
36+$(T2 joiner,
37+ $(D joiner(["hello", "world!"], "; ")) returns a range that iterates
38+ over the characters $(D "hello; world!"). No new string is created -
39+ the existing inputs are iterated.)
40+$(T2 map,
41+ $(D map!(a => a * 2)([1, 2, 3])) lazily returns a range with the numbers
42+ $(D 2), $(D 4), $(D 6).)
43+$(T2 permutations,
44+ Lazily computes all permutations using Heap's algorithm.)
45+$(T2 reduce,
46+ $(D reduce!((a, b) => a + b)([1, 2, 3, 4])) returns $(D 10).
47+ This is the old implementation of `fold`.)
48+$(T2 splitter,
49+ Lazily splits a range by a separator.)
50+$(T2 sum,
51+ Same as $(D fold), but specialized for accurate summation.)
52+$(T2 uniq,
53+ Iterates over the unique elements in a range, which is assumed sorted.)
54+)
55+
56+Copyright: Andrei Alexandrescu 2008-.
57+
58+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
59+
60+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
61+
62+Source: $(PHOBOSSRC std/algorithm/_iteration.d)
63+
64+Macros:
65+T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
66+ */
67+module std.algorithm.iteration;
68+
69+// FIXME
70+import std.functional; // : unaryFun, binaryFun;
71+import std.range.primitives;
72+import std.traits;
73+
74+private template aggregate(fun...)
75+if (fun.length >= 1)
76+{
77+ /* --Intentionally not ddoc--
78+ * Aggregates elements in each subrange of the given range of ranges using
79+ * the given aggregating function(s).
80+ * Params:
81+ * fun = One or more aggregating functions (binary functions that return a
82+ * single _aggregate value of their arguments).
83+ * ror = A range of ranges to be aggregated.
84+ *
85+ * Returns:
86+ * A range representing the aggregated value(s) of each subrange
87+ * of the original range. If only one aggregating function is specified,
88+ * each element will be the aggregated value itself; if multiple functions
89+ * are specified, each element will be a tuple of the aggregated values of
90+ * each respective function.
91+ */
92+ auto aggregate(RoR)(RoR ror)
93+ if (isInputRange!RoR && isIterable!(ElementType!RoR))
94+ {
95+ return ror.map!(reduce!fun);
96+ }
97+
98+ @safe unittest
99+ {
100+ import std.algorithm.comparison : equal, max, min;
101+
102+ auto data = [[4, 2, 1, 3], [4, 9, -1, 3, 2], [3]];
103+
104+ // Single aggregating function
105+ auto agg1 = data.aggregate!max;
106+ assert(agg1.equal([4, 9, 3]));
107+
108+ // Multiple aggregating functions
109+ import std.typecons : tuple;
110+ auto agg2 = data.aggregate!(max, min);
111+ assert(agg2.equal([
112+ tuple(4, 1),
113+ tuple(9, -1),
114+ tuple(3, 3)
115+ ]));
116+ }
117+}
118+
119+/++
120+$(D cache) eagerly evaluates $(D front) of $(D range)
121+on each construction or call to $(D popFront),
122+to store the result in a cache.
123+The result is then directly returned when $(D front) is called,
124+rather than re-evaluated.
125+
126+This can be a useful function to place in a chain, after functions
127+that have expensive evaluation, as a lazy alternative to $(REF array, std,array).
128+In particular, it can be placed after a call to $(D map), or before a call
129+to $(D filter).
130+
131+$(D cache) may provide
132+$(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
133+iteration if needed, but since this comes at an increased cost, it must be explicitly requested via the
134+call to $(D cacheBidirectional). Furthermore, a bidirectional cache will
135+evaluate the "center" element twice, when there is only one element left in
136+the range.
137+
138+$(D cache) does not provide random access primitives,
139+as $(D cache) would be unable to cache the random accesses.
140+If $(D Range) provides slicing primitives,
141+then $(D cache) will provide the same slicing primitives,
142+but $(D hasSlicing!Cache) will not yield true (as the $(REF hasSlicing, std,_range,primitives)
143+trait also checks for random access).
144+
145+Params:
146+ range = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
147+
148+Returns:
149+ an input range with the cached values of range
150++/
151+auto cache(Range)(Range range)
152+if (isInputRange!Range)
153+{
154+ return _Cache!(Range, false)(range);
155+}
156+
157+/// ditto
158+auto cacheBidirectional(Range)(Range range)
159+if (isBidirectionalRange!Range)
160+{
161+ return _Cache!(Range, true)(range);
162+}
163+
164+///
165+@safe unittest
166+{
167+ import std.algorithm.comparison : equal;
168+ import std.range, std.stdio;
169+ import std.typecons : tuple;
170+
171+ ulong counter = 0;
172+ double fun(int x)
173+ {
174+ ++counter;
175+ // http://en.wikipedia.org/wiki/Quartic_function
176+ return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5;
177+ }
178+ // Without cache, with array (greedy)
179+ auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))()
180+ .filter!(a => a[1] < 0)()
181+ .map!(a => a[0])()
182+ .array();
183+
184+ // the values of x that have a negative y are:
185+ assert(equal(result1, [-3, -2, 2]));
186+
187+ // Check how many times fun was evaluated.
188+ // As many times as the number of items in both source and result.
189+ assert(counter == iota(-4, 5).length + result1.length);
190+
191+ counter = 0;
192+ // Without array, with cache (lazy)
193+ auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))()
194+ .cache()
195+ .filter!(a => a[1] < 0)()
196+ .map!(a => a[0])();
197+
198+ // the values of x that have a negative y are:
199+ assert(equal(result2, [-3, -2, 2]));
200+
201+ // Check how many times fun was evaluated.
202+ // Only as many times as the number of items in source.
203+ assert(counter == iota(-4, 5).length);
204+}
205+
206+/++
207+Tip: $(D cache) is eager when evaluating elements. If calling front on the
208+underlying _range has a side effect, it will be observable before calling
209+front on the actual cached _range.
210+
211+Furthermore, care should be taken composing $(D cache) with $(REF take, std,_range).
212+By placing $(D take) before $(D cache), then $(D cache) will be "aware"
213+of when the _range ends, and correctly stop caching elements when needed.
214+If calling front has no side effect though, placing $(D take) after $(D cache)
215+may yield a faster _range.
216+
217+Either way, the resulting ranges will be equivalent, but maybe not at the
218+same cost or side effects.
219++/
220+@safe unittest
221+{
222+ import std.algorithm.comparison : equal;
223+ import std.range;
224+ int i = 0;
225+
226+ auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop);
227+ auto r1 = r.take(3).cache();
228+ auto r2 = r.cache().take(3);
229+
230+ assert(equal(r1, [0, 1, 2]));
231+ assert(i == 2); //The last "seen" element was 2. The data in cache has been cleared.
232+
233+ assert(equal(r2, [0, 1, 2]));
234+ assert(i == 3); //cache has accessed 3. It is still stored internally by cache.
235+}
236+
237+@safe unittest
238+{
239+ import std.algorithm.comparison : equal;
240+ import std.range;
241+ auto a = [1, 2, 3, 4];
242+ assert(equal(a.map!(a => (a - 1) * a)().cache(), [ 0, 2, 6, 12]));
243+ assert(equal(a.map!(a => (a - 1) * a)().cacheBidirectional().retro(), [12, 6, 2, 0]));
244+ auto r1 = [1, 2, 3, 4].cache() [1 .. $];
245+ auto r2 = [1, 2, 3, 4].cacheBidirectional()[1 .. $];
246+ assert(equal(r1, [2, 3, 4]));
247+ assert(equal(r2, [2, 3, 4]));
248+}
249+
250+@safe unittest
251+{
252+ import std.algorithm.comparison : equal;
253+
254+ //immutable test
255+ static struct S
256+ {
257+ int i;
258+ this(int i)
259+ {
260+ //this.i = i;
261+ }
262+ }
263+ immutable(S)[] s = [S(1), S(2), S(3)];
264+ assert(equal(s.cache(), s));
265+ assert(equal(s.cacheBidirectional(), s));
266+}
267+
268+@safe pure nothrow unittest
269+{
270+ import std.algorithm.comparison : equal;
271+
272+ //safety etc
273+ auto a = [1, 2, 3, 4];
274+ assert(equal(a.cache(), a));
275+ assert(equal(a.cacheBidirectional(), a));
276+}
277+
278+@safe unittest
279+{
280+ char[][] stringbufs = ["hello".dup, "world".dup];
281+ auto strings = stringbufs.map!((a)=>a.idup)().cache();
282+ assert(strings.front is strings.front);
283+}
284+
285+@safe unittest
286+{
287+ import std.range : 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;
301+ bool front() @property {return initialized = true;}
302+ void popFront() {initialized = false;}
303+ enum empty = false;
304+ }
305+ auto r = Range().cache();
306+ assert(r.source.initialized == true);
307+}
308+
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.
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;
547+ auto foo(string[] args)
548+ {
549+ return args.map!strip;
550+ }
551+}
552+
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+
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
783+ static void voidFun(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;
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;
1072+ 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+
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+
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;
1246+ int overX(int a) { return a > x; }
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;
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+ */
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+
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+ ///
1454+ this(R input)
1455+ {
1456+ _input = input;
1457+ if (!_input.empty) popFront();
1458+ }
1459+
1460+ ///
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+ ///
1487+ @property bool empty()
1488+ {
1489+ return _current[1] == 0;
1490+ }
1491+ }
1492+
1493+ ///
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+ ///
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+
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+
1618+ @property bool empty()
1619+ {
1620+ return r.empty || !fun(prev, r.front);
1621+ }
1622+
1623+ @property ElementType!Range front() { return r.front; }
1624+ void popFront() { r.popFront(); }
1625+}
1626+
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+
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+ }
1676+ @property bool empty() { return r.empty; }
1677+
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+
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+
1751+ @property bool empty() { return groupNum == size_t.max; }
1752+ @property auto ref front() { return current.front; }
1753+
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+
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+
1783+ this(Range r)
1784+ {
1785+ impl = RefCounted!Impl(0, r, r.save);
1786+ }
1787+
1788+ @property bool empty() { return impl.current.empty; }
1789+
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+
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+
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+
1840+ this(int[] data) { impl = data; }
1841+ @property bool empty() { return impl.empty; }
1842+ @property auto ref front() { return impl.front; }
1843+ void popFront()
1844+ {
1845+ impl.popFront();
1846+ popCount++;
1847+ }
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+
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+ ];
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+ ];
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.
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+ }
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
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+
2172+ 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+
2219+ 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+
2246+ @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+
2258+ 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+ {
2279+ @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+
2378+ this(int[][] _src)
2379+ {
2380+ src = _src;
2381+ buf.length = 100;
2382+ }
2383+ @property bool empty() { return src.empty; }
2384+ @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+ }
2390+ 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:
2452+ 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+ {
2480+ @property auto empty()
2481+ {
2482+ return _items.empty;
2483+ }
2484+ }
2485+ @property auto ref front()
2486+ {
2487+ assert(!empty, "Attempting to fetch the front of an empty joiner.");
2488+ return _current.front;
2489+ }
2490+ 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+ {
2503+ @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;
2585+ this(int[][] values)
2586+ {
2587+ _values = values;
2588+ _buf = new int[128];
2589+ }
2590+ @property bool empty()
2591+ {
2592+ return _values.length == 0;
2593+ }
2594+ @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+ }
2602+ 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;
2631+ this(dstring[] values)
2632+ {
2633+ _buf.length = 128;
2634+ _values = values;
2635+ }
2636+ @property bool empty()
2637+ {
2638+ return _values.length == 0;
2639+ }
2640+ @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+ }
2648+ 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;
2691+ @property int front()
2692+ {
2693+ return element;
2694+ }
2695+
2696+ enum empty = false;
2697+
2698+ void popFront()
2699+ {
2700+ }
2701+
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+
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+
3018+ 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+ {
3086+ 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
3100+ int fun(int a, int b) @safe {return a + b + 1;}
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+ //"Incompatable 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
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+{
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+
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+ //"Incompatable 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+
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+ {
3724+ 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:
3733+ 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+ {
3754+ @property bool empty()
3755+ {
3756+ return _frontLength == _atEnd;
3757+ }
3758+ }
3759+
3760+ @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+
3771+ 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+ {
3796+ @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+ {
3806+ @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+
3824+ 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+
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+
3992+ @property auto separatorLength() { return _separator.length; }
3993+
3994+ 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+
4005+ 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:
4020+ this(Range input, Separator separator)
4021+ {
4022+ _input = input;
4023+ _separator = separator;
4024+ }
4025+
4026+ @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+ {
4039+ @property bool empty()
4040+ {
4041+ return _frontLength == size_t.max && _input.empty;
4042+ }
4043+ }
4044+
4045+ 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+ {
4077+ @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, ',');
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;
4192+ this(string s) { _impl = s; }
4193+ @property empty() { return _impl.empty; }
4194+ @property auto front() { return _impl.front; }
4195+ void popFront() { _impl = _impl[1..$]; }
4196+ @property RefSep save() { return new RefSep(_impl); }
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+
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+
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+
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+ ];
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+
4484+ 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:
4493+ this(C[] s) pure @safe
4494+ {
4495+ import std.string : strip;
4496+ _s = s.strip();
4497+ getFirst();
4498+ }
4499+
4500+ @property C[] front() pure @safe
4501+ {
4502+ version (assert) if (empty) throw new RangeError();
4503+ return _s[0 .. _frontLength];
4504+ }
4505+
4506+ 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+
4514+ @property bool empty() const @safe pure nothrow
4515+ {
4516+ return _s.empty;
4517+ }
4518+
4519+ @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;
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
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+ }
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+
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;
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
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+
4992+private struct UniqResult(alias pred, Range)
4993+{
4994+ Range _input;
4995+
4996+ this(Range input)
4997+ {
4998+ _input = input;
4999+ }

188 more lines aren’t shown here.

gcc/libphobos/src/std/algorithm/mutation.d+2909−0
@@ -0,0 +1,2909 @@
1+// Written in the D programming language.
2+/**
3+This is a submodule of $(MREF std, algorithm).
4+It contains generic _mutation algorithms.
5+
6+$(SCRIPT inhibitQuickIndex = 1;)
7+$(BOOKTABLE Cheat Sheet,
8+$(TR $(TH Function Name) $(TH Description))
9+$(T2 bringToFront,
10+ If $(D a = [1, 2, 3]) and $(D b = [4, 5, 6, 7]),
11+ $(D bringToFront(a, b)) leaves $(D a = [4, 5, 6]) and
12+ $(D b = [7, 1, 2, 3]).)
13+$(T2 copy,
14+ Copies a range to another. If
15+ $(D a = [1, 2, 3]) and $(D b = new int[5]), then $(D copy(a, b))
16+ leaves $(D b = [1, 2, 3, 0, 0]) and returns $(D b[3 .. $]).)
17+$(T2 fill,
18+ Fills a range with a pattern,
19+ e.g., if $(D a = new int[3]), then $(D fill(a, 4))
20+ leaves $(D a = [4, 4, 4]) and $(D fill(a, [3, 4])) leaves
21+ $(D a = [3, 4, 3]).)
22+$(T2 initializeAll,
23+ If $(D a = [1.2, 3.4]), then $(D initializeAll(a)) leaves
24+ $(D a = [double.init, double.init]).)
25+$(T2 move,
26+ $(D move(a, b)) moves $(D a) into $(D b). $(D move(a)) reads $(D a)
27+ destructively when necessary.)
28+$(T2 moveEmplace,
29+ Similar to $(D move) but assumes `target` is uninitialized.)
30+$(T2 moveAll,
31+ Moves all elements from one range to another.)
32+$(T2 moveEmplaceAll,
33+ Similar to $(D moveAll) but assumes all elements in `target` are uninitialized.)
34+$(T2 moveSome,
35+ Moves as many elements as possible from one range to another.)
36+$(T2 moveEmplaceSome,
37+ Similar to $(D moveSome) but assumes all elements in `target` are uninitialized.)
38+$(T2 remove,
39+ Removes elements from a range in-place, and returns the shortened
40+ range.)
41+$(T2 reverse,
42+ If $(D a = [1, 2, 3]), $(D reverse(a)) changes it to $(D [3, 2, 1]).)
43+$(T2 strip,
44+ Strips all leading and trailing elements equal to a value, or that
45+ satisfy a predicate.
46+ If $(D a = [1, 1, 0, 1, 1]), then $(D strip(a, 1)) and
47+ $(D strip!(e => e == 1)(a)) returns $(D [0]).)
48+$(T2 stripLeft,
49+ Strips all leading elements equal to a value, or that satisfy a
50+ predicate. If $(D a = [1, 1, 0, 1, 1]), then $(D stripLeft(a, 1)) and
51+ $(D stripLeft!(e => e == 1)(a)) returns $(D [0, 1, 1]).)
52+$(T2 stripRight,
53+ Strips all trailing elements equal to a value, or that satisfy a
54+ predicate.
55+ If $(D a = [1, 1, 0, 1, 1]), then $(D stripRight(a, 1)) and
56+ $(D stripRight!(e => e == 1)(a)) returns $(D [1, 1, 0]).)
57+$(T2 swap,
58+ Swaps two values.)
59+$(T2 swapAt,
60+ Swaps two values by indices.)
61+$(T2 swapRanges,
62+ Swaps all elements of two ranges.)
63+$(T2 uninitializedFill,
64+ Fills a range (assumed uninitialized) with a value.)
65+)
66+
67+Copyright: Andrei Alexandrescu 2008-.
68+
69+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
70+
71+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
72+
73+Source: $(PHOBOSSRC std/algorithm/_mutation.d)
74+
75+Macros:
76+T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
77+ */
78+module std.algorithm.mutation;
79+
80+import std.range.primitives;
81+import std.traits : isArray, isBlitAssignable, isNarrowString, Unqual, isSomeChar;
82+// FIXME
83+import std.typecons; // : tuple, Tuple;
84+
85+// bringToFront
86+/**
87+The $(D bringToFront) function has considerable flexibility and
88+usefulness. It can rotate elements in one buffer left or right, swap
89+buffers of equal length, and even move elements across disjoint
90+buffers of different types and different lengths.
91+
92+$(D bringToFront) takes two ranges $(D front) and $(D back), which may
93+be of different types. Considering the concatenation of $(D front) and
94+$(D back) one unified range, $(D bringToFront) rotates that unified
95+range such that all elements in $(D back) are brought to the beginning
96+of the unified range. The relative ordering of elements in $(D front)
97+and $(D back), respectively, remains unchanged.
98+
99+The $(D bringToFront) function treats strings at the code unit
100+level and it is not concerned with Unicode character integrity.
101+$(D bringToFront) is designed as a function for moving elements
102+in ranges, not as a string function.
103+
104+Performs $(BIGOH max(front.length, back.length)) evaluations of $(D
105+swap).
106+
107+Preconditions:
108+
109+Either $(D front) and $(D back) are disjoint, or $(D back) is
110+reachable from $(D front) and $(D front) is not reachable from $(D
111+back).
112+
113+Params:
114+ front = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
115+ back = a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
116+
117+Returns:
118+ The number of elements brought to the front, i.e., the length of $(D back).
119+
120+See_Also:
121+ $(HTTP sgi.com/tech/stl/_rotate.html, STL's rotate)
122+*/
123+size_t bringToFront(InputRange, ForwardRange)(InputRange front, ForwardRange back)
124+if (isInputRange!InputRange && isForwardRange!ForwardRange)
125+{
126+ import std.string : representation;
127+
128+ static if (isNarrowString!InputRange)
129+ {
130+ auto frontW = representation(front);
131+ }
132+ else
133+ {
134+ alias frontW = front;
135+ }
136+ static if (isNarrowString!ForwardRange)
137+ {
138+ auto backW = representation(back);
139+ }
140+ else
141+ {
142+ alias backW = back;
143+ }
144+
145+ return bringToFrontImpl(frontW, backW);
146+}
147+
148+private size_t bringToFrontImpl(InputRange, ForwardRange)(InputRange front, ForwardRange back)
149+if (isInputRange!InputRange && isForwardRange!ForwardRange)
150+{
151+ import std.array : sameHead;
152+ import std.range : take, Take;
153+ enum bool sameHeadExists = is(typeof(front.sameHead(back)));
154+ size_t result;
155+
156+ for (bool semidone; !front.empty && !back.empty; )
157+ {
158+ static if (sameHeadExists)
159+ {
160+ if (front.sameHead(back)) break; // shortcut
161+ }
162+ // Swap elements until front and/or back ends.
163+ auto back0 = back.save;
164+ size_t nswaps;
165+ do
166+ {
167+ static if (sameHeadExists)
168+ {
169+ // Detect the stepping-over condition.
170+ if (front.sameHead(back0)) back0 = back.save;
171+ }
172+ swapFront(front, back);
173+ ++nswaps;
174+ front.popFront();
175+ back.popFront();
176+ }
177+ while (!front.empty && !back.empty);
178+
179+ if (!semidone) result += nswaps;
180+
181+ // Now deal with the remaining elements.
182+ if (back.empty)
183+ {
184+ if (front.empty) break;
185+ // Right side was shorter, which means that we've brought
186+ // all the back elements to the front.
187+ semidone = true;
188+ // Next pass: bringToFront(front, back0) to adjust the rest.
189+ back = back0;
190+ }
191+ else
192+ {
193+ assert(front.empty);
194+ // Left side was shorter. Let's step into the back.
195+ static if (is(InputRange == Take!ForwardRange))
196+ {
197+ front = take(back0, nswaps);
198+ }
199+ else
200+ {
201+ immutable subresult = bringToFront(take(back0, nswaps),
202+ back);
203+ if (!semidone) result += subresult;
204+ break; // done
205+ }
206+ }
207+ }
208+ return result;
209+}
210+
211+/**
212+The simplest use of $(D bringToFront) is for rotating elements in a
213+buffer. For example:
214+*/
215+@safe unittest
216+{
217+ auto arr = [4, 5, 6, 7, 1, 2, 3];
218+ auto p = bringToFront(arr[0 .. 4], arr[4 .. $]);
219+ assert(p == arr.length - 4);
220+ assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]);
221+}
222+
223+/**
224+The $(D front) range may actually "step over" the $(D back)
225+range. This is very useful with forward ranges that cannot compute
226+comfortably right-bounded subranges like $(D arr[0 .. 4]) above. In
227+the example below, $(D r2) is a right subrange of $(D r1).
228+*/
229+@safe unittest
230+{
231+ import std.algorithm.comparison : equal;
232+ import std.container : SList;
233+ import std.range.primitives : popFrontN;
234+
235+ auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3);
236+ auto r1 = list[];
237+ auto r2 = list[]; popFrontN(r2, 4);
238+ assert(equal(r2, [ 1, 2, 3 ]));
239+ bringToFront(r1, r2);
240+ assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ]));
241+}
242+
243+/**
244+Elements can be swapped across ranges of different types:
245+*/
246+@safe unittest
247+{
248+ import std.algorithm.comparison : equal;
249+ import std.container : SList;
250+
251+ auto list = SList!(int)(4, 5, 6, 7);
252+ auto vec = [ 1, 2, 3 ];
253+ bringToFront(list[], vec);
254+ assert(equal(list[], [ 1, 2, 3, 4 ]));
255+ assert(equal(vec, [ 5, 6, 7 ]));
256+}
257+
258+/**
259+Unicode integrity is not preserved:
260+*/
261+@safe unittest
262+{
263+ import std.string : representation;
264+ auto ar = representation("a".dup);
265+ auto br = representation("ç".dup);
266+
267+ bringToFront(ar, br);
268+
269+ auto a = cast(char[]) ar;
270+ auto b = cast(char[]) br;
271+
272+ // Illegal UTF-8
273+ assert(a == "\303");
274+ // Illegal UTF-8
275+ assert(b == "\247a");
276+}
277+
278+@safe unittest
279+{
280+ import std.algorithm.comparison : equal;
281+ import std.conv : text;
282+ import std.random : Random, unpredictableSeed, uniform;
283+
284+ // a more elaborate test
285+ {
286+ auto rnd = Random(unpredictableSeed);
287+ int[] a = new int[uniform(100, 200, rnd)];
288+ int[] b = new int[uniform(100, 200, rnd)];
289+ foreach (ref e; a) e = uniform(-100, 100, rnd);
290+ foreach (ref e; b) e = uniform(-100, 100, rnd);
291+ int[] c = a ~ b;
292+ // writeln("a= ", a);
293+ // writeln("b= ", b);
294+ auto n = bringToFront(c[0 .. a.length], c[a.length .. $]);
295+ //writeln("c= ", c);
296+ assert(n == b.length);
297+ assert(c == b ~ a, text(c, "\n", a, "\n", b));
298+ }
299+ // different types, moveFront, no sameHead
300+ {
301+ static struct R(T)
302+ {
303+ T[] data;
304+ size_t i;
305+ @property
306+ {
307+ R save() { return this; }
308+ bool empty() { return i >= data.length; }
309+ T front() { return data[i]; }
310+ T front(real e) { return data[i] = cast(T) e; }
311+ }
312+ void popFront() { ++i; }
313+ }
314+ auto a = R!int([1, 2, 3, 4, 5]);
315+ auto b = R!real([6, 7, 8, 9]);
316+ auto n = bringToFront(a, b);
317+ assert(n == 4);
318+ assert(a.data == [6, 7, 8, 9, 1]);
319+ assert(b.data == [2, 3, 4, 5]);
320+ }
321+ // front steps over back
322+ {
323+ int[] arr, r1, r2;
324+
325+ // back is shorter
326+ arr = [4, 5, 6, 7, 1, 2, 3];
327+ r1 = arr;
328+ r2 = arr[4 .. $];
329+ bringToFront(r1, r2) == 3 || assert(0);
330+ assert(equal(arr, [1, 2, 3, 4, 5, 6, 7]));
331+
332+ // front is shorter
333+ arr = [5, 6, 7, 1, 2, 3, 4];
334+ r1 = arr;
335+ r2 = arr[3 .. $];
336+ bringToFront(r1, r2) == 4 || assert(0);
337+ assert(equal(arr, [1, 2, 3, 4, 5, 6, 7]));
338+ }
339+
340+ // Bugzilla 16959
341+ auto arr = ['4', '5', '6', '7', '1', '2', '3'];
342+ auto p = bringToFront(arr[0 .. 4], arr[4 .. $]);
343+
344+ assert(p == arr.length - 4);
345+ assert(arr == ['1', '2', '3', '4', '5', '6', '7']);
346+}
347+
348+// Tests if types are arrays and support slice assign.
349+private enum bool areCopyCompatibleArrays(T1, T2) =
350+ isArray!T1 && isArray!T2 && is(typeof(T2.init[] = T1.init[]));
351+
352+// copy
353+/**
354+Copies the content of $(D source) into $(D target) and returns the
355+remaining (unfilled) part of $(D target).
356+
357+Preconditions: $(D target) shall have enough room to accommodate
358+the entirety of $(D source).
359+
360+Params:
361+ source = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
362+ target = an output range
363+
364+Returns:
365+ The unfilled part of target
366+
367+See_Also:
368+ $(HTTP sgi.com/tech/stl/_copy.html, STL's _copy)
369+ */
370+TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
371+if (areCopyCompatibleArrays!(SourceRange, TargetRange))
372+{
373+ const tlen = target.length;
374+ const slen = source.length;
375+ assert(tlen >= slen,
376+ "Cannot copy a source range into a smaller target range.");
377+
378+ immutable overlaps = __ctfe || () @trusted {
379+ return source.ptr < target.ptr + tlen &&
380+ target.ptr < source.ptr + slen; }();
381+
382+ if (overlaps)
383+ {
384+ foreach (idx; 0 .. slen)
385+ target[idx] = source[idx];
386+ return target[slen .. tlen];
387+ }
388+ else
389+ {
390+ // Array specialization. This uses optimized memory copying
391+ // routines under the hood and is about 10-20x faster than the
392+ // generic implementation.
393+ target[0 .. slen] = source[];
394+ return target[slen .. $];
395+ }
396+}
397+
398+/// ditto
399+TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
400+if (!areCopyCompatibleArrays!(SourceRange, TargetRange) &&
401+ isInputRange!SourceRange &&
402+ isOutputRange!(TargetRange, ElementType!SourceRange))
403+{
404+ // Specialize for 2 random access ranges.
405+ // Typically 2 random access ranges are faster iterated by common
406+ // index than by x.popFront(), y.popFront() pair
407+ static if (isRandomAccessRange!SourceRange &&
408+ hasLength!SourceRange &&
409+ hasSlicing!TargetRange &&
410+ isRandomAccessRange!TargetRange &&
411+ hasLength!TargetRange)
412+ {
413+ auto len = source.length;
414+ foreach (idx; 0 .. len)
415+ target[idx] = source[idx];
416+ return target[len .. target.length];
417+ }
418+ else
419+ {
420+ put(target, source);
421+ return target;
422+ }
423+}
424+
425+///
426+@safe unittest
427+{
428+ int[] a = [ 1, 5 ];
429+ int[] b = [ 9, 8 ];
430+ int[] buf = new int[](a.length + b.length + 10);
431+ auto rem = a.copy(buf); // copy a into buf
432+ rem = b.copy(rem); // copy b into remainder of buf
433+ assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]);
434+ assert(rem.length == 10); // unused slots in buf
435+}
436+
437+/**
438+As long as the target range elements support assignment from source
439+range elements, different types of ranges are accepted:
440+*/
441+@safe unittest
442+{
443+ float[] src = [ 1.0f, 5 ];
444+ double[] dest = new double[src.length];
445+ src.copy(dest);
446+}
447+
448+/**
449+To _copy at most $(D n) elements from a range, you may want to use
450+$(REF take, std,range):
451+*/
452+@safe unittest
453+{
454+ import std.range;
455+ int[] src = [ 1, 5, 8, 9, 10 ];
456+ auto dest = new int[](3);
457+ src.take(dest.length).copy(dest);
458+ assert(dest == [ 1, 5, 8 ]);
459+}
460+
461+/**
462+To _copy just those elements from a range that satisfy a predicate,
463+use $(LREF filter):
464+*/
465+@safe unittest
466+{
467+ import std.algorithm.iteration : filter;
468+ int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ];
469+ auto dest = new int[src.length];
470+ auto rem = src
471+ .filter!(a => (a & 1) == 1)
472+ .copy(dest);
473+ assert(dest[0 .. $ - rem.length] == [ 1, 5, 9, 1 ]);
474+}
475+
476+/**
477+$(REF retro, std,range) can be used to achieve behavior similar to
478+$(HTTP sgi.com/tech/stl/copy_backward.html, STL's copy_backward'):
479+*/
480+@safe unittest
481+{
482+ import std.algorithm, std.range;
483+ int[] src = [1, 2, 4];
484+ int[] dest = [0, 0, 0, 0, 0];
485+ src.retro.copy(dest.retro);
486+ assert(dest == [0, 0, 1, 2, 4]);
487+}
488+
489+// Test CTFE copy.
490+@safe unittest
491+{
492+ enum c = copy([1,2,3], [4,5,6,7]);
493+ assert(c == [7]);
494+}
495+
496+
497+@safe unittest
498+{
499+ import std.algorithm.iteration : filter;
500+
501+ {
502+ int[] a = [ 1, 5 ];
503+ int[] b = [ 9, 8 ];
504+ auto e = copy(filter!("a > 1")(a), b);
505+ assert(b[0] == 5 && e.length == 1);
506+ }
507+
508+ {
509+ int[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
510+ copy(a[5 .. 10], a[4 .. 9]);
511+ assert(a[4 .. 9] == [6, 7, 8, 9, 10]);
512+ }
513+
514+ { // Test for bug 7898
515+ enum v =
516+ {
517+ import std.algorithm;
518+ int[] arr1 = [10, 20, 30, 40, 50];
519+ int[] arr2 = arr1.dup;
520+ copy(arr1, arr2);
521+ return 35;
522+ }();
523+ assert(v == 35);
524+ }
525+}
526+
527+@safe unittest
528+{
529+ // Issue 13650
530+ import std.meta : AliasSeq;
531+ foreach (Char; AliasSeq!(char, wchar, dchar))
532+ {
533+ Char[3] a1 = "123";
534+ Char[6] a2 = "456789";
535+ assert(copy(a1[], a2[]) is a2[3..$]);
536+ assert(a1[] == "123");
537+ assert(a2[] == "123789");
538+ }
539+}
540+
541+/**
542+Assigns $(D value) to each element of input _range $(D range).
543+
544+Params:
545+ range = An
546+ $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
547+ that exposes references to its elements and has assignable
548+ elements
549+ value = Assigned to each element of range
550+
551+See_Also:
552+ $(LREF uninitializedFill)
553+ $(LREF initializeAll)
554+ */
555+void fill(Range, Value)(auto ref Range range, auto ref Value value)
556+if ((isInputRange!Range && is(typeof(range.front = value)) ||
557+ isSomeChar!Value && is(typeof(range[] = value))))
558+{
559+ alias T = ElementType!Range;
560+
561+ static if (is(typeof(range[] = value)))
562+ {
563+ range[] = value;
564+ }
565+ else static if (is(typeof(range[] = T(value))))
566+ {
567+ range[] = T(value);
568+ }
569+ else
570+ {
571+ for ( ; !range.empty; range.popFront() )
572+ {
573+ range.front = value;
574+ }
575+ }
576+}
577+
578+///
579+@safe unittest
580+{
581+ int[] a = [ 1, 2, 3, 4 ];
582+ fill(a, 5);
583+ assert(a == [ 5, 5, 5, 5 ]);
584+}
585+
586+// issue 16342, test fallback on mutable narrow strings
587+@safe unittest
588+{
589+ char[] chars = ['a', 'b'];
590+ fill(chars, 'c');
591+ assert(chars == "cc");
592+
593+ char[2] chars2 = ['a', 'b'];
594+ fill(chars2, 'c');
595+ assert(chars2 == "cc");
596+
597+ wchar[] wchars = ['a', 'b'];
598+ fill(wchars, wchar('c'));
599+ assert(wchars == "cc"w);
600+
601+ dchar[] dchars = ['a', 'b'];
602+ fill(dchars, dchar('c'));
603+ assert(dchars == "cc"d);
604+}
605+
606+@nogc @safe unittest
607+{
608+ const(char)[] chars;
609+ assert(chars.length == 0);
610+ static assert(!__traits(compiles, fill(chars, 'c')));
611+ wstring wchars;
612+ assert(wchars.length == 0);
613+ static assert(!__traits(compiles, fill(wchars, wchar('c'))));
614+}
615+
616+@nogc @safe unittest
617+{
618+ char[] chars;
619+ fill(chars, 'c');
620+ assert(chars == ""c);
621+}
622+
623+@safe unittest
624+{
625+ shared(char)[] chrs = ['r'];
626+ fill(chrs, 'c');
627+ assert(chrs == [shared(char)('c')]);
628+}
629+
630+@nogc @safe unittest
631+{
632+ struct Str(size_t len)
633+ {
634+ private char[len] _data;
635+ void opIndexAssign(char value) @safe @nogc
636+ {_data[] = value;}
637+ }
638+ Str!2 str;
639+ str.fill(':');
640+ assert(str._data == "::");
641+}
642+
643+@safe unittest
644+{
645+ char[] chars = ['a','b','c','d'];
646+ chars[1 .. 3].fill(':');
647+ assert(chars == "a::d");
648+}
649+// end issue 16342
650+
651+@safe unittest
652+{
653+ import std.conv : text;
654+ import std.internal.test.dummyrange;
655+
656+ int[] a = [ 1, 2, 3 ];
657+ fill(a, 6);
658+ assert(a == [ 6, 6, 6 ], text(a));
659+
660+ void fun0()
661+ {
662+ foreach (i; 0 .. 1000)
663+ {
664+ foreach (ref e; a) e = 6;
665+ }
666+ }
667+ void fun1() { foreach (i; 0 .. 1000) fill(a, 6); }
668+
669+ // fill should accept InputRange
670+ alias InputRange = DummyRange!(ReturnBy.Reference, Length.No, RangeType.Input);
671+ enum filler = uint.max;
672+ InputRange range;
673+ fill(range, filler);
674+ foreach (value; range.arr)
675+ assert(value == filler);
676+}
677+
678+@safe unittest
679+{
680+ //ER8638_1 IS_NOT self assignable
681+ static struct ER8638_1
682+ {
683+ void opAssign(int){}
684+ }
685+
686+ //ER8638_1 IS self assignable
687+ static struct ER8638_2
688+ {
689+ void opAssign(ER8638_2){}
690+ void opAssign(int){}
691+ }
692+
693+ auto er8638_1 = new ER8638_1[](10);
694+ auto er8638_2 = new ER8638_2[](10);
695+ er8638_1.fill(5); //generic case
696+ er8638_2.fill(5); //opSlice(T.init) case
697+}
698+
699+@safe unittest
700+{
701+ {
702+ int[] a = [1, 2, 3];
703+ immutable(int) b = 0;
704+ a.fill(b);
705+ assert(a == [0, 0, 0]);
706+ }
707+ {
708+ double[] a = [1, 2, 3];
709+ immutable(int) b = 0;
710+ a.fill(b);
711+ assert(a == [0, 0, 0]);
712+ }
713+}
714+
715+/**
716+Fills $(D range) with a pattern copied from $(D filler). The length of
717+$(D range) does not have to be a multiple of the length of $(D
718+filler). If $(D filler) is empty, an exception is thrown.
719+
720+Params:
721+ range = An $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
722+ that exposes references to its elements and has assignable elements.
723+ filler = The
724+ $(REF_ALTTEXT forward _range, isForwardRange, std,_range,primitives)
725+ representing the _fill pattern.
726+ */
727+void fill(InputRange, ForwardRange)(InputRange range, ForwardRange filler)
728+if (isInputRange!InputRange
729+ && (isForwardRange!ForwardRange
730+ || (isInputRange!ForwardRange && isInfinite!ForwardRange))
731+ && is(typeof(InputRange.init.front = ForwardRange.init.front)))
732+{
733+ static if (isInfinite!ForwardRange)
734+ {
735+ //ForwardRange is infinite, no need for bounds checking or saving
736+ static if (hasSlicing!ForwardRange && hasLength!InputRange
737+ && is(typeof(filler[0 .. range.length])))
738+ {
739+ copy(filler[0 .. range.length], range);
740+ }
741+ else
742+ {
743+ //manual feed
744+ for ( ; !range.empty; range.popFront(), filler.popFront())
745+ {
746+ range.front = filler.front;
747+ }
748+ }
749+ }
750+ else
751+ {
752+ import std.exception : enforce;
753+
754+ enforce(!filler.empty, "Cannot fill range with an empty filler");
755+
756+ static if (hasLength!InputRange && hasLength!ForwardRange
757+ && is(typeof(range.length > filler.length)))
758+ {
759+ //Case we have access to length
760+ immutable len = filler.length;
761+ //Start by bulk copies
762+ while (range.length > len)
763+ {
764+ range = copy(filler.save, range);
765+ }
766+
767+ //and finally fill the partial range. No need to save here.
768+ static if (hasSlicing!ForwardRange && is(typeof(filler[0 .. range.length])))
769+ {
770+ //use a quick copy
771+ auto len2 = range.length;
772+ range = copy(filler[0 .. len2], range);
773+ }
774+ else
775+ {
776+ //iterate. No need to check filler, it's length is longer than range's
777+ for (; !range.empty; range.popFront(), filler.popFront())
778+ {
779+ range.front = filler.front;
780+ }
781+ }
782+ }
783+ else
784+ {
785+ //Most basic case.
786+ auto bck = filler.save;
787+ for (; !range.empty; range.popFront(), filler.popFront())
788+ {
789+ if (filler.empty) filler = bck.save;
790+ range.front = filler.front;
791+ }
792+ }
793+ }
794+}
795+
796+///
797+@safe unittest
798+{
799+ int[] a = [ 1, 2, 3, 4, 5 ];
800+ int[] b = [ 8, 9 ];
801+ fill(a, b);
802+ assert(a == [ 8, 9, 8, 9, 8 ]);
803+}
804+
805+@safe unittest
806+{
807+ import std.exception : assertThrown;
808+ import std.internal.test.dummyrange;
809+
810+ int[] a = [ 1, 2, 3, 4, 5 ];
811+ int[] b = [1, 2];
812+ fill(a, b);
813+ assert(a == [ 1, 2, 1, 2, 1 ]);
814+
815+ // fill should accept InputRange
816+ alias InputRange = DummyRange!(ReturnBy.Reference, Length.No, RangeType.Input);
817+ InputRange range;
818+ fill(range,[1,2]);
819+ foreach (i,value;range.arr)
820+ assert(value == (i%2 == 0?1:2));
821+
822+ //test with a input being a "reference forward" range
823+ fill(a, new ReferenceForwardRange!int([8, 9]));
824+ assert(a == [8, 9, 8, 9, 8]);
825+
826+ //test with a input being an "infinite input" range
827+ fill(a, new ReferenceInfiniteInputRange!int());
828+ assert(a == [0, 1, 2, 3, 4]);
829+
830+ //empty filler test
831+ assertThrown(fill(a, a[$..$]));
832+}
833+
834+/**
835+Initializes all elements of $(D range) with their $(D .init) value.
836+Assumes that the elements of the range are uninitialized.
837+
838+Params:
839+ range = An
840+ $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
841+ that exposes references to its elements and has assignable
842+ elements
843+
844+See_Also:
845+ $(LREF fill)
846+ $(LREF uninitializeFill)
847+ */
848+void initializeAll(Range)(Range range)
849+if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range)
850+{
851+ import core.stdc.string : memset, memcpy;
852+ import std.traits : hasElaborateAssign, isDynamicArray;
853+
854+ alias T = ElementType!Range;
855+ static if (hasElaborateAssign!T)
856+ {
857+ import std.algorithm.internal : addressOf;
858+ //Elaborate opAssign. Must go the memcpy road.
859+ //We avoid calling emplace here, because our goal is to initialize to
860+ //the static state of T.init,
861+ //So we want to avoid any un-necassarilly CC'ing of T.init
862+ auto p = typeid(T).initializer();
863+ if (p.ptr)
864+ {
865+ for ( ; !range.empty ; range.popFront() )
866+ {
867+ static if (__traits(isStaticArray, T))
868+ {
869+ // static array initializer only contains initialization
870+ // for one element of the static array.
871+ auto elemp = cast(void *) addressOf(range.front);
872+ auto endp = elemp + T.sizeof;
873+ while (elemp < endp)
874+ {
875+ memcpy(elemp, p.ptr, p.length);
876+ elemp += p.length;
877+ }
878+ }
879+ else
880+ {
881+ memcpy(addressOf(range.front), p.ptr, T.sizeof);
882+ }
883+ }
884+ }
885+ else
886+ static if (isDynamicArray!Range)
887+ memset(range.ptr, 0, range.length * T.sizeof);
888+ else
889+ for ( ; !range.empty ; range.popFront() )
890+ memset(addressOf(range.front), 0, T.sizeof);
891+ }
892+ else
893+ fill(range, T.init);
894+}
895+
896+/// ditto
897+void initializeAll(Range)(Range range)
898+if (is(Range == char[]) || is(Range == wchar[]))
899+{
900+ alias T = ElementEncodingType!Range;
901+ range[] = T.init;
902+}
903+
904+///
905+@system unittest
906+{
907+ import core.stdc.stdlib : malloc, free;
908+
909+ struct S
910+ {
911+ int a = 10;
912+ }
913+
914+ auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
915+ initializeAll(s);
916+ assert(s == [S(10), S(10), S(10), S(10), S(10)]);
917+
918+ scope(exit) free(s.ptr);
919+}
920+
921+@system unittest
922+{
923+ import std.algorithm.iteration : filter;
924+ import std.meta : AliasSeq;
925+ import std.traits : hasElaborateAssign;
926+
927+ //Test strings:
928+ //Must work on narrow strings.
929+ //Must reject const
930+ char[3] a = void;
931+ a[].initializeAll();
932+ assert(a[] == [char.init, char.init, char.init]);
933+ string s;
934+ assert(!__traits(compiles, s.initializeAll()));
935+ assert(!__traits(compiles, s.initializeAll()));
936+ assert(s.empty);
937+
938+ //Note: Cannot call uninitializedFill on narrow strings
939+
940+ enum e {e1, e2}
941+ e[3] b1 = void;
942+ b1[].initializeAll();
943+ assert(b1[] == [e.e1, e.e1, e.e1]);
944+ e[3] b2 = void;
945+ b2[].uninitializedFill(e.e2);
946+ assert(b2[] == [e.e2, e.e2, e.e2]);
947+
948+ static struct S1
949+ {
950+ int i;
951+ }
952+ static struct S2
953+ {
954+ int i = 1;
955+ }
956+ static struct S3
957+ {
958+ int i;
959+ this(this){}
960+ }
961+ static struct S4
962+ {
963+ int i = 1;
964+ this(this){}
965+ }
966+ static assert(!hasElaborateAssign!S1);
967+ static assert(!hasElaborateAssign!S2);
968+ static assert( hasElaborateAssign!S3);
969+ static assert( hasElaborateAssign!S4);
970+ assert(!typeid(S1).initializer().ptr);
971+ assert( typeid(S2).initializer().ptr);
972+ assert(!typeid(S3).initializer().ptr);
973+ assert( typeid(S4).initializer().ptr);
974+
975+ foreach (S; AliasSeq!(S1, S2, S3, S4))
976+ {
977+ //initializeAll
978+ {
979+ //Array
980+ S[3] ss1 = void;
981+ ss1[].initializeAll();
982+ assert(ss1[] == [S.init, S.init, S.init]);
983+
984+ //Not array
985+ S[3] ss2 = void;
986+ auto sf = ss2[].filter!"true"();
987+
988+ sf.initializeAll();
989+ assert(ss2[] == [S.init, S.init, S.init]);
990+ }
991+ //uninitializedFill
992+ {
993+ //Array
994+ S[3] ss1 = void;
995+ ss1[].uninitializedFill(S(2));
996+ assert(ss1[] == [S(2), S(2), S(2)]);
997+
998+ //Not array
999+ S[3] ss2 = void;
1000+ auto sf = ss2[].filter!"true"();
1001+ sf.uninitializedFill(S(2));
1002+ assert(ss2[] == [S(2), S(2), S(2)]);
1003+ }
1004+ }
1005+}
1006+
1007+// test that initializeAll works for arrays of static arrays of structs with
1008+// elaborate assigns.
1009+@system unittest
1010+{
1011+ struct Int {
1012+ ~this() {}
1013+ int x = 3;
1014+ }
1015+ Int[2] xs = [Int(1), Int(2)];
1016+ struct R {
1017+ bool done;
1018+ bool empty() { return done; }
1019+ ref Int[2] front() { return xs; }
1020+ void popFront() { done = true; }
1021+ }
1022+ initializeAll(R());
1023+ assert(xs[0].x == 3);
1024+ assert(xs[1].x == 3);
1025+}
1026+
1027+// move
1028+/**
1029+Moves `source` into `target`, via a destructive copy when necessary.
1030+
1031+If `T` is a struct with a destructor or postblit defined, source is reset
1032+to its `.init` value after it is moved into target, otherwise it is
1033+left unchanged.
1034+
1035+Preconditions:
1036+If source has internal pointers that point to itself, it cannot be moved, and
1037+will trigger an assertion failure.
1038+
1039+Params:
1040+ source = Data to copy.
1041+ target = Where to copy into. The destructor, if any, is invoked before the
1042+ copy is performed.
1043+*/
1044+void move(T)(ref T source, ref T target)
1045+{
1046+ // test @safe destructible
1047+ static if (__traits(compiles, (T t) @safe {}))
1048+ trustedMoveImpl(source, target);
1049+ else
1050+ moveImpl(source, target);
1051+}
1052+
1053+/// For non-struct types, `move` just performs `target = source`:
1054+@safe unittest
1055+{
1056+ Object obj1 = new Object;
1057+ Object obj2 = obj1;
1058+ Object obj3;
1059+
1060+ move(obj2, obj3);
1061+ assert(obj3 is obj1);
1062+ // obj2 unchanged
1063+ assert(obj2 is obj1);
1064+}
1065+
1066+///
1067+pure nothrow @safe @nogc unittest
1068+{
1069+ // Structs without destructors are simply copied
1070+ struct S1
1071+ {
1072+ int a = 1;
1073+ int b = 2;
1074+ }
1075+ S1 s11 = { 10, 11 };
1076+ S1 s12;
1077+
1078+ move(s11, s12);
1079+
1080+ assert(s12 == S1(10, 11));
1081+ assert(s11 == s12);
1082+
1083+ // But structs with destructors or postblits are reset to their .init value
1084+ // after copying to the target.
1085+ struct S2
1086+ {
1087+ int a = 1;
1088+ int b = 2;
1089+
1090+ ~this() pure nothrow @safe @nogc { }
1091+ }
1092+ S2 s21 = { 3, 4 };
1093+ S2 s22;
1094+
1095+ move(s21, s22);
1096+
1097+ assert(s21 == S2(1, 2));
1098+ assert(s22 == S2(3, 4));
1099+}
1100+
1101+@safe unittest
1102+{
1103+ import std.exception : assertCTFEable;
1104+ import std.traits;
1105+
1106+ assertCTFEable!((){
1107+ Object obj1 = new Object;
1108+ Object obj2 = obj1;
1109+ Object obj3;
1110+ move(obj2, obj3);
1111+ assert(obj3 is obj1);
1112+
1113+ static struct S1 { int a = 1, b = 2; }
1114+ S1 s11 = { 10, 11 };
1115+ S1 s12;
1116+ move(s11, s12);
1117+ assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1118+
1119+ static struct S2 { int a = 1; int * b; }
1120+ S2 s21 = { 10, null };
1121+ s21.b = new int;
1122+ S2 s22;
1123+ move(s21, s22);
1124+ assert(s21 == s22);
1125+ });
1126+ // Issue 5661 test(1)
1127+ static struct S3
1128+ {
1129+ static struct X { int n = 0; ~this(){n = 0;} }
1130+ X x;
1131+ }
1132+ static assert(hasElaborateDestructor!S3);
1133+ S3 s31, s32;
1134+ s31.x.n = 1;
1135+ move(s31, s32);
1136+ assert(s31.x.n == 0);
1137+ assert(s32.x.n == 1);
1138+
1139+ // Issue 5661 test(2)
1140+ static struct S4
1141+ {
1142+ static struct X { int n = 0; this(this){n = 0;} }
1143+ X x;
1144+ }
1145+ static assert(hasElaborateCopyConstructor!S4);
1146+ S4 s41, s42;
1147+ s41.x.n = 1;
1148+ move(s41, s42);
1149+ assert(s41.x.n == 0);
1150+ assert(s42.x.n == 1);
1151+
1152+ // Issue 13990 test
1153+ class S5;
1154+
1155+ S5 s51;
1156+ S5 s52 = s51;
1157+ S5 s53;
1158+ move(s52, s53);
1159+ assert(s53 is s51);
1160+}
1161+
1162+/// Ditto
1163+T move(T)(ref T source)
1164+{
1165+ // test @safe destructible
1166+ static if (__traits(compiles, (T t) @safe {}))
1167+ return trustedMoveImpl(source);
1168+ else
1169+ return moveImpl(source);
1170+}
1171+
1172+/// Non-copyable structs can still be moved:
1173+pure nothrow @safe @nogc unittest
1174+{
1175+ struct S
1176+ {
1177+ int a = 1;
1178+ @disable this(this);
1179+ ~this() pure nothrow @safe @nogc {}
1180+ }
1181+ S s1;
1182+ s1.a = 2;
1183+ S s2 = move(s1);
1184+ assert(s1.a == 1);
1185+ assert(s2.a == 2);
1186+}
1187+
1188+private void trustedMoveImpl(T)(ref T source, ref T target) @trusted
1189+{
1190+ moveImpl(source, target);
1191+}
1192+
1193+private void moveImpl(T)(ref T source, ref T target)
1194+{
1195+ import std.traits : hasElaborateDestructor;
1196+
1197+ static if (is(T == struct))
1198+ {
1199+ if (&source == &target) return;
1200+ // Destroy target before overwriting it
1201+ static if (hasElaborateDestructor!T) target.__xdtor();
1202+ }
1203+ // move and emplace source into target
1204+ moveEmplace(source, target);
1205+}
1206+
1207+private T trustedMoveImpl(T)(ref T source) @trusted
1208+{
1209+ return moveImpl(source);
1210+}
1211+
1212+private T moveImpl(T)(ref T source)
1213+{
1214+ T result = void;
1215+ moveEmplace(source, result);
1216+ return result;
1217+}
1218+
1219+@safe unittest
1220+{
1221+ import std.exception : assertCTFEable;
1222+ import std.traits;
1223+
1224+ assertCTFEable!((){
1225+ Object obj1 = new Object;
1226+ Object obj2 = obj1;
1227+ Object obj3 = move(obj2);
1228+ assert(obj3 is obj1);
1229+
1230+ static struct S1 { int a = 1, b = 2; }
1231+ S1 s11 = { 10, 11 };
1232+ S1 s12 = move(s11);
1233+ assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1234+
1235+ static struct S2 { int a = 1; int * b; }
1236+ S2 s21 = { 10, null };
1237+ s21.b = new int;
1238+ S2 s22 = move(s21);
1239+ assert(s21 == s22);
1240+ });
1241+
1242+ // Issue 5661 test(1)
1243+ static struct S3
1244+ {
1245+ static struct X { int n = 0; ~this(){n = 0;} }
1246+ X x;
1247+ }
1248+ static assert(hasElaborateDestructor!S3);
1249+ S3 s31;
1250+ s31.x.n = 1;
1251+ S3 s32 = move(s31);
1252+ assert(s31.x.n == 0);
1253+ assert(s32.x.n == 1);
1254+
1255+ // Issue 5661 test(2)
1256+ static struct S4
1257+ {
1258+ static struct X { int n = 0; this(this){n = 0;} }
1259+ X x;
1260+ }
1261+ static assert(hasElaborateCopyConstructor!S4);
1262+ S4 s41;
1263+ s41.x.n = 1;
1264+ S4 s42 = move(s41);
1265+ assert(s41.x.n == 0);
1266+ assert(s42.x.n == 1);
1267+
1268+ // Issue 13990 test
1269+ class S5;
1270+
1271+ S5 s51;
1272+ S5 s52 = s51;
1273+ S5 s53;
1274+ s53 = move(s52);
1275+ assert(s53 is s51);
1276+}
1277+
1278+@system unittest
1279+{
1280+ static struct S { int n = 0; ~this() @system { n = 0; } }
1281+ S a, b;
1282+ static assert(!__traits(compiles, () @safe { move(a, b); }));
1283+ static assert(!__traits(compiles, () @safe { move(a); }));
1284+ a.n = 1;
1285+ () @trusted { move(a, b); }();
1286+ assert(a.n == 0);
1287+ a.n = 1;
1288+ () @trusted { move(a); }();
1289+ assert(a.n == 0);
1290+}
1291+
1292+@safe unittest//Issue 6217
1293+{
1294+ import std.algorithm.iteration : map;
1295+ auto x = map!"a"([1,2,3]);
1296+ x = move(x);
1297+}
1298+
1299+@safe unittest// Issue 8055
1300+{
1301+ static struct S
1302+ {
1303+ int x;
1304+ ~this()
1305+ {
1306+ assert(x == 0);
1307+ }
1308+ }
1309+ S foo(S s)
1310+ {
1311+ return move(s);
1312+ }
1313+ S a;
1314+ a.x = 0;
1315+ auto b = foo(a);
1316+ assert(b.x == 0);
1317+}
1318+
1319+@system unittest// Issue 8057
1320+{
1321+ int n = 10;
1322+ struct S
1323+ {
1324+ int x;
1325+ ~this()
1326+ {
1327+ // Access to enclosing scope
1328+ assert(n == 10);
1329+ }
1330+ }
1331+ S foo(S s)
1332+ {
1333+ // Move nested struct
1334+ return move(s);
1335+ }
1336+ S a;
1337+ a.x = 1;
1338+ auto b = foo(a);
1339+ assert(b.x == 1);
1340+
1341+ // Regression 8171
1342+ static struct Array(T)
1343+ {
1344+ // nested struct has no member
1345+ struct Payload
1346+ {
1347+ ~this() {}
1348+ }
1349+ }
1350+ Array!int.Payload x = void;
1351+ move(x);
1352+ move(x, x);
1353+}
1354+
1355+/**
1356+ * Similar to $(LREF move) but assumes `target` is uninitialized. This
1357+ * is more efficient because `source` can be blitted over `target`
1358+ * without destroying or initializing it first.
1359+ *
1360+ * Params:
1361+ * source = value to be moved into target
1362+ * target = uninitialized value to be filled by source
1363+ */
1364+void moveEmplace(T)(ref T source, ref T target) @system
1365+{
1366+ import core.stdc.string : memcpy, memset;
1367+ import std.traits : hasAliasing, hasElaborateAssign,
1368+ hasElaborateCopyConstructor, hasElaborateDestructor,
1369+ isAssignable;
1370+
1371+ static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
1372+ {
1373+ import std.exception : doesPointTo;
1374+ assert(!doesPointTo(source, source), "Cannot move object with internal pointer.");
1375+ }
1376+
1377+ static if (is(T == struct))
1378+ {
1379+ assert(&source !is &target, "source and target must not be identical");
1380+
1381+ static if (hasElaborateAssign!T || !isAssignable!T)
1382+ memcpy(&target, &source, T.sizeof);
1383+ else
1384+ target = source;
1385+
1386+ // If the source defines a destructor or a postblit hook, we must obliterate the
1387+ // object in order to avoid double freeing and undue aliasing
1388+ static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)
1389+ {
1390+ // If T is nested struct, keep original context pointer
1391+ static if (__traits(isNested, T))
1392+ enum sz = T.sizeof - (void*).sizeof;
1393+ else
1394+ enum sz = T.sizeof;
1395+
1396+ auto init = typeid(T).initializer();
1397+ if (init.ptr is null) // null ptr means initialize to 0s
1398+ memset(&source, 0, sz);
1399+ else
1400+ memcpy(&source, init.ptr, sz);
1401+ }
1402+ }
1403+ else
1404+ {
1405+ // Primitive data (including pointers and arrays) or class -
1406+ // assignment works great
1407+ target = source;
1408+ }
1409+}
1410+
1411+///
1412+pure nothrow @nogc @system unittest
1413+{
1414+ static struct Foo
1415+ {
1416+ pure nothrow @nogc:
1417+ this(int* ptr) { _ptr = ptr; }
1418+ ~this() { if (_ptr) ++*_ptr; }
1419+ int* _ptr;
1420+ }
1421+
1422+ int val;
1423+ Foo foo1 = void; // uninitialized
1424+ auto foo2 = Foo(&val); // initialized
1425+ assert(foo2._ptr is &val);
1426+
1427+ // Using `move(foo2, foo1)` would have an undefined effect because it would destroy
1428+ // the uninitialized foo1.
1429+ // moveEmplace directly overwrites foo1 without destroying or initializing it first.
1430+ moveEmplace(foo2, foo1);
1431+ assert(foo1._ptr is &val);
1432+ assert(foo2._ptr is null);
1433+ assert(val == 0);
1434+}
1435+
1436+// moveAll
1437+/**
1438+Calls `move(a, b)` for each element `a` in `src` and the corresponding
1439+element `b` in `tgt`, in increasing order.
1440+
1441+Preconditions:
1442+`walkLength(src) <= walkLength(tgt)`.
1443+This precondition will be asserted. If you cannot ensure there is enough room in
1444+`tgt` to accommodate all of `src` use $(LREF moveSome) instead.
1445+
1446+Params:
1447+ src = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1448+ movable elements.
1449+ tgt = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1450+ elements that elements from $(D src) can be moved into.
1451+
1452+Returns: The leftover portion of $(D tgt) after all elements from $(D src) have
1453+been moved.
1454+ */
1455+InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1456+if (isInputRange!InputRange1 && isInputRange!InputRange2
1457+ && is(typeof(move(src.front, tgt.front))))
1458+{
1459+ return moveAllImpl!move(src, tgt);
1460+}
1461+
1462+///
1463+pure nothrow @safe @nogc unittest
1464+{
1465+ int[3] a = [ 1, 2, 3 ];
1466+ int[5] b;
1467+ assert(moveAll(a[], b[]) is b[3 .. $]);
1468+ assert(a[] == b[0 .. 3]);
1469+ int[3] cmp = [ 1, 2, 3 ];
1470+ assert(a[] == cmp[]);
1471+}
1472+
1473+/**
1474+ * Similar to $(LREF moveAll) but assumes all elements in `tgt` are
1475+ * uninitialized. Uses $(LREF moveEmplace) to move elements from
1476+ * `src` over elements from `tgt`.
1477+ */
1478+InputRange2 moveEmplaceAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1479+if (isInputRange!InputRange1 && isInputRange!InputRange2
1480+ && is(typeof(moveEmplace(src.front, tgt.front))))
1481+{
1482+ return moveAllImpl!moveEmplace(src, tgt);
1483+}
1484+
1485+///
1486+pure nothrow @nogc @system unittest
1487+{
1488+ static struct Foo
1489+ {
1490+ ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; }
1491+ int* _ptr;
1492+ }
1493+ int[3] refs = [0, 1, 2];
1494+ Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])];
1495+ Foo[5] dst = void;
1496+
1497+ auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst
1498+ assert(tail.length == 2); // returns remaining uninitialized values
1499+ initializeAll(tail);
1500+
1501+ import std.algorithm.searching : all;
1502+ assert(src[].all!(e => e._ptr is null));
1503+ assert(dst[0 .. 3].all!(e => e._ptr !is null));
1504+}
1505+
1506+@system unittest
1507+{
1508+ struct InputRange
1509+ {
1510+ ref int front() { return data[0]; }
1511+ void popFront() { data.popFront; }
1512+ bool empty() { return data.empty; }
1513+ int[] data;
1514+ }
1515+ auto a = InputRange([ 1, 2, 3 ]);
1516+ auto b = InputRange(new int[5]);
1517+ moveAll(a, b);
1518+ assert(a.data == b.data[0 .. 3]);
1519+ assert(a.data == [ 1, 2, 3 ]);
1520+}
1521+
1522+private InputRange2 moveAllImpl(alias moveOp, InputRange1, InputRange2)(
1523+ ref InputRange1 src, ref InputRange2 tgt)
1524+{
1525+ import std.exception : enforce;
1526+
1527+ static if (isRandomAccessRange!InputRange1 && hasLength!InputRange1 && hasLength!InputRange2
1528+ && hasSlicing!InputRange2 && isRandomAccessRange!InputRange2)
1529+ {
1530+ auto toMove = src.length;
1531+ assert(toMove <= tgt.length);
1532+ foreach (idx; 0 .. toMove)
1533+ moveOp(src[idx], tgt[idx]);
1534+ return tgt[toMove .. tgt.length];
1535+ }
1536+ else
1537+ {
1538+ for (; !src.empty; src.popFront(), tgt.popFront())
1539+ {
1540+ assert(!tgt.empty);
1541+ moveOp(src.front, tgt.front);
1542+ }
1543+ return tgt;
1544+ }
1545+}
1546+
1547+// moveSome
1548+/**
1549+Calls `move(a, b)` for each element `a` in `src` and the corresponding
1550+element `b` in `tgt`, in increasing order, stopping when either range has been
1551+exhausted.
1552+
1553+Params:
1554+ src = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1555+ movable elements.
1556+ tgt = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1557+ elements that elements from $(D src) can be moved into.
1558+
1559+Returns: The leftover portions of the two ranges after one or the other of the
1560+ranges have been exhausted.
1561+ */
1562+Tuple!(InputRange1, InputRange2) moveSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1563+if (isInputRange!InputRange1 && isInputRange!InputRange2
1564+ && is(typeof(move(src.front, tgt.front))))
1565+{
1566+ return moveSomeImpl!move(src, tgt);
1567+}
1568+
1569+///
1570+pure nothrow @safe @nogc unittest
1571+{
1572+ int[5] a = [ 1, 2, 3, 4, 5 ];
1573+ int[3] b;
1574+ assert(moveSome(a[], b[])[0] is a[3 .. $]);
1575+ assert(a[0 .. 3] == b);
1576+ assert(a == [ 1, 2, 3, 4, 5 ]);
1577+}
1578+
1579+/**
1580+ * Same as $(LREF moveSome) but assumes all elements in `tgt` are
1581+ * uninitialized. Uses $(LREF moveEmplace) to move elements from
1582+ * `src` over elements from `tgt`.
1583+ */
1584+Tuple!(InputRange1, InputRange2) moveEmplaceSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1585+if (isInputRange!InputRange1 && isInputRange!InputRange2
1586+ && is(typeof(move(src.front, tgt.front))))
1587+{
1588+ return moveSomeImpl!moveEmplace(src, tgt);
1589+}
1590+
1591+///
1592+pure nothrow @nogc @system unittest
1593+{
1594+ static struct Foo
1595+ {
1596+ ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; }
1597+ int* _ptr;
1598+ }
1599+ int[4] refs = [0, 1, 2, 3];
1600+ Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])];
1601+ Foo[3] dst = void;
1602+
1603+ auto res = moveEmplaceSome(src[], dst[]);
1604+ assert(res.length == 2);
1605+
1606+ import std.algorithm.searching : all;
1607+ assert(src[0 .. 3].all!(e => e._ptr is null));
1608+ assert(src[3]._ptr !is null);
1609+ assert(dst[].all!(e => e._ptr !is null));
1610+}
1611+
1612+private Tuple!(InputRange1, InputRange2) moveSomeImpl(alias moveOp, InputRange1, InputRange2)(
1613+ ref InputRange1 src, ref InputRange2 tgt)
1614+{
1615+ for (; !src.empty && !tgt.empty; src.popFront(), tgt.popFront())
1616+ moveOp(src.front, tgt.front);
1617+ return tuple(src, tgt);
1618+ }
1619+
1620+
1621+// SwapStrategy
1622+/**
1623+Defines the swapping strategy for algorithms that need to swap
1624+elements in a range (such as partition and sort). The strategy
1625+concerns the swapping of elements that are not the core concern of the
1626+algorithm. For example, consider an algorithm that sorts $(D [ "abc",
1627+"b", "aBc" ]) according to $(D toUpper(a) < toUpper(b)). That
1628+algorithm might choose to swap the two equivalent strings $(D "abc")
1629+and $(D "aBc"). That does not affect the sorting since both $(D [
1630+"abc", "aBc", "b" ]) and $(D [ "aBc", "abc", "b" ]) are valid
1631+outcomes.
1632+
1633+Some situations require that the algorithm must NOT ever change the
1634+relative ordering of equivalent elements (in the example above, only
1635+$(D [ "abc", "aBc", "b" ]) would be the correct result). Such
1636+algorithms are called $(B stable). If the ordering algorithm may swap
1637+equivalent elements discretionarily, the ordering is called $(B
1638+unstable).
1639+
1640+Yet another class of algorithms may choose an intermediate tradeoff by
1641+being stable only on a well-defined subrange of the range. There is no
1642+established terminology for such behavior; this library calls it $(B
1643+semistable).
1644+
1645+Generally, the $(D stable) ordering strategy may be more costly in
1646+time and/or space than the other two because it imposes additional
1647+constraints. Similarly, $(D semistable) may be costlier than $(D
1648+unstable). As (semi-)stability is not needed very often, the ordering
1649+algorithms in this module parameterized by $(D SwapStrategy) all
1650+choose $(D SwapStrategy.unstable) as the default.
1651+*/
1652+
1653+enum SwapStrategy
1654+{
1655+ /**
1656+ Allows freely swapping of elements as long as the output
1657+ satisfies the algorithm's requirements.
1658+ */
1659+ unstable,
1660+ /**
1661+ In algorithms partitioning ranges in two, preserve relative
1662+ ordering of elements only to the left of the partition point.
1663+ */
1664+ semistable,
1665+ /**
1666+ Preserve the relative ordering of elements to the largest
1667+ extent allowed by the algorithm's requirements.
1668+ */
1669+ stable,
1670+}
1671+
1672+///
1673+@safe unittest
1674+{
1675+ import std.stdio;
1676+ import std.algorithm.sorting : partition;
1677+ int[] a = [0, 1, 2, 3];
1678+ assert(remove!(SwapStrategy.stable)(a, 1) == [0, 2, 3]);
1679+ a = [0, 1, 2, 3];
1680+ assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 3, 2]);
1681+}
1682+
1683+///
1684+@safe unittest
1685+{
1686+ import std.algorithm.sorting : partition;
1687+
1688+ // Put stuff greater than 3 on the left
1689+ auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1690+ assert(partition!(a => a > 3, SwapStrategy.stable)(arr) == [1, 2, 3]);
1691+ assert(arr == [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]);
1692+
1693+ arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1694+ assert(partition!(a => a > 3, SwapStrategy.semistable)(arr) == [2, 3, 1]);
1695+ assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]);
1696+
1697+ arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1698+ assert(partition!(a => a > 3, SwapStrategy.unstable)(arr) == [3, 2, 1]);
1699+ assert(arr == [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]);
1700+}
1701+
1702+/**
1703+Eliminates elements at given offsets from `range` and returns the shortened
1704+range.
1705+
1706+For example, here is how to _remove a single element from an array:
1707+
1708+----
1709+string[] a = [ "a", "b", "c", "d" ];
1710+a = a.remove(1); // remove element at offset 1
1711+assert(a == [ "a", "c", "d"]);
1712+----
1713+
1714+Note that `remove` does not change the length of the original _range directly;
1715+instead, it returns the shortened _range. If its return value is not assigned to
1716+the original _range, the original _range will retain its original length, though
1717+its contents will have changed:
1718+
1719+----
1720+int[] a = [ 3, 5, 7, 8 ];
1721+assert(remove(a, 1) == [ 3, 7, 8 ]);
1722+assert(a == [ 3, 7, 8, 8 ]);
1723+----
1724+
1725+The element at _offset `1` has been removed and the rest of the elements have
1726+shifted up to fill its place, however, the original array remains of the same
1727+length. This is because all functions in `std.algorithm` only change $(I
1728+content), not $(I topology). The value `8` is repeated because $(LREF move) was
1729+invoked to rearrange elements, and on integers `move` simply copies the source
1730+to the destination. To replace `a` with the effect of the removal, simply
1731+assign the slice returned by `remove` to it, as shown in the first example.
1732+
1733+Multiple indices can be passed into $(D remove). In that case,
1734+elements at the respective indices are all removed. The indices must
1735+be passed in increasing order, otherwise an exception occurs.
1736+
1737+----
1738+int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1739+assert(remove(a, 1, 3, 5) ==
1740+ [ 0, 2, 4, 6, 7, 8, 9, 10 ]);
1741+----
1742+
1743+(Note that all indices refer to slots in the $(I original) array, not
1744+in the array as it is being progressively shortened.) Finally, any
1745+combination of integral offsets and tuples composed of two integral
1746+offsets can be passed in.
1747+
1748+----
1749+int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1750+assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);
1751+----
1752+
1753+In this case, the slots at positions 1, 3, 4, and 9 are removed from
1754+the array. The tuple passes in a range closed to the left and open to
1755+the right (consistent with built-in slices), e.g. $(D tuple(3, 5))
1756+means indices $(D 3) and $(D 4) but not $(D 5).
1757+
1758+If the need is to remove some elements in the range but the order of
1759+the remaining elements does not have to be preserved, you may want to
1760+pass $(D SwapStrategy.unstable) to $(D remove).
1761+
1762+----
1763+int[] a = [ 0, 1, 2, 3 ];
1764+assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
1765+----
1766+
1767+In the case above, the element at slot $(D 1) is removed, but replaced
1768+with the last element of the range. Taking advantage of the relaxation
1769+of the stability requirement, $(D remove) moved elements from the end
1770+of the array over the slots to be removed. This way there is less data
1771+movement to be done which improves the execution time of the function.
1772+
1773+The function $(D remove) works on bidirectional ranges that have assignable
1774+lvalue elements. The moving strategy is (listed from fastest to slowest):
1775+$(UL $(LI If $(D s == SwapStrategy.unstable && isRandomAccessRange!Range &&
1776+hasLength!Range && hasLvalueElements!Range), then elements are moved from the
1777+end of the range into the slots to be filled. In this case, the absolute
1778+minimum of moves is performed.) $(LI Otherwise, if $(D s ==
1779+SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range
1780+&& hasLvalueElements!Range), then elements are still moved from the
1781+end of the range, but time is spent on advancing between slots by repeated
1782+calls to $(D range.popFront).) $(LI Otherwise, elements are moved
1783+incrementally towards the front of $(D range); a given element is never
1784+moved several times, but more elements are moved than in the previous
1785+cases.))
1786+
1787+Params:
1788+ s = a SwapStrategy to determine if the original order needs to be preserved
1789+ range = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,_range,primitives)
1790+ with a length member
1791+ offset = which element(s) to remove
1792+
1793+Returns:
1794+ a range containing all of the elements of range with offset removed
1795+ */
1796+Range remove
1797+(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
1798+(Range range, Offset offset)
1799+if (s != SwapStrategy.stable
1800+ && isBidirectionalRange!Range
1801+ && hasLvalueElements!Range
1802+ && hasLength!Range
1803+ && Offset.length >= 1)
1804+{
1805+ Tuple!(size_t, "pos", size_t, "len")[offset.length] blackouts;
1806+ foreach (i, v; offset)
1807+ {
1808+ static if (is(typeof(v[0]) : size_t) && is(typeof(v[1]) : size_t))
1809+ {
1810+ blackouts[i].pos = v[0];
1811+ blackouts[i].len = v[1] - v[0];
1812+ }
1813+ else
1814+ {
1815+ static assert(is(typeof(v) : size_t), typeof(v).stringof);
1816+ blackouts[i].pos = v;
1817+ blackouts[i].len = 1;
1818+ }
1819+ static if (i > 0)
1820+ {
1821+ import std.exception : enforce;
1822+
1823+ enforce(blackouts[i - 1].pos + blackouts[i - 1].len
1824+ <= blackouts[i].pos,
1825+ "remove(): incorrect ordering of elements to remove");
1826+ }
1827+ }
1828+
1829+ size_t left = 0, right = offset.length - 1;
1830+ auto tgt = range.save;
1831+ size_t tgtPos = 0;
1832+
1833+ while (left <= right)
1834+ {
1835+ // Look for a blackout on the right
1836+ if (blackouts[right].pos + blackouts[right].len >= range.length)
1837+ {
1838+ range.popBackExactly(blackouts[right].len);
1839+
1840+ // Since right is unsigned, we must check for this case, otherwise
1841+ // we might turn it into size_t.max and the loop condition will not
1842+ // fail when it should.
1843+ if (right > 0)
1844+ {
1845+ --right;
1846+ continue;
1847+ }
1848+ else
1849+ break;
1850+ }
1851+ // Advance to next blackout on the left
1852+ assert(blackouts[left].pos >= tgtPos);
1853+ tgt.popFrontExactly(blackouts[left].pos - tgtPos);
1854+ tgtPos = blackouts[left].pos;
1855+
1856+ // Number of elements to the right of blackouts[right]
1857+ immutable tailLen = range.length - (blackouts[right].pos + blackouts[right].len);
1858+ size_t toMove = void;
1859+ if (tailLen < blackouts[left].len)
1860+ {
1861+ toMove = tailLen;
1862+ blackouts[left].pos += toMove;
1863+ blackouts[left].len -= toMove;
1864+ }
1865+ else
1866+ {
1867+ toMove = blackouts[left].len;
1868+ ++left;
1869+ }
1870+ tgtPos += toMove;
1871+ foreach (i; 0 .. toMove)
1872+ {
1873+ move(range.back, tgt.front);
1874+ range.popBack();
1875+ tgt.popFront();
1876+ }
1877+ }
1878+
1879+ return range;
1880+}
1881+
1882+/// Ditto
1883+Range remove
1884+(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
1885+(Range range, Offset offset)
1886+if (s == SwapStrategy.stable
1887+ && isBidirectionalRange!Range
1888+ && hasLvalueElements!Range
1889+ && Offset.length >= 1)
1890+{
1891+ auto result = range;
1892+ auto src = range, tgt = range;
1893+ size_t pos;
1894+ foreach (pass, i; offset)
1895+ {
1896+ static if (is(typeof(i[0])) && is(typeof(i[1])))
1897+ {
1898+ auto from = i[0], delta = i[1] - i[0];
1899+ }
1900+ else
1901+ {
1902+ auto from = i;
1903+ enum delta = 1;
1904+ }
1905+
1906+ static if (pass > 0)
1907+ {
1908+ import std.exception : enforce;
1909+ enforce(pos <= from,
1910+ "remove(): incorrect ordering of elements to remove");
1911+
1912+ for (; pos < from; ++pos, src.popFront(), tgt.popFront())
1913+ {
1914+ move(src.front, tgt.front);
1915+ }
1916+ }
1917+ else
1918+ {
1919+ src.popFrontExactly(from);
1920+ tgt.popFrontExactly(from);
1921+ pos = from;
1922+ }
1923+ // now skip source to the "to" position
1924+ src.popFrontExactly(delta);
1925+ result.popBackExactly(delta);
1926+ pos += delta;
1927+ }
1928+ // leftover move
1929+ moveAll(src, tgt);
1930+ return result;
1931+}
1932+
1933+///
1934+@safe pure unittest
1935+{
1936+ import std.typecons : tuple;
1937+
1938+ auto a = [ 0, 1, 2, 3, 4, 5 ];
1939+ assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5 ]);
1940+ a = [ 0, 1, 2, 3, 4, 5 ];
1941+ assert(remove!(SwapStrategy.stable)(a, 1, 3) == [ 0, 2, 4, 5] );
1942+ a = [ 0, 1, 2, 3, 4, 5 ];
1943+ assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)) == [ 0, 2 ]);
1944+
1945+ a = [ 0, 1, 2, 3, 4, 5 ];
1946+ assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]);
1947+ a = [ 0, 1, 2, 3, 4, 5 ];
1948+ assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]);
1949+}
1950+
1951+@safe unittest
1952+{
1953+ import std.exception : assertThrown;
1954+ import std.range;
1955+
1956+ // http://d.puremagic.com/issues/show_bug.cgi?id=10173
1957+ int[] test = iota(0, 10).array();
1958+ assertThrown(remove!(SwapStrategy.stable)(test, tuple(2, 4), tuple(1, 3)));
1959+ assertThrown(remove!(SwapStrategy.unstable)(test, tuple(2, 4), tuple(1, 3)));
1960+ assertThrown(remove!(SwapStrategy.stable)(test, 2, 4, 1, 3));
1961+ assertThrown(remove!(SwapStrategy.unstable)(test, 2, 4, 1, 3));
1962+}
1963+
1964+@safe unittest
1965+{
1966+ import std.range;
1967+ int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1968+ a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1969+ assert(remove!(SwapStrategy.stable)(a, 1) ==
1970+ [ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]);
1971+
1972+ a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1973+ assert(remove!(SwapStrategy.unstable)(a, 0, 10) ==
1974+ [ 9, 1, 2, 3, 4, 5, 6, 7, 8 ]);
1975+
1976+ a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1977+ assert(remove!(SwapStrategy.unstable)(a, 0, tuple(9, 11)) ==
1978+ [ 8, 1, 2, 3, 4, 5, 6, 7 ]);
1979+ // http://d.puremagic.com/issues/show_bug.cgi?id=5224
1980+ a = [ 1, 2, 3, 4 ];
1981+ assert(remove!(SwapStrategy.unstable)(a, 2) ==
1982+ [ 1, 2, 4 ]);
1983+
1984+ a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1985+ assert(remove!(SwapStrategy.stable)(a, 1, 5) ==
1986+ [ 0, 2, 3, 4, 6, 7, 8, 9, 10 ]);
1987+
1988+ a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1989+ assert(remove!(SwapStrategy.stable)(a, 1, 3, 5)
1990+ == [ 0, 2, 4, 6, 7, 8, 9, 10]);
1991+ a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1992+ assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 5))
1993+ == [ 0, 2, 5, 6, 7, 8, 9, 10]);
1994+
1995+ a = iota(0, 10).array();
1996+ assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4), tuple(6, 7))
1997+ == [0, 9, 8, 7, 4, 5]);
1998+}
1999+
2000+@safe unittest
2001+{
2002+ // Issue 11576
2003+ auto arr = [1,2,3];
2004+ arr = arr.remove!(SwapStrategy.unstable)(2);
2005+ assert(arr == [1,2]);
2006+
2007+}
2008+
2009+@safe unittest
2010+{
2011+ import std.range;
2012+ // Bug# 12889
2013+ int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]];
2014+ auto orig = arr.dup;
2015+ foreach (i; iota(arr.length))
2016+ {
2017+ assert(orig == arr.remove!(SwapStrategy.unstable)(tuple(i,i)));
2018+ assert(orig == arr.remove!(SwapStrategy.stable)(tuple(i,i)));
2019+ }
2020+}
2021+
2022+/**
2023+Reduces the length of the
2024+$(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,_range,primitives) $(D range) by removing
2025+elements that satisfy $(D pred). If $(D s = SwapStrategy.unstable),
2026+elements are moved from the right end of the range over the elements
2027+to eliminate. If $(D s = SwapStrategy.stable) (the default),
2028+elements are moved progressively to front such that their relative
2029+order is preserved. Returns the filtered range.
2030+
2031+Params:
2032+ range = a bidirectional ranges with lvalue elements
2033+
2034+Returns:
2035+ the range with all of the elements where $(D pred) is $(D true)
2036+ removed
2037+*/
2038+Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)
2039+(Range range)
2040+if (isBidirectionalRange!Range
2041+ && hasLvalueElements!Range)
2042+{
2043+ import std.functional : unaryFun;
2044+ auto result = range;
2045+ static if (s != SwapStrategy.stable)
2046+ {
2047+ for (;!range.empty;)
2048+ {
2049+ if (!unaryFun!pred(range.front))
2050+ {
2051+ range.popFront();
2052+ continue;
2053+ }
2054+ move(range.back, range.front);
2055+ range.popBack();
2056+ result.popBack();
2057+ }
2058+ }
2059+ else
2060+ {
2061+ auto tgt = range;
2062+ for (; !range.empty; range.popFront())
2063+ {
2064+ if (unaryFun!(pred)(range.front))
2065+ {
2066+ // yank this guy
2067+ result.popBack();
2068+ continue;
2069+ }
2070+ // keep this guy
2071+ move(range.front, tgt.front);
2072+ tgt.popFront();
2073+ }
2074+ }
2075+ return result;
2076+}
2077+
2078+///
2079+@safe unittest
2080+{
2081+ static immutable base = [1, 2, 3, 2, 4, 2, 5, 2];
2082+
2083+ int[] arr = base[].dup;
2084+
2085+ // using a string-based predicate
2086+ assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]);
2087+
2088+ // The original array contents have been modified,
2089+ // so we need to reset it to its original state.
2090+ // The length is unmodified however.
2091+ arr[] = base[];
2092+
2093+ // using a lambda predicate
2094+ assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]);
2095+}
2096+
2097+@safe unittest
2098+{
2099+ int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
2100+ assert(remove!("a == 2", SwapStrategy.unstable)(a) ==
2101+ [ 1, 6, 3, 5, 3, 4, 5 ]);
2102+ a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
2103+ assert(remove!("a == 2", SwapStrategy.stable)(a) ==
2104+ [ 1, 3, 3, 4, 5, 5, 6 ]);
2105+}
2106+
2107+@nogc @system unittest
2108+{
2109+ // @nogc test
2110+ int[10] arr = [0,1,2,3,4,5,6,7,8,9];
2111+ alias pred = e => e < 5;
2112+
2113+ auto r = arr[].remove!(SwapStrategy.unstable)(0);
2114+ r = r.remove!(SwapStrategy.stable)(0);
2115+ r = r.remove!(pred, SwapStrategy.unstable);
2116+ r = r.remove!(pred, SwapStrategy.stable);
2117+}
2118+
2119+@safe unittest
2120+{
2121+ import std.algorithm.comparison : min;
2122+ import std.algorithm.searching : all, any;
2123+ import std.algorithm.sorting : isStrictlyMonotonic;
2124+ import std.array : array;
2125+ import std.meta : AliasSeq;
2126+ import std.range : iota, only;
2127+ import std.typecons : Tuple;
2128+ alias S = Tuple!(int[2]);
2129+ S[] soffsets;
2130+ foreach (start; 0 .. 5)
2131+ foreach (end; min(start+1,5) .. 5)
2132+ soffsets ~= S([start,end]);
2133+ alias D = Tuple!(int[2],int[2]);
2134+ D[] doffsets;
2135+ foreach (start1; 0 .. 10)
2136+ foreach (end1; min(start1+1,10) .. 10)
2137+ foreach (start2; end1 .. 10)
2138+ foreach (end2; min(start2+1,10) .. 10)
2139+ doffsets ~= D([start1,end1],[start2,end2]);
2140+ alias T = Tuple!(int[2],int[2],int[2]);
2141+ T[] toffsets;
2142+ foreach (start1; 0 .. 15)
2143+ foreach (end1; min(start1+1,15) .. 15)
2144+ foreach (start2; end1 .. 15)
2145+ foreach (end2; min(start2+1,15) .. 15)
2146+ foreach (start3; end2 .. 15)
2147+ foreach (end3; min(start3+1,15) .. 15)
2148+ toffsets ~= T([start1,end1],[start2,end2],[start3,end3]);
2149+
2150+ static void verify(O...)(int[] r, int len, int removed, bool stable, O offsets)
2151+ {
2152+ assert(r.length == len - removed);
2153+ assert(!stable || r.isStrictlyMonotonic);
2154+ assert(r.all!(e => all!(o => e < o[0] || e >= o[1])(offsets.only)));
2155+ }
2156+
2157+ foreach (offsets; AliasSeq!(soffsets,doffsets,toffsets))
2158+ foreach (os; offsets)
2159+ {
2160+ int len = 5*os.length;
2161+ auto w = iota(0, len).array;
2162+ auto x = w.dup;
2163+ auto y = w.dup;
2164+ auto z = w.dup;
2165+ alias pred = e => any!(o => o[0] <= e && e < o[1])(only(os.expand));
2166+ w = w.remove!(SwapStrategy.unstable)(os.expand);
2167+ x = x.remove!(SwapStrategy.stable)(os.expand);
2168+ y = y.remove!(pred, SwapStrategy.unstable);
2169+ z = z.remove!(pred, SwapStrategy.stable);
2170+ int removed;
2171+ foreach (o; os)
2172+ removed += o[1] - o[0];
2173+ verify(w, len, removed, false, os[]);
2174+ verify(x, len, removed, true, os[]);
2175+ verify(y, len, removed, false, os[]);
2176+ verify(z, len, removed, true, os[]);
2177+ assert(w == y);
2178+ assert(x == z);
2179+ }
2180+}
2181+
2182+// reverse
2183+/**
2184+Reverses $(D r) in-place. Performs $(D r.length / 2) evaluations of $(D
2185+swap).
2186+Params:
2187+ r = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
2188+ with swappable elements or a random access range with a length member
2189+
2190+See_Also:
2191+ $(HTTP sgi.com/tech/stl/_reverse.html, STL's _reverse), $(REF retro, std,range) for a lazy reversed range view
2192+*/
2193+void reverse(Range)(Range r)
2194+if (isBidirectionalRange!Range && !isRandomAccessRange!Range
2195+ && hasSwappableElements!Range)
2196+{
2197+ while (!r.empty)
2198+ {
2199+ swap(r.front, r.back);
2200+ r.popFront();
2201+ if (r.empty) break;
2202+ r.popBack();
2203+ }
2204+}
2205+
2206+///
2207+@safe unittest
2208+{
2209+ int[] arr = [ 1, 2, 3 ];
2210+ reverse(arr);
2211+ assert(arr == [ 3, 2, 1 ]);
2212+}
2213+
2214+///ditto
2215+void reverse(Range)(Range r)
2216+if (isRandomAccessRange!Range && hasLength!Range)
2217+{
2218+ //swapAt is in fact the only way to swap non lvalue ranges
2219+ immutable last = r.length-1;
2220+ immutable steps = r.length/2;
2221+ for (size_t i = 0; i < steps; i++)
2222+ {
2223+ r.swapAt(i, last-i);
2224+ }
2225+}
2226+
2227+@safe unittest
2228+{
2229+ int[] range = null;
2230+ reverse(range);
2231+ range = [ 1 ];
2232+ reverse(range);
2233+ assert(range == [1]);
2234+ range = [1, 2];
2235+ reverse(range);
2236+ assert(range == [2, 1]);
2237+ range = [1, 2, 3];
2238+ reverse(range);
2239+ assert(range == [3, 2, 1]);
2240+}
2241+
2242+/**
2243+Reverses $(D r) in-place, where $(D r) is a narrow string (having
2244+elements of type $(D char) or $(D wchar)). UTF sequences consisting of
2245+multiple code units are preserved properly.
2246+
2247+Params:
2248+ s = a narrow string
2249+
2250+Bugs:
2251+ When passing a sting with unicode modifiers on characters, such as $(D \u0301),
2252+ this function will not properly keep the position of the modifier. For example,
2253+ reversing $(D ba\u0301d) ("bád") will result in d\u0301ab ("d́ab") instead of
2254+ $(D da\u0301b) ("dáb").
2255+*/
2256+void reverse(Char)(Char[] s)
2257+if (isNarrowString!(Char[]) && !is(Char == const) && !is(Char == immutable))
2258+{
2259+ import std.string : representation;
2260+ import std.utf : stride;
2261+
2262+ auto r = representation(s);
2263+ for (size_t i = 0; i < s.length; )
2264+ {
2265+ immutable step = stride(s, i);
2266+ if (step > 1)
2267+ {
2268+ .reverse(r[i .. i + step]);
2269+ i += step;
2270+ }
2271+ else
2272+ {
2273+ ++i;
2274+ }
2275+ }
2276+ reverse(r);
2277+}
2278+
2279+///
2280+@safe unittest
2281+{
2282+ char[] arr = "hello\U00010143\u0100\U00010143".dup;
2283+ reverse(arr);
2284+ assert(arr == "\U00010143\u0100\U00010143olleh");
2285+}
2286+
2287+@safe unittest
2288+{
2289+ void test(string a, string b)
2290+ {
2291+ auto c = a.dup;
2292+ reverse(c);
2293+ assert(c == b, c ~ " != " ~ b);
2294+ }
2295+
2296+ test("a", "a");
2297+ test(" ", " ");
2298+ test("\u2029", "\u2029");
2299+ test("\u0100", "\u0100");
2300+ test("\u0430", "\u0430");
2301+ test("\U00010143", "\U00010143");
2302+ test("abcdefcdef", "fedcfedcba");
2303+ test("hello\U00010143\u0100\U00010143", "\U00010143\u0100\U00010143olleh");
2304+}
2305+
2306+/**
2307+ The strip group of functions allow stripping of either leading, trailing,
2308+ or both leading and trailing elements.
2309+
2310+ The $(D stripLeft) function will strip the $(D front) of the range,
2311+ the $(D stripRight) function will strip the $(D back) of the range,
2312+ while the $(D strip) function will strip both the $(D front) and $(D back)
2313+ of the range.
2314+
2315+ Note that the $(D strip) and $(D stripRight) functions require the range to
2316+ be a $(LREF BidirectionalRange) range.
2317+
2318+ All of these functions come in two varieties: one takes a target element,
2319+ where the range will be stripped as long as this element can be found.
2320+ The other takes a lambda predicate, where the range will be stripped as
2321+ long as the predicate returns true.
2322+
2323+ Params:
2324+ range = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
2325+ or $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2326+ element = the elements to remove
2327+
2328+ Returns:
2329+ a Range with all of range except element at the start and end
2330+*/
2331+Range strip(Range, E)(Range range, E element)
2332+if (isBidirectionalRange!Range && is(typeof(range.front == element) : bool))
2333+{
2334+ return range.stripLeft(element).stripRight(element);
2335+}
2336+
2337+/// ditto
2338+Range strip(alias pred, Range)(Range range)
2339+if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2340+{
2341+ return range.stripLeft!pred().stripRight!pred();
2342+}
2343+
2344+/// ditto
2345+Range stripLeft(Range, E)(Range range, E element)
2346+if (isInputRange!Range && is(typeof(range.front == element) : bool))
2347+{
2348+ import std.algorithm.searching : find;
2349+ return find!((auto ref a) => a != element)(range);
2350+}
2351+
2352+/// ditto
2353+Range stripLeft(alias pred, Range)(Range range)
2354+if (isInputRange!Range && is(typeof(pred(range.front)) : bool))
2355+{
2356+ import std.algorithm.searching : find;
2357+ import std.functional : not;
2358+
2359+ return find!(not!pred)(range);
2360+}
2361+
2362+/// ditto
2363+Range stripRight(Range, E)(Range range, E element)
2364+if (isBidirectionalRange!Range && is(typeof(range.back == element) : bool))
2365+{
2366+ for (; !range.empty; range.popBack())
2367+ {
2368+ if (range.back != element)
2369+ break;
2370+ }
2371+ return range;
2372+}
2373+
2374+/// ditto
2375+Range stripRight(alias pred, Range)(Range range)
2376+if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2377+{
2378+ for (; !range.empty; range.popBack())
2379+ {
2380+ if (!pred(range.back))
2381+ break;
2382+ }
2383+ return range;
2384+}
2385+
2386+/// Strip leading and trailing elements equal to the target element.
2387+@safe pure unittest
2388+{
2389+ assert(" foobar ".strip(' ') == "foobar");
2390+ assert("00223.444500".strip('0') == "223.4445");
2391+ assert("ëëêéüŗōpéêëë".strip('ë') == "êéüŗōpéê");
2392+ assert([1, 1, 0, 1, 1].strip(1) == [0]);
2393+ assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2);
2394+}
2395+
2396+/// Strip leading and trailing elements while the predicate returns true.
2397+@safe pure unittest
2398+{
2399+ assert(" foobar ".strip!(a => a == ' ')() == "foobar");
2400+ assert("00223.444500".strip!(a => a == '0')() == "223.4445");
2401+ assert("ëëêéüŗōpéêëë".strip!(a => a == 'ë')() == "êéüŗōpéê");
2402+ assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]);
2403+ assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2);
2404+}
2405+
2406+/// Strip leading elements equal to the target element.
2407+@safe pure unittest
2408+{
2409+ assert(" foobar ".stripLeft(' ') == "foobar ");
2410+ assert("00223.444500".stripLeft('0') == "223.444500");
2411+ assert("ůůűniçodêéé".stripLeft('ů') == "űniçodêéé");
2412+ assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]);
2413+ assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3);
2414+}
2415+
2416+/// Strip leading elements while the predicate returns true.
2417+@safe pure unittest
2418+{
2419+ assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar ");
2420+ assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500");
2421+ assert("ůůűniçodêéé".stripLeft!(a => a == 'ů')() == "űniçodêéé");
2422+ assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]);
2423+ assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2);
2424+}
2425+
2426+/// Strip trailing elements equal to the target element.
2427+@safe pure unittest
2428+{
2429+ assert(" foobar ".stripRight(' ') == " foobar");
2430+ assert("00223.444500".stripRight('0') == "00223.4445");
2431+ assert("ùniçodêéé".stripRight('é') == "ùniçodê");
2432+ assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]);
2433+ assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3);
2434+}
2435+
2436+/// Strip trailing elements while the predicate returns true.
2437+@safe pure unittest
2438+{
2439+ assert(" foobar ".stripRight!(a => a == ' ')() == " foobar");
2440+ assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445");
2441+ assert("ùniçodêéé".stripRight!(a => a == 'é')() == "ùniçodê");
2442+ assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]);
2443+ assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3);
2444+}
2445+
2446+// swap
2447+/**
2448+Swaps $(D lhs) and $(D rhs). The instances $(D lhs) and $(D rhs) are moved in
2449+memory, without ever calling $(D opAssign), nor any other function. $(D T)
2450+need not be assignable at all to be swapped.
2451+
2452+If $(D lhs) and $(D rhs) reference the same instance, then nothing is done.
2453+
2454+$(D lhs) and $(D rhs) must be mutable. If $(D T) is a struct or union, then
2455+its fields must also all be (recursively) mutable.
2456+
2457+Params:
2458+ lhs = Data to be swapped with $(D rhs).
2459+ rhs = Data to be swapped with $(D lhs).
2460+*/
2461+void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow @nogc
2462+if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
2463+{
2464+ import std.traits : hasAliasing, hasElaborateAssign, isAssignable,
2465+ isStaticArray;
2466+ static if (hasAliasing!T) if (!__ctfe)
2467+ {
2468+ import std.exception : doesPointTo;
2469+ assert(!doesPointTo(lhs, lhs), "Swap: lhs internal pointer.");
2470+ assert(!doesPointTo(rhs, rhs), "Swap: rhs internal pointer.");
2471+ assert(!doesPointTo(lhs, rhs), "Swap: lhs points to rhs.");
2472+ assert(!doesPointTo(rhs, lhs), "Swap: rhs points to lhs.");
2473+ }
2474+
2475+ static if (hasElaborateAssign!T || !isAssignable!T)
2476+ {
2477+ if (&lhs != &rhs)
2478+ {
2479+ // For structs with non-trivial assignment, move memory directly
2480+ ubyte[T.sizeof] t = void;
2481+ auto a = (cast(ubyte*) &lhs)[0 .. T.sizeof];
2482+ auto b = (cast(ubyte*) &rhs)[0 .. T.sizeof];
2483+ t[] = a[];
2484+ a[] = b[];
2485+ b[] = t[];
2486+ }
2487+ }
2488+ else
2489+ {
2490+ //Avoid assigning overlapping arrays. Dynamic arrays are fine, because
2491+ //it's their ptr and length properties which get assigned rather
2492+ //than their elements when assigning them, but static arrays are value
2493+ //types and therefore all of their elements get copied as part of
2494+ //assigning them, which would be assigning overlapping arrays if lhs
2495+ //and rhs were the same array.
2496+ static if (isStaticArray!T)
2497+ {
2498+ if (lhs.ptr == rhs.ptr)
2499+ return;
2500+ }
2501+
2502+ // For non-struct types, suffice to do the classic swap
2503+ auto tmp = lhs;
2504+ lhs = rhs;
2505+ rhs = tmp;
2506+ }
2507+}
2508+
2509+///
2510+@safe unittest
2511+{
2512+ // Swapping POD (plain old data) types:
2513+ int a = 42, b = 34;
2514+ swap(a, b);
2515+ assert(a == 34 && b == 42);
2516+
2517+ // Swapping structs with indirection:
2518+ static struct S { int x; char c; int[] y; }
2519+ S s1 = { 0, 'z', [ 1, 2 ] };
2520+ S s2 = { 42, 'a', [ 4, 6 ] };
2521+ swap(s1, s2);
2522+ assert(s1.x == 42);
2523+ assert(s1.c == 'a');
2524+ assert(s1.y == [ 4, 6 ]);
2525+
2526+ assert(s2.x == 0);
2527+ assert(s2.c == 'z');
2528+ assert(s2.y == [ 1, 2 ]);
2529+
2530+ // Immutables cannot be swapped:
2531+ immutable int imm1 = 1, imm2 = 2;
2532+ static assert(!__traits(compiles, swap(imm1, imm2)));
2533+
2534+ int c = imm1 + 0;
2535+ int d = imm2 + 0;
2536+ swap(c, d);
2537+ assert(c == 2);
2538+ assert(d == 1);
2539+}
2540+
2541+///
2542+@safe unittest
2543+{
2544+ // Non-copyable types can still be swapped.
2545+ static struct NoCopy
2546+ {
2547+ this(this) { assert(0); }
2548+ int n;
2549+ string s;
2550+ }
2551+ NoCopy nc1, nc2;
2552+ nc1.n = 127; nc1.s = "abc";
2553+ nc2.n = 513; nc2.s = "uvwxyz";
2554+
2555+ swap(nc1, nc2);
2556+ assert(nc1.n == 513 && nc1.s == "uvwxyz");
2557+ assert(nc2.n == 127 && nc2.s == "abc");
2558+
2559+ swap(nc1, nc1);
2560+ swap(nc2, nc2);
2561+ assert(nc1.n == 513 && nc1.s == "uvwxyz");
2562+ assert(nc2.n == 127 && nc2.s == "abc");
2563+
2564+ // Types containing non-copyable fields can also be swapped.
2565+ static struct NoCopyHolder
2566+ {
2567+ NoCopy noCopy;
2568+ }
2569+ NoCopyHolder h1, h2;
2570+ h1.noCopy.n = 31; h1.noCopy.s = "abc";
2571+ h2.noCopy.n = 65; h2.noCopy.s = null;
2572+
2573+ swap(h1, h2);
2574+ assert(h1.noCopy.n == 65 && h1.noCopy.s == null);
2575+ assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc");
2576+
2577+ swap(h1, h1);
2578+ swap(h2, h2);
2579+ assert(h1.noCopy.n == 65 && h1.noCopy.s == null);
2580+ assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc");
2581+
2582+ // Const types cannot be swapped.
2583+ const NoCopy const1, const2;
2584+ assert(const1.n == 0 && const2.n == 0);
2585+ static assert(!__traits(compiles, swap(const1, const2)));
2586+}
2587+
2588+@safe unittest
2589+{
2590+ //Bug# 4789
2591+ int[1] s = [1];
2592+ swap(s, s);
2593+
2594+ int[3] a = [1, 2, 3];
2595+ swap(a[1], a[2]);
2596+ assert(a == [1, 3, 2]);
2597+}
2598+
2599+@safe unittest
2600+{
2601+ static struct NoAssign
2602+ {
2603+ int i;
2604+ void opAssign(NoAssign) @disable;
2605+ }
2606+ auto s1 = NoAssign(1);
2607+ auto s2 = NoAssign(2);
2608+ swap(s1, s2);
2609+ assert(s1.i == 2);
2610+ assert(s2.i == 1);
2611+}
2612+
2613+@safe unittest
2614+{
2615+ struct S
2616+ {
2617+ const int i;
2618+ int i2 = 2;
2619+ int i3 = 3;
2620+ }
2621+ S s;
2622+ static assert(!__traits(compiles, swap(s, s)));
2623+ swap(s.i2, s.i3);
2624+ assert(s.i2 == 3);
2625+ assert(s.i3 == 2);
2626+}
2627+
2628+@safe unittest
2629+{
2630+ //11853
2631+ import std.traits : isAssignable;
2632+ alias T = Tuple!(int, double);
2633+ static assert(isAssignable!T);
2634+}
2635+
2636+@safe unittest
2637+{
2638+ // 12024
2639+ import std.datetime;
2640+ SysTime a, b;
2641+ swap(a, b);
2642+}
2643+
2644+@system unittest // 9975
2645+{
2646+ import std.exception : doesPointTo, mayPointTo;
2647+ static struct S2
2648+ {
2649+ union
2650+ {
2651+ size_t sz;
2652+ string s;
2653+ }
2654+ }
2655+ S2 a , b;
2656+ a.sz = -1;
2657+ assert(!doesPointTo(a, b));
2658+ assert( mayPointTo(a, b));
2659+ swap(a, b);
2660+
2661+ //Note: we can catch an error here, because there is no RAII in this test
2662+ import std.exception : assertThrown;
2663+ void* p, pp;
2664+ p = &p;
2665+ assertThrown!Error(move(p));
2666+ assertThrown!Error(move(p, pp));
2667+ assertThrown!Error(swap(p, pp));
2668+}
2669+
2670+@system unittest
2671+{
2672+ static struct A
2673+ {
2674+ int* x;
2675+ this(this) { x = new int; }
2676+ }
2677+ A a1, a2;
2678+ swap(a1, a2);
2679+
2680+ static struct B
2681+ {
2682+ int* x;
2683+ void opAssign(B) { x = new int; }
2684+ }
2685+ B b1, b2;
2686+ swap(b1, b2);
2687+}
2688+
2689+/// ditto
2690+void swap(T)(ref T lhs, ref T rhs)
2691+if (is(typeof(lhs.proxySwap(rhs))))
2692+{
2693+ lhs.proxySwap(rhs);
2694+}
2695+
2696+/**
2697+Swaps two elements in-place of a range `r`,
2698+specified by their indices `i1` and `i2`.
2699+
2700+Params:
2701+ r = a range with swappable elements
2702+ i1 = first index
2703+ i2 = second index
2704+*/
2705+void swapAt(R)(auto ref R r, size_t i1, size_t i2)
2706+{
2707+ static if (is(typeof(&r.swapAt)))
2708+ {
2709+ r.swapAt(i1, i2);
2710+ }
2711+ else static if (is(typeof(&r[i1])))
2712+ {
2713+ swap(r[i1], r[i2]);
2714+ }
2715+ else
2716+ {
2717+ if (i1 == i2) return;
2718+ auto t1 = r.moveAt(i1);
2719+ auto t2 = r.moveAt(i2);
2720+ r[i2] = t1;
2721+ r[i1] = t2;
2722+ }
2723+}
2724+
2725+///
2726+pure @safe nothrow unittest
2727+{
2728+ import std.algorithm.comparison : equal;
2729+ auto a = [1, 2, 3];
2730+ a.swapAt(1, 2);
2731+ assert(a.equal([1, 3, 2]));
2732+}
2733+
2734+pure @safe nothrow unittest
2735+{
2736+ import std.algorithm.comparison : equal;
2737+ auto a = [4, 5, 6];
2738+ a.swapAt(1, 1);
2739+ assert(a.equal([4, 5, 6]));
2740+}
2741+
2742+pure @safe nothrow unittest
2743+{
2744+ // test non random access ranges
2745+ import std.algorithm.comparison : equal;
2746+ import std.array : array;
2747+
2748+ char[] b = ['a', 'b', 'c'];
2749+ b.swapAt(1, 2);
2750+ assert(b.equal(['a', 'c', 'b']));
2751+
2752+ int[3] c = [1, 2, 3];
2753+ c.swapAt(1, 2);
2754+ assert(c.array.equal([1, 3, 2]));
2755+
2756+ // opIndex returns lvalue
2757+ struct RandomIndexType(T)
2758+ {
2759+ T payload;
2760+
2761+ @property ref auto opIndex(size_t i)
2762+ {
2763+ return payload[i];
2764+ }
2765+
2766+ }
2767+ auto d = RandomIndexType!(int[])([4, 5, 6]);
2768+ d.swapAt(1, 2);
2769+ assert(d.payload.equal([4, 6, 5]));
2770+
2771+ // custom moveAt and opIndexAssign
2772+ struct RandomMoveAtType(T)
2773+ {
2774+ T payload;
2775+
2776+ ElementType!T moveAt(size_t i)
2777+ {
2778+ return payload.moveAt(i);
2779+ }
2780+
2781+ void opIndexAssign(ElementType!T val, size_t idx)
2782+ {
2783+ payload[idx] = val;
2784+ }
2785+ }
2786+ auto e = RandomMoveAtType!(int[])([7, 8, 9]);
2787+ e.swapAt(1, 2);
2788+ assert(e.payload.equal([7, 9, 8]));
2789+
2790+
2791+ // custom swapAt
2792+ struct RandomSwapAtType(T)
2793+ {
2794+ T payload;
2795+
2796+ void swapAt(size_t i)
2797+ {
2798+ return payload.swapAt(i);
2799+ }
2800+ }
2801+ auto f = RandomMoveAtType!(int[])([10, 11, 12]);
2802+ swapAt(f, 1, 2);
2803+ assert(f.payload.equal([10, 12, 11]));
2804+}
2805+
2806+private void swapFront(R1, R2)(R1 r1, R2 r2)
2807+if (isInputRange!R1 && isInputRange!R2)
2808+{
2809+ static if (is(typeof(swap(r1.front, r2.front))))
2810+ {
2811+ swap(r1.front, r2.front);
2812+ }
2813+ else
2814+ {
2815+ auto t1 = moveFront(r1), t2 = moveFront(r2);
2816+ r1.front = move(t2);
2817+ r2.front = move(t1);
2818+ }
2819+}
2820+
2821+// swapRanges
2822+/**
2823+Swaps all elements of $(D r1) with successive elements in $(D r2).
2824+Returns a tuple containing the remainder portions of $(D r1) and $(D
2825+r2) that were not swapped (one of them will be empty). The ranges may
2826+be of different types but must have the same element type and support
2827+swapping.
2828+
2829+Params:
2830+ r1 = an $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
2831+ with swappable elements
2832+ r2 = an $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
2833+ with swappable elements
2834+
2835+Returns:
2836+ Tuple containing the remainder portions of r1 and r2 that were not swapped
2837+*/
2838+Tuple!(InputRange1, InputRange2)
2839+swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
2840+if (hasSwappableElements!InputRange1 && hasSwappableElements!InputRange2
2841+ && is(ElementType!InputRange1 == ElementType!InputRange2))
2842+{
2843+ for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront())
2844+ {
2845+ swap(r1.front, r2.front);
2846+ }
2847+ return tuple(r1, r2);
2848+}
2849+
2850+///
2851+@safe unittest
2852+{
2853+ import std.range : empty;
2854+ int[] a = [ 100, 101, 102, 103 ];
2855+ int[] b = [ 0, 1, 2, 3 ];
2856+ auto c = swapRanges(a[1 .. 3], b[2 .. 4]);
2857+ assert(c[0].empty && c[1].empty);
2858+ assert(a == [ 100, 2, 3, 103 ]);
2859+ assert(b == [ 0, 1, 101, 102 ]);
2860+}
2861+
2862+/**
2863+Initializes each element of $(D range) with $(D value).
2864+Assumes that the elements of the range are uninitialized.
2865+This is of interest for structs that
2866+define copy constructors (for all other types, $(LREF fill) and
2867+uninitializedFill are equivalent).
2868+
2869+Params:
2870+ range = An
2871+ $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
2872+ that exposes references to its elements and has assignable
2873+ elements
2874+ value = Assigned to each element of range
2875+
2876+See_Also:
2877+ $(LREF fill)
2878+ $(LREF initializeAll)
2879+ */
2880+void uninitializedFill(Range, Value)(Range range, Value value)
2881+if (isInputRange!Range && hasLvalueElements!Range && is(typeof(range.front = value)))
2882+{
2883+ import std.traits : hasElaborateAssign;
2884+
2885+ alias T = ElementType!Range;
2886+ static if (hasElaborateAssign!T)
2887+ {
2888+ import std.conv : emplaceRef;
2889+
2890+ // Must construct stuff by the book
2891+ for (; !range.empty; range.popFront())
2892+ emplaceRef!T(range.front, value);
2893+ }
2894+ else
2895+ // Doesn't matter whether fill is initialized or not
2896+ return fill(range, value);
2897+}
2898+
2899+///
2900+nothrow @system unittest
2901+{
2902+ import core.stdc.stdlib : malloc, free;
2903+
2904+ auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5];
2905+ uninitializedFill(s, 42);
2906+ assert(s == [ 42, 42, 42, 42, 42 ]);
2907+
2908+ scope(exit) free(s.ptr);
2909+}
gcc/libphobos/src/std/algorithm/package.d+198−0
@@ -0,0 +1,198 @@
1+// Written in the D programming language.
2+
3+/**
4+This package implements generic algorithms oriented towards the processing of
5+sequences. Sequences processed by these functions define range-based
6+interfaces. See also $(MREF_ALTTEXT Reference on ranges, std, range) and
7+$(HTTP ddili.org/ders/d.en/ranges.html, tutorial on ranges).
8+
9+$(SCRIPT inhibitQuickIndex = 1;)
10+
11+Algorithms are categorized into the following submodules:
12+
13+$(DIVC quickindex,
14+$(BOOKTABLE ,
15+$(TR $(TH Submodule) $(TH Functions)
16+)
17+$(TR
18+ $(TDNW $(SUBMODULE Searching, searching))
19+ $(TD
20+ $(SUBREF searching, all)
21+ $(SUBREF searching, any)
22+ $(SUBREF searching, balancedParens)
23+ $(SUBREF searching, boyerMooreFinder)
24+ $(SUBREF searching, canFind)
25+ $(SUBREF searching, commonPrefix)
26+ $(SUBREF searching, count)
27+ $(SUBREF searching, countUntil)
28+ $(SUBREF searching, endsWith)
29+ $(SUBREF searching, find)
30+ $(SUBREF searching, findAdjacent)
31+ $(SUBREF searching, findAmong)
32+ $(SUBREF searching, findSkip)
33+ $(SUBREF searching, findSplit)
34+ $(SUBREF searching, findSplitAfter)
35+ $(SUBREF searching, findSplitBefore)
36+ $(SUBREF searching, minCount)
37+ $(SUBREF searching, maxCount)
38+ $(SUBREF searching, minElement)
39+ $(SUBREF searching, maxElement)
40+ $(SUBREF searching, minIndex)
41+ $(SUBREF searching, maxIndex)
42+ $(SUBREF searching, minPos)
43+ $(SUBREF searching, maxPos)
44+ $(SUBREF searching, skipOver)
45+ $(SUBREF searching, startsWith)
46+ $(SUBREF searching, until)
47+ )
48+)
49+$(TR
50+ $(TDNW $(SUBMODULE Comparison, comparison))
51+ $(TD
52+ $(SUBREF comparison, among)
53+ $(SUBREF comparison, castSwitch)
54+ $(SUBREF comparison, clamp)
55+ $(SUBREF comparison, cmp)
56+ $(SUBREF comparison, either)
57+ $(SUBREF comparison, equal)
58+ $(SUBREF comparison, isPermutation)
59+ $(SUBREF comparison, isSameLength)
60+ $(SUBREF comparison, levenshteinDistance)
61+ $(SUBREF comparison, levenshteinDistanceAndPath)
62+ $(SUBREF comparison, max)
63+ $(SUBREF comparison, min)
64+ $(SUBREF comparison, mismatch)
65+ $(SUBREF comparison, predSwitch)
66+ )
67+)
68+$(TR
69+ $(TDNW $(SUBMODULE Iteration, iteration))
70+ $(TD
71+ $(SUBREF iteration, cache)
72+ $(SUBREF iteration, cacheBidirectional)
73+ $(SUBREF iteration, chunkBy)
74+ $(SUBREF iteration, cumulativeFold)
75+ $(SUBREF iteration, each)
76+ $(SUBREF iteration, filter)
77+ $(SUBREF iteration, filterBidirectional)
78+ $(SUBREF iteration, fold)
79+ $(SUBREF iteration, group)
80+ $(SUBREF iteration, joiner)
81+ $(SUBREF iteration, map)
82+ $(SUBREF iteration, permutations)
83+ $(SUBREF iteration, reduce)
84+ $(SUBREF iteration, splitter)
85+ $(SUBREF iteration, sum)
86+ $(SUBREF iteration, uniq)
87+ )
88+)
89+$(TR
90+ $(TDNW $(SUBMODULE Sorting, sorting))
91+ $(TD
92+ $(SUBREF sorting, completeSort)
93+ $(SUBREF sorting, isPartitioned)
94+ $(SUBREF sorting, isSorted)
95+ $(SUBREF sorting, isStrictlyMonotonic)
96+ $(SUBREF sorting, ordered)
97+ $(SUBREF sorting, strictlyOrdered)
98+ $(SUBREF sorting, makeIndex)
99+ $(SUBREF sorting, merge)
100+ $(SUBREF sorting, multiSort)
101+ $(SUBREF sorting, nextEvenPermutation)
102+ $(SUBREF sorting, nextPermutation)
103+ $(SUBREF sorting, partialSort)
104+ $(SUBREF sorting, partition)
105+ $(SUBREF sorting, partition3)
106+ $(SUBREF sorting, schwartzSort)
107+ $(SUBREF sorting, sort)
108+ $(SUBREF sorting, topN)
109+ $(SUBREF sorting, topNCopy)
110+ $(SUBREF sorting, topNIndex)
111+ )
112+)
113+$(TR
114+ $(TDNW Set operations $(BR)($(SUBMODULE setops, setops)))
115+ $(TD
116+ $(SUBREF setops, cartesianProduct)
117+ $(SUBREF setops, largestPartialIntersection)
118+ $(SUBREF setops, largestPartialIntersectionWeighted)
119+ $(SUBREF setops, multiwayMerge)
120+ $(SUBREF setops, multiwayUnion)
121+ $(SUBREF setops, setDifference)
122+ $(SUBREF setops, setIntersection)
123+ $(SUBREF setops, setSymmetricDifference)
124+ )
125+)
126+$(TR
127+ $(TDNW $(SUBMODULE Mutation, mutation))
128+ $(TD
129+ $(SUBREF mutation, bringToFront)
130+ $(SUBREF mutation, copy)
131+ $(SUBREF mutation, fill)
132+ $(SUBREF mutation, initializeAll)
133+ $(SUBREF mutation, move)
134+ $(SUBREF mutation, moveAll)
135+ $(SUBREF mutation, moveSome)
136+ $(SUBREF mutation, moveEmplace)
137+ $(SUBREF mutation, moveEmplaceAll)
138+ $(SUBREF mutation, moveEmplaceSome)
139+ $(SUBREF mutation, remove)
140+ $(SUBREF mutation, reverse)
141+ $(SUBREF mutation, strip)
142+ $(SUBREF mutation, stripLeft)
143+ $(SUBREF mutation, stripRight)
144+ $(SUBREF mutation, swap)
145+ $(SUBREF mutation, swapRanges)
146+ $(SUBREF mutation, uninitializedFill)
147+ )
148+)
149+))
150+
151+Many functions in this package are parameterized with a $(GLOSSARY predicate).
152+The predicate may be any suitable callable type
153+(a function, a delegate, a $(GLOSSARY functor), or a lambda), or a
154+compile-time string. The string may consist of $(B any) legal D
155+expression that uses the symbol $(D a) (for unary functions) or the
156+symbols $(D a) and $(D b) (for binary functions). These names will NOT
157+interfere with other homonym symbols in user code because they are
158+evaluated in a different context. The default for all binary
159+comparison predicates is $(D "a == b") for unordered operations and
160+$(D "a < b") for ordered operations.
161+
162+Example:
163+
164+----
165+int[] a = ...;
166+static bool greater(int a, int b)
167+{
168+ return a > b;
169+}
170+sort!greater(a); // predicate as alias
171+sort!((a, b) => a > b)(a); // predicate as a lambda.
172+sort!"a > b"(a); // predicate as string
173+ // (no ambiguity with array name)
174+sort(a); // no predicate, "a < b" is implicit
175+----
176+
177+Macros:
178+SUBMODULE = $(MREF_ALTTEXT $1, std, algorithm, $2)
179+SUBREF = $(REF_ALTTEXT $(TT $2), $2, std, algorithm, $1)$(NBSP)
180+
181+Copyright: Andrei Alexandrescu 2008-.
182+
183+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
184+
185+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
186+
187+Source: $(PHOBOSSRC std/_algorithm/package.d)
188+ */
189+module std.algorithm;
190+
191+public import std.algorithm.comparison;
192+public import std.algorithm.iteration;
193+public import std.algorithm.mutation;
194+public import std.algorithm.searching;
195+public import std.algorithm.setops;
196+public import std.algorithm.sorting;
197+
198+static import std.functional;
gcc/libphobos/src/std/algorithm/searching.d+4600−0
@@ -0,0 +1,4600 @@
1+// Written in the D programming language.
2+/**
3+This is a submodule of $(MREF std, algorithm).
4+It contains generic _searching algorithms.
5+
6+$(SCRIPT inhibitQuickIndex = 1;)
7+$(BOOKTABLE Cheat Sheet,
8+$(TR $(TH Function Name) $(TH Description))
9+$(T2 all,
10+ $(D all!"a > 0"([1, 2, 3, 4])) returns $(D true) because all elements
11+ are positive)
12+$(T2 any,
13+ $(D any!"a > 0"([1, 2, -3, -4])) returns $(D true) because at least one
14+ element is positive)
15+$(T2 balancedParens,
16+ $(D balancedParens("((1 + 1) / 2)")) returns $(D true) because the
17+ string has balanced parentheses.)
18+$(T2 boyerMooreFinder,
19+ $(D find("hello world", boyerMooreFinder("or"))) returns $(D "orld")
20+ using the $(LINK2 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm,
21+ Boyer-Moore _algorithm).)
22+$(T2 canFind,
23+ $(D canFind("hello world", "or")) returns $(D true).)
24+$(T2 count,
25+ Counts elements that are equal to a specified value or satisfy a
26+ predicate. $(D count([1, 2, 1], 1)) returns $(D 2) and
27+ $(D count!"a < 0"([1, -3, 0])) returns $(D 1).)
28+$(T2 countUntil,
29+ $(D countUntil(a, b)) returns the number of steps taken in $(D a) to
30+ reach $(D b); for example, $(D countUntil("hello!", "o")) returns
31+ $(D 4).)
32+$(T2 commonPrefix,
33+ $(D commonPrefix("parakeet", "parachute")) returns $(D "para").)
34+$(T2 endsWith,
35+ $(D endsWith("rocks", "ks")) returns $(D true).)
36+$(T2 find,
37+ $(D find("hello world", "or")) returns $(D "orld") using linear search.
38+ (For binary search refer to $(REF sortedRange, std,range).))
39+$(T2 findAdjacent,
40+ $(D findAdjacent([1, 2, 3, 3, 4])) returns the subrange starting with
41+ two equal adjacent elements, i.e. $(D [3, 3, 4]).)
42+$(T2 findAmong,
43+ $(D findAmong("abcd", "qcx")) returns $(D "cd") because $(D 'c') is
44+ among $(D "qcx").)
45+$(T2 findSkip,
46+ If $(D a = "abcde"), then $(D findSkip(a, "x")) returns $(D false) and
47+ leaves $(D a) unchanged, whereas $(D findSkip(a, "c")) advances $(D a)
48+ to $(D "de") and returns $(D true).)
49+$(T2 findSplit,
50+ $(D findSplit("abcdefg", "de")) returns the three ranges $(D "abc"),
51+ $(D "de"), and $(D "fg").)
52+$(T2 findSplitAfter,
53+ $(D findSplitAfter("abcdefg", "de")) returns the two ranges
54+ $(D "abcde") and $(D "fg").)
55+$(T2 findSplitBefore,
56+ $(D findSplitBefore("abcdefg", "de")) returns the two ranges $(D "abc")
57+ and $(D "defg").)
58+$(T2 minCount,
59+ $(D minCount([2, 1, 1, 4, 1])) returns $(D tuple(1, 3)).)
60+$(T2 maxCount,
61+ $(D maxCount([2, 4, 1, 4, 1])) returns $(D tuple(4, 2)).)
62+$(T2 minElement,
63+ Selects the minimal element of a range.
64+ `minElement([3, 4, 1, 2])` returns `1`.)
65+$(T2 maxElement,
66+ Selects the maximal element of a range.
67+ `maxElement([3, 4, 1, 2])` returns `4`.)
68+$(T2 minIndex,
69+ Index of the minimal element of a range.
70+ `minElement([3, 4, 1, 2])` returns `2`.)
71+$(T2 maxIndex,
72+ Index of the maximal element of a range.
73+ `maxElement([3, 4, 1, 2])` returns `1`.)
74+$(T2 minPos,
75+ $(D minPos([2, 3, 1, 3, 4, 1])) returns the subrange $(D [1, 3, 4, 1]),
76+ i.e., positions the range at the first occurrence of its minimal
77+ element.)
78+$(T2 maxPos,
79+ $(D maxPos([2, 3, 1, 3, 4, 1])) returns the subrange $(D [4, 1]),
80+ i.e., positions the range at the first occurrence of its maximal
81+ element.)
82+$(T2 mismatch,
83+ $(D mismatch("parakeet", "parachute")) returns the two ranges
84+ $(D "keet") and $(D "chute").)
85+$(T2 skipOver,
86+ Assume $(D a = "blah"). Then $(D skipOver(a, "bi")) leaves $(D a)
87+ unchanged and returns $(D false), whereas $(D skipOver(a, "bl"))
88+ advances $(D a) to refer to $(D "ah") and returns $(D true).)
89+$(T2 startsWith,
90+ $(D startsWith("hello, world", "hello")) returns $(D true).)
91+$(T2 until,
92+ Lazily iterates a range until a specific value is found.)
93+)
94+
95+Copyright: Andrei Alexandrescu 2008-.
96+
97+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
98+
99+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
100+
101+Source: $(PHOBOSSRC std/algorithm/_searching.d)
102+
103+Macros:
104+T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
105+ */
106+module std.algorithm.searching;
107+
108+// FIXME
109+import std.functional; // : unaryFun, binaryFun;
110+import std.range.primitives;
111+import std.traits;
112+// FIXME
113+import std.typecons; // : Tuple, Flag, Yes, No;
114+
115+/++
116+Checks if $(I _all) of the elements verify $(D pred).
117+ +/
118+template all(alias pred = "a")
119+{
120+ /++
121+ Returns $(D true) if and only if $(I _all) values $(D v) found in the
122+ input _range $(D range) satisfy the predicate $(D pred).
123+ Performs (at most) $(BIGOH range.length) evaluations of $(D pred).
124+ +/
125+ bool all(Range)(Range range)
126+ if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))))
127+ {
128+ import std.functional : not;
129+
130+ return find!(not!(unaryFun!pred))(range).empty;
131+ }
132+}
133+
134+///
135+@safe unittest
136+{
137+ assert( all!"a & 1"([1, 3, 5, 7, 9]));
138+ assert(!all!"a & 1"([1, 2, 3, 5, 7, 9]));
139+}
140+
141+/++
142+$(D all) can also be used without a predicate, if its items can be
143+evaluated to true or false in a conditional statement. This can be a
144+convenient way to quickly evaluate that $(I _all) of the elements of a range
145+are true.
146+ +/
147+@safe unittest
148+{
149+ int[3] vals = [5, 3, 18];
150+ assert( all(vals[]));
151+}
152+
153+@safe unittest
154+{
155+ int x = 1;
156+ assert(all!(a => a > x)([2, 3]));
157+}
158+
159+/++
160+Checks if $(I _any) of the elements verifies $(D pred).
161+$(D !any) can be used to verify that $(I none) of the elements verify
162+$(D pred).
163+This is sometimes called `exists` in other languages.
164+ +/
165+template any(alias pred = "a")
166+{
167+ /++
168+ Returns $(D true) if and only if $(I _any) value $(D v) found in the
169+ input _range $(D range) satisfies the predicate $(D pred).
170+ Performs (at most) $(BIGOH range.length) evaluations of $(D pred).
171+ +/
172+ bool any(Range)(Range range)
173+ if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))))
174+ {
175+ return !find!pred(range).empty;
176+ }
177+}
178+
179+///
180+@safe unittest
181+{
182+ import std.ascii : isWhite;
183+ assert( all!(any!isWhite)(["a a", "b b"]));
184+ assert(!any!(all!isWhite)(["a a", "b b"]));
185+}
186+
187+/++
188+$(D any) can also be used without a predicate, if its items can be
189+evaluated to true or false in a conditional statement. $(D !any) can be a
190+convenient way to quickly test that $(I none) of the elements of a range
191+evaluate to true.
192+ +/
193+@safe unittest
194+{
195+ int[3] vals1 = [0, 0, 0];
196+ assert(!any(vals1[])); //none of vals1 evaluate to true
197+
198+ int[3] vals2 = [2, 0, 2];
199+ assert( any(vals2[]));
200+ assert(!all(vals2[]));
201+
202+ int[3] vals3 = [3, 3, 3];
203+ assert( any(vals3[]));
204+ assert( all(vals3[]));
205+}
206+
207+@safe unittest
208+{
209+ auto a = [ 1, 2, 0, 4 ];
210+ assert(any!"a == 2"(a));
211+}
212+
213+// balancedParens
214+/**
215+Checks whether $(D r) has "balanced parentheses", i.e. all instances
216+of $(D lPar) are closed by corresponding instances of $(D rPar). The
217+parameter $(D maxNestingLevel) controls the nesting level allowed. The
218+most common uses are the default or $(D 0). In the latter case, no
219+nesting is allowed.
220+
221+Params:
222+ r = The range to check.
223+ lPar = The element corresponding with a left (opening) parenthesis.
224+ rPar = The element corresponding with a right (closing) parenthesis.
225+ maxNestingLevel = The maximum allowed nesting level.
226+
227+Returns:
228+ true if the given range has balanced parenthesis within the given maximum
229+ nesting level; false otherwise.
230+*/
231+bool balancedParens(Range, E)(Range r, E lPar, E rPar,
232+ size_t maxNestingLevel = size_t.max)
233+if (isInputRange!(Range) && is(typeof(r.front == lPar)))
234+{
235+ size_t count;
236+ for (; !r.empty; r.popFront())
237+ {
238+ if (r.front == lPar)
239+ {
240+ if (count > maxNestingLevel) return false;
241+ ++count;
242+ }
243+ else if (r.front == rPar)
244+ {
245+ if (!count) return false;
246+ --count;
247+ }
248+ }
249+ return count == 0;
250+}
251+
252+///
253+@safe unittest
254+{
255+ auto s = "1 + (2 * (3 + 1 / 2)";
256+ assert(!balancedParens(s, '(', ')'));
257+ s = "1 + (2 * (3 + 1) / 2)";
258+ assert(balancedParens(s, '(', ')'));
259+ s = "1 + (2 * (3 + 1) / 2)";
260+ assert(!balancedParens(s, '(', ')', 0));
261+ s = "1 + (2 * 3 + 1) / (2 - 5)";
262+ assert(balancedParens(s, '(', ')', 0));
263+}
264+
265+/**
266+ * Sets up Boyer-Moore matching for use with $(D find) below.
267+ * By default, elements are compared for equality.
268+ *
269+ * $(D BoyerMooreFinder) allocates GC memory.
270+ *
271+ * Params:
272+ * pred = Predicate used to compare elements.
273+ * needle = A random-access range with length and slicing.
274+ *
275+ * Returns:
276+ * An instance of $(D BoyerMooreFinder) that can be used with $(D find()) to
277+ * invoke the Boyer-Moore matching algorithm for finding of $(D needle) in a
278+ * given haystack.
279+ */
280+struct BoyerMooreFinder(alias pred, Range)
281+{
282+private:
283+ size_t[] skip; // GC allocated
284+ ptrdiff_t[ElementType!(Range)] occ; // GC allocated
285+ Range needle;
286+
287+ ptrdiff_t occurrence(ElementType!(Range) c)
288+ {
289+ auto p = c in occ;
290+ return p ? *p : -1;
291+ }
292+
293+/*
294+This helper function checks whether the last "portion" bytes of
295+"needle" (which is "nlen" bytes long) exist within the "needle" at
296+offset "offset" (counted from the end of the string), and whether the
297+character preceding "offset" is not a match. Notice that the range
298+being checked may reach beyond the beginning of the string. Such range
299+is ignored.
300+ */
301+ static bool needlematch(R)(R needle,
302+ size_t portion, size_t offset)
303+ {
304+ import std.algorithm.comparison : equal;
305+ ptrdiff_t virtual_begin = needle.length - offset - portion;
306+ ptrdiff_t ignore = 0;
307+ if (virtual_begin < 0)
308+ {
309+ ignore = -virtual_begin;
310+ virtual_begin = 0;
311+ }
312+ if (virtual_begin > 0
313+ && needle[virtual_begin - 1] == needle[$ - portion - 1])
314+ return 0;
315+
316+ immutable delta = portion - ignore;
317+ return equal(needle[needle.length - delta .. needle.length],
318+ needle[virtual_begin .. virtual_begin + delta]);
319+ }
320+
321+public:
322+ ///
323+ this(Range needle)
324+ {
325+ if (!needle.length) return;
326+ this.needle = needle;
327+ /* Populate table with the analysis of the needle */
328+ /* But ignoring the last letter */
329+ foreach (i, n ; needle[0 .. $ - 1])
330+ {
331+ this.occ[n] = i;
332+ }
333+ /* Preprocess #2: init skip[] */
334+ /* Note: This step could be made a lot faster.
335+ * A simple implementation is shown here. */
336+ this.skip = new size_t[needle.length];
337+ foreach (a; 0 .. needle.length)
338+ {
339+ size_t value = 0;
340+ while (value < needle.length
341+ && !needlematch(needle, a, value))
342+ {
343+ ++value;
344+ }
345+ this.skip[needle.length - a - 1] = value;
346+ }
347+ }
348+
349+ ///
350+ Range beFound(Range haystack)
351+ {
352+ import std.algorithm.comparison : max;
353+
354+ if (!needle.length) return haystack;
355+ if (needle.length > haystack.length) return haystack[$ .. $];
356+ /* Search: */
357+ immutable limit = haystack.length - needle.length;
358+ for (size_t hpos = 0; hpos <= limit; )
359+ {
360+ size_t npos = needle.length - 1;
361+ while (pred(needle[npos], haystack[npos+hpos]))
362+ {
363+ if (npos == 0) return haystack[hpos .. $];
364+ --npos;
365+ }
366+ hpos += max(skip[npos], cast(sizediff_t) npos - occurrence(haystack[npos+hpos]));
367+ }
368+ return haystack[$ .. $];
369+ }
370+
371+ ///
372+ @property size_t length()
373+ {
374+ return needle.length;
375+ }
376+
377+ ///
378+ alias opDollar = length;
379+}
380+
381+/// Ditto
382+BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder
383+(alias pred = "a == b", Range)
384+(Range needle)
385+if ((isRandomAccessRange!(Range) && hasSlicing!Range) || isSomeString!Range)
386+{
387+ return typeof(return)(needle);
388+}
389+
390+///
391+@safe pure nothrow unittest
392+{
393+ auto bmFinder = boyerMooreFinder("TG");
394+
395+ string r = "TAGTGCCTGA";
396+ // search for the first match in the haystack r
397+ r = bmFinder.beFound(r);
398+ assert(r == "TGCCTGA");
399+
400+ // continue search in haystack
401+ r = bmFinder.beFound(r[2 .. $]);
402+ assert(r == "TGA");
403+}
404+
405+/**
406+Returns the common prefix of two ranges.
407+
408+Params:
409+ pred = The predicate to use in comparing elements for commonality. Defaults
410+ to equality $(D "a == b").
411+
412+ r1 = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) of
413+ elements.
414+
415+ r2 = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of
416+ elements.
417+
418+Returns:
419+A slice of $(D r1) which contains the characters that both ranges start with,
420+if the first argument is a string; otherwise, the same as the result of
421+$(D takeExactly(r1, n)), where $(D n) is the number of elements in the common
422+prefix of both ranges.
423+
424+See_Also:
425+ $(REF takeExactly, std,range)
426+ */
427+auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2)
428+if (isForwardRange!R1 && isInputRange!R2 &&
429+ !isNarrowString!R1 &&
430+ is(typeof(binaryFun!pred(r1.front, r2.front))))
431+{
432+ import std.algorithm.comparison : min;
433+ static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 &&
434+ hasLength!R1 && hasLength!R2 &&
435+ hasSlicing!R1)
436+ {
437+ immutable limit = min(r1.length, r2.length);
438+ foreach (i; 0 .. limit)
439+ {
440+ if (!binaryFun!pred(r1[i], r2[i]))
441+ {
442+ return r1[0 .. i];
443+ }
444+ }
445+ return r1[0 .. limit];
446+ }
447+ else
448+ {
449+ import std.range : takeExactly;
450+ auto result = r1.save;
451+ size_t i = 0;
452+ for (;
453+ !r1.empty && !r2.empty && binaryFun!pred(r1.front, r2.front);
454+ ++i, r1.popFront(), r2.popFront())
455+ {}
456+ return takeExactly(result, i);
457+ }
458+}
459+
460+///
461+@safe unittest
462+{
463+ assert(commonPrefix("hello, world", "hello, there") == "hello, ");
464+}
465+
466+/// ditto
467+auto commonPrefix(alias pred, R1, R2)(R1 r1, R2 r2)
468+if (isNarrowString!R1 && isInputRange!R2 &&
469+ is(typeof(binaryFun!pred(r1.front, r2.front))))
470+{
471+ import std.utf : decode;
472+
473+ auto result = r1.save;
474+ immutable len = r1.length;
475+ size_t i = 0;
476+
477+ for (size_t j = 0; i < len && !r2.empty; r2.popFront(), i = j)
478+ {
479+ immutable f = decode(r1, j);
480+ if (!binaryFun!pred(f, r2.front))
481+ break;
482+ }
483+
484+ return result[0 .. i];
485+}
486+
487+/// ditto
488+auto commonPrefix(R1, R2)(R1 r1, R2 r2)
489+if (isNarrowString!R1 && isInputRange!R2 && !isNarrowString!R2 &&
490+ is(typeof(r1.front == r2.front)))
491+{
492+ return commonPrefix!"a == b"(r1, r2);
493+}
494+
495+/// ditto
496+auto commonPrefix(R1, R2)(R1 r1, R2 r2)
497+if (isNarrowString!R1 && isNarrowString!R2)
498+{
499+ import std.algorithm.comparison : min;
500+
501+ static if (ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof)
502+ {
503+ import std.utf : stride, UTFException;
504+
505+ immutable limit = min(r1.length, r2.length);
506+ for (size_t i = 0; i < limit;)
507+ {
508+ immutable codeLen = stride(r1, i);
509+ size_t j = 0;
510+
511+ for (; j < codeLen && i < limit; ++i, ++j)
512+ {
513+ if (r1[i] != r2[i])
514+ return r1[0 .. i - j];
515+ }
516+
517+ if (i == limit && j < codeLen)
518+ throw new UTFException("Invalid UTF-8 sequence", i);
519+ }
520+ return r1[0 .. limit];
521+ }
522+ else
523+ return commonPrefix!"a == b"(r1, r2);
524+}
525+
526+@safe unittest
527+{
528+ import std.algorithm.comparison : equal;
529+ import std.algorithm.iteration : filter;
530+ import std.conv : to;
531+ import std.exception : assertThrown;
532+ import std.meta : AliasSeq;
533+ import std.range;
534+ import std.utf : UTFException;
535+
536+ assert(commonPrefix([1, 2, 3], [1, 2, 3, 4, 5]) == [1, 2, 3]);
537+ assert(commonPrefix([1, 2, 3, 4, 5], [1, 2, 3]) == [1, 2, 3]);
538+ assert(commonPrefix([1, 2, 3, 4], [1, 2, 3, 4]) == [1, 2, 3, 4]);
539+ assert(commonPrefix([1, 2, 3], [7, 2, 3, 4, 5]).empty);
540+ assert(commonPrefix([7, 2, 3, 4, 5], [1, 2, 3]).empty);
541+ assert(commonPrefix([1, 2, 3], cast(int[]) null).empty);
542+ assert(commonPrefix(cast(int[]) null, [1, 2, 3]).empty);
543+ assert(commonPrefix(cast(int[]) null, cast(int[]) null).empty);
544+
545+ foreach (S; AliasSeq!(char[], const(char)[], string,
546+ wchar[], const(wchar)[], wstring,
547+ dchar[], const(dchar)[], dstring))
548+ {
549+ foreach (T; AliasSeq!(string, wstring, dstring))
550+ (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
551+ assert(commonPrefix(to!S(""), to!T("")).empty);
552+ assert(commonPrefix(to!S(""), to!T("hello")).empty);
553+ assert(commonPrefix(to!S("hello"), to!T("")).empty);
554+ assert(commonPrefix(to!S("hello, world"), to!T("hello, there")) == to!S("hello, "));
555+ assert(commonPrefix(to!S("hello, there"), to!T("hello, world")) == to!S("hello, "));
556+ assert(commonPrefix(to!S("hello, "), to!T("hello, world")) == to!S("hello, "));
557+ assert(commonPrefix(to!S("hello, world"), to!T("hello, ")) == to!S("hello, "));
558+ assert(commonPrefix(to!S("hello, world"), to!T("hello, world")) == to!S("hello, world"));
559+
560+ //Bug# 8890
561+ assert(commonPrefix(to!S("Пиво"), to!T("Пони"))== to!S("П"));
562+ assert(commonPrefix(to!S("Пони"), to!T("Пиво"))== to!S("П"));
563+ assert(commonPrefix(to!S("Пиво"), to!T("Пиво"))== to!S("Пиво"));
564+ assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFE"),
565+ to!T("\U0010FFFF\U0010FFFB\U0010FFFC")) == to!S("\U0010FFFF\U0010FFFB"));
566+ assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFC"),
567+ to!T("\U0010FFFF\U0010FFFB\U0010FFFE")) == to!S("\U0010FFFF\U0010FFFB"));
568+ assert(commonPrefix!"a != b"(to!S("Пиво"), to!T("онво")) == to!S("Пи"));
569+ assert(commonPrefix!"a != b"(to!S("онво"), to!T("Пиво")) == to!S("он"));
570+ }();
571+
572+ static assert(is(typeof(commonPrefix(to!S("Пиво"), filter!"true"("Пони"))) == S));
573+ assert(equal(commonPrefix(to!S("Пиво"), filter!"true"("Пони")), to!S("П")));
574+
575+ static assert(is(typeof(commonPrefix(filter!"true"("Пиво"), to!S("Пони"))) ==
576+ typeof(takeExactly(filter!"true"("П"), 1))));
577+ assert(equal(commonPrefix(filter!"true"("Пиво"), to!S("Пони")), takeExactly(filter!"true"("П"), 1)));
578+ }
579+
580+ assertThrown!UTFException(commonPrefix("\U0010FFFF\U0010FFFB", "\U0010FFFF\U0010FFFB"[0 .. $ - 1]));
581+
582+ assert(commonPrefix("12345"d, [49, 50, 51, 60, 60]) == "123"d);
583+ assert(commonPrefix([49, 50, 51, 60, 60], "12345" ) == [49, 50, 51]);
584+ assert(commonPrefix([49, 50, 51, 60, 60], "12345"d) == [49, 50, 51]);
585+
586+ assert(commonPrefix!"a == ('0' + b)"("12345" , [1, 2, 3, 9, 9]) == "123");
587+ assert(commonPrefix!"a == ('0' + b)"("12345"d, [1, 2, 3, 9, 9]) == "123"d);
588+ assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345" ) == [1, 2, 3]);
589+ assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345"d) == [1, 2, 3]);
590+}
591+
592+// count
593+/**
594+The first version counts the number of elements $(D x) in $(D r) for
595+which $(D pred(x, value)) is $(D true). $(D pred) defaults to
596+equality. Performs $(BIGOH haystack.length) evaluations of $(D pred).
597+
598+The second version returns the number of times $(D needle) occurs in
599+$(D haystack). Throws an exception if $(D needle.empty), as the _count
600+of the empty range in any range would be infinite. Overlapped counts
601+are not considered, for example $(D count("aaa", "aa")) is $(D 1), not
602+$(D 2).
603+
604+The third version counts the elements for which $(D pred(x)) is $(D
605+true). Performs $(BIGOH haystack.length) evaluations of $(D pred).
606+
607+The fourth version counts the number of elements in a range. It is
608+an optimization for the third version: if the given range has the
609+`length` property the count is returned right away, otherwise
610+performs $(BIGOH haystack.length) to walk the range.
611+
612+Note: Regardless of the overload, $(D count) will not accept
613+infinite ranges for $(D haystack).
614+
615+Params:
616+ pred = The predicate to evaluate.
617+ haystack = The range to _count.
618+ needle = The element or sub-range to _count in the `haystack`.
619+
620+Returns:
621+ The number of positions in the `haystack` for which `pred` returned true.
622+*/
623+size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle)
624+if (isInputRange!Range && !isInfinite!Range &&
625+ is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
626+{
627+ bool pred2(ElementType!Range a) { return binaryFun!pred(a, needle); }
628+ return count!pred2(haystack);
629+}
630+
631+///
632+@safe unittest
633+{
634+ import std.uni : toLower;
635+
636+ // count elements in range
637+ int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
638+ assert(count(a) == 9);
639+ assert(count(a, 2) == 3);
640+ assert(count!("a > b")(a, 2) == 5);
641+ // count range in range
642+ assert(count("abcadfabf", "ab") == 2);
643+ assert(count("ababab", "abab") == 1);
644+ assert(count("ababab", "abx") == 0);
645+ // fuzzy count range in range
646+ assert(count!((a, b) => toLower(a) == toLower(b))("AbcAdFaBf", "ab") == 2);
647+ // count predicate in range
648+ assert(count!("a > 1")(a) == 8);
649+}
650+
651+@safe unittest
652+{
653+ import std.conv : text;
654+
655+ int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
656+ assert(count(a, 2) == 3, text(count(a, 2)));
657+ assert(count!("a > b")(a, 2) == 5, text(count!("a > b")(a, 2)));
658+
659+ // check strings
660+ assert(count("日本語") == 3);
661+ assert(count("日本語"w) == 3);
662+ assert(count("日本語"d) == 3);
663+
664+ assert(count!("a == '日'")("日本語") == 1);
665+ assert(count!("a == '本'")("日本語"w) == 1);
666+ assert(count!("a == '語'")("日本語"d) == 1);
667+}
668+
669+@safe unittest
670+{
671+ string s = "This is a fofofof list";
672+ string sub = "fof";
673+ assert(count(s, sub) == 2);
674+}
675+
676+/// Ditto
677+size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
678+if (isForwardRange!R1 && !isInfinite!R1 &&
679+ isForwardRange!R2 &&
680+ is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool))
681+{
682+ assert(!needle.empty, "Cannot count occurrences of an empty range");
683+
684+ static if (isInfinite!R2)
685+ {
686+ //Note: This is the special case of looking for an infinite inside a finite...
687+ //"How many instances of the Fibonacci sequence can you count in [1, 2, 3]?" - "None."
688+ return 0;
689+ }
690+ else
691+ {
692+ size_t result;
693+ //Note: haystack is not saved, because findskip is designed to modify it
694+ for ( ; findSkip!pred(haystack, needle.save) ; ++result)
695+ {}
696+ return result;
697+ }
698+}
699+
700+/// Ditto
701+size_t count(alias pred, R)(R haystack)
702+if (isInputRange!R && !isInfinite!R &&
703+ is(typeof(unaryFun!pred(haystack.front)) : bool))
704+{
705+ size_t result;
706+ alias T = ElementType!R; //For narrow strings forces dchar iteration
707+ foreach (T elem; haystack)
708+ if (unaryFun!pred(elem)) ++result;
709+ return result;
710+}
711+
712+/// Ditto
713+size_t count(R)(R haystack)
714+if (isInputRange!R && !isInfinite!R)
715+{
716+ return walkLength(haystack);
717+}
718+
719+@safe unittest
720+{
721+ int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
722+ assert(count!("a == 3")(a) == 2);
723+ assert(count("日本語") == 3);
724+}
725+
726+// Issue 11253
727+@safe nothrow unittest
728+{
729+ assert([1, 2, 3].count([2, 3]) == 1);
730+}
731+
732+/++
733+ Counts elements in the given
734+ $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
735+ until the given predicate is true for one of the given $(D needles).
736+
737+ Params:
738+ pred = The predicate for determining when to stop counting.
739+ haystack = The
740+ $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be
741+ counted.
742+ needles = Either a single element, or a
743+ $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
744+ of elements, to be evaluated in turn against each
745+ element in $(D haystack) under the given predicate.
746+
747+ Returns: The number of elements which must be popped from the front of
748+ $(D haystack) before reaching an element for which
749+ $(D startsWith!pred(haystack, needles)) is $(D true). If
750+ $(D startsWith!pred(haystack, needles)) is not $(D true) for any element in
751+ $(D haystack), then $(D -1) is returned.
752+
753+ See_Also: $(REF indexOf, std,string)
754+ +/
755+ptrdiff_t countUntil(alias pred = "a == b", R, Rs...)(R haystack, Rs needles)
756+if (isForwardRange!R
757+ && Rs.length > 0
758+ && isForwardRange!(Rs[0]) == isInputRange!(Rs[0])
759+ && is(typeof(startsWith!pred(haystack, needles[0])))
760+ && (Rs.length == 1
761+ || is(typeof(countUntil!pred(haystack, needles[1 .. $])))))
762+{
763+ typeof(return) result;
764+
765+ static if (needles.length == 1)
766+ {
767+ static if (hasLength!R) //Note: Narrow strings don't have length.
768+ {
769+ //We delegate to find because find is very efficient.
770+ //We store the length of the haystack so we don't have to save it.
771+ auto len = haystack.length;
772+ auto r2 = find!pred(haystack, needles[0]);
773+ if (!r2.empty)
774+ return cast(typeof(return)) (len - r2.length);
775+ }
776+ else
777+ {
778+ import std.range : dropOne;
779+
780+ if (needles[0].empty)
781+ return 0;
782+
783+ //Default case, slower route doing startsWith iteration
784+ for ( ; !haystack.empty ; ++result )
785+ {
786+ //We compare the first elements of the ranges here before
787+ //forwarding to startsWith. This avoids making useless saves to
788+ //haystack/needle if they aren't even going to be mutated anyways.
789+ //It also cuts down on the amount of pops on haystack.
790+ if (binaryFun!pred(haystack.front, needles[0].front))
791+ {
792+ //Here, we need to save the needle before popping it.
793+ //haystack we pop in all paths, so we do that, and then save.
794+ haystack.popFront();
795+ if (startsWith!pred(haystack.save, needles[0].save.dropOne()))
796+ return result;
797+ }
798+ else
799+ haystack.popFront();
800+ }
801+ }
802+ }
803+ else
804+ {
805+ foreach (i, Ri; Rs)
806+ {
807+ static if (isForwardRange!Ri)
808+ {
809+ if (needles[i].empty)
810+ return 0;
811+ }
812+ }
813+ Tuple!Rs t;
814+ foreach (i, Ri; Rs)
815+ {
816+ static if (!isForwardRange!Ri)
817+ {
818+ t[i] = needles[i];
819+ }
820+ }
821+ for (; !haystack.empty ; ++result, haystack.popFront())
822+ {
823+ foreach (i, Ri; Rs)
824+ {
825+ static if (isForwardRange!Ri)
826+ {
827+ t[i] = needles[i].save;
828+ }
829+ }
830+ if (startsWith!pred(haystack.save, t.expand))
831+ {
832+ return result;
833+ }
834+ }
835+ }
836+
837+ //Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement"
838+ static if (isInfinite!R) assert(0);
839+ else return -1;
840+}
841+
842+/// ditto
843+ptrdiff_t countUntil(alias pred = "a == b", R, N)(R haystack, N needle)
844+if (isInputRange!R &&
845+ is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
846+{
847+ bool pred2(ElementType!R a) { return binaryFun!pred(a, needle); }
848+ return countUntil!pred2(haystack);
849+}
850+
851+///
852+@safe unittest
853+{
854+ assert(countUntil("hello world", "world") == 6);
855+ assert(countUntil("hello world", 'r') == 8);
856+ assert(countUntil("hello world", "programming") == -1);
857+ assert(countUntil("日本語", "本語") == 1);
858+ assert(countUntil("日本語", '語') == 2);
859+ assert(countUntil("日本語", "五") == -1);
860+ assert(countUntil("日本語", '五') == -1);
861+ assert(countUntil([0, 7, 12, 22, 9], [12, 22]) == 2);
862+ assert(countUntil([0, 7, 12, 22, 9], 9) == 4);
863+ assert(countUntil!"a > b"([0, 7, 12, 22, 9], 20) == 3);
864+}
865+
866+@safe unittest
867+{
868+ import std.algorithm.iteration : filter;
869+ import std.internal.test.dummyrange;
870+
871+ assert(countUntil("日本語", "") == 0);
872+ assert(countUntil("日本語"d, "") == 0);
873+
874+ assert(countUntil("", "") == 0);
875+ assert(countUntil("".filter!"true"(), "") == 0);
876+
877+ auto rf = [0, 20, 12, 22, 9].filter!"true"();
878+ assert(rf.countUntil!"a > b"((int[]).init) == 0);
879+ assert(rf.countUntil!"a > b"(20) == 3);
880+ assert(rf.countUntil!"a > b"([20, 8]) == 3);
881+ assert(rf.countUntil!"a > b"([20, 10]) == -1);
882+ assert(rf.countUntil!"a > b"([20, 8, 0]) == -1);
883+
884+ auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]);
885+ auto r2 = new ReferenceForwardRange!int([3, 4]);
886+ auto r3 = new ReferenceForwardRange!int([3, 5]);
887+ assert(r.save.countUntil(3) == 3);
888+ assert(r.save.countUntil(r2) == 3);
889+ assert(r.save.countUntil(7) == -1);
890+ assert(r.save.countUntil(r3) == -1);
891+}
892+
893+@safe unittest
894+{
895+ assert(countUntil("hello world", "world", "asd") == 6);
896+ assert(countUntil("hello world", "world", "ello") == 1);
897+ assert(countUntil("hello world", "world", "") == 0);
898+ assert(countUntil("hello world", "world", 'l') == 2);
899+}
900+
901+/++
902+ Similar to the previous overload of $(D countUntil), except that this one
903+ evaluates only the predicate $(D pred).
904+
905+ Params:
906+ pred = Predicate to when to stop counting.
907+ haystack = An
908+ $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of
909+ elements to be counted.
910+ Returns: The number of elements which must be popped from $(D haystack)
911+ before $(D pred(haystack.front)) is $(D true).
912+ +/
913+ptrdiff_t countUntil(alias pred, R)(R haystack)
914+if (isInputRange!R &&
915+ is(typeof(unaryFun!pred(haystack.front)) : bool))
916+{
917+ typeof(return) i;
918+ static if (isRandomAccessRange!R)
919+ {
920+ //Optimized RA implementation. Since we want to count *and* iterate at
921+ //the same time, it is more efficient this way.
922+ static if (hasLength!R)
923+ {
924+ immutable len = cast(typeof(return)) haystack.length;
925+ for ( ; i < len ; ++i )
926+ if (unaryFun!pred(haystack[i])) return i;
927+ }
928+ else //if (isInfinite!R)
929+ {
930+ for ( ; ; ++i )
931+ if (unaryFun!pred(haystack[i])) return i;
932+ }
933+ }
934+ else static if (hasLength!R)
935+ {
936+ //For those odd ranges that have a length, but aren't RA.
937+ //It is faster to quick find, and then compare the lengths
938+ auto r2 = find!pred(haystack.save);
939+ if (!r2.empty) return cast(typeof(return)) (haystack.length - r2.length);
940+ }
941+ else //Everything else
942+ {
943+ alias T = ElementType!R; //For narrow strings forces dchar iteration
944+ foreach (T elem; haystack)
945+ {
946+ if (unaryFun!pred(elem)) return i;
947+ ++i;
948+ }
949+ }
950+
951+ //Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement"
952+ static if (isInfinite!R) assert(0);
953+ else return -1;
954+}
955+
956+///
957+@safe unittest
958+{
959+ import std.ascii : isDigit;
960+ import std.uni : isWhite;
961+
962+ assert(countUntil!(std.uni.isWhite)("hello world") == 5);
963+ assert(countUntil!(std.ascii.isDigit)("hello world") == -1);
964+ assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3);
965+}
966+
967+@safe unittest
968+{
969+ import std.internal.test.dummyrange;
970+
971+ // References
972+ {
973+ // input
974+ ReferenceInputRange!int r;
975+ r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]);
976+ assert(r.countUntil(3) == 3);
977+ r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]);
978+ assert(r.countUntil(7) == -1);
979+ }
980+ {
981+ // forward
982+ auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]);
983+ assert(r.save.countUntil([3, 4]) == 3);
984+ assert(r.save.countUntil(3) == 3);
985+ assert(r.save.countUntil([3, 7]) == -1);
986+ assert(r.save.countUntil(7) == -1);
987+ }
988+ {
989+ // infinite forward
990+ auto r = new ReferenceInfiniteForwardRange!int(0);
991+ assert(r.save.countUntil([3, 4]) == 3);
992+ assert(r.save.countUntil(3) == 3);
993+ }
994+}
995+
996+/**
997+Checks if the given range ends with (one of) the given needle(s).
998+The reciprocal of $(D startsWith).
999+
1000+Params:
1001+ pred = The predicate to use for comparing elements between the range and
1002+ the needle(s).
1003+
1004+ doesThisEnd = The
1005+ $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
1006+ to check.
1007+
1008+ withOneOfThese = The needles to check against, which may be single
1009+ elements, or bidirectional ranges of elements.
1010+
1011+ withThis = The single element to check.
1012+
1013+Returns:
1014+0 if the needle(s) do not occur at the end of the given range;
1015+otherwise the position of the matching needle, that is, 1 if the range ends
1016+with $(D withOneOfThese[0]), 2 if it ends with $(D withOneOfThese[1]), and so
1017+on.
1018+
1019+In the case when no needle parameters are given, return $(D true) iff back of
1020+$(D doesThisStart) fulfils predicate $(D pred).
1021+*/
1022+uint endsWith(alias pred = "a == b", Range, Needles...)(Range doesThisEnd, Needles withOneOfThese)
1023+if (isBidirectionalRange!Range && Needles.length > 1 &&
1024+ is(typeof(.endsWith!pred(doesThisEnd, withOneOfThese[0])) : bool) &&
1025+ is(typeof(.endsWith!pred(doesThisEnd, withOneOfThese[1 .. $])) : uint))
1026+{
1027+ alias haystack = doesThisEnd;
1028+ alias needles = withOneOfThese;
1029+
1030+ // Make one pass looking for empty ranges in needles
1031+ foreach (i, Unused; Needles)
1032+ {
1033+ // Empty range matches everything
1034+ static if (!is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool))
1035+ {
1036+ if (needles[i].empty) return i + 1;
1037+ }
1038+ }
1039+
1040+ for (; !haystack.empty; haystack.popBack())
1041+ {
1042+ foreach (i, Unused; Needles)
1043+ {
1044+ static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool))
1045+ {
1046+ // Single-element
1047+ if (binaryFun!pred(haystack.back, needles[i]))
1048+ {
1049+ // found, but continue to account for one-element
1050+ // range matches (consider endsWith("ab", "b",
1051+ // 'b') should return 1, not 2).
1052+ continue;
1053+ }
1054+ }
1055+ else
1056+ {
1057+ if (binaryFun!pred(haystack.back, needles[i].back))
1058+ continue;
1059+ }
1060+
1061+ // This code executed on failure to match
1062+ // Out with this guy, check for the others
1063+ uint result = endsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]);
1064+ if (result > i) ++result;
1065+ return result;
1066+ }
1067+
1068+ // If execution reaches this point, then the back matches for all
1069+ // needles ranges. What we need to do now is to lop off the back of
1070+ // all ranges involved and recurse.
1071+ foreach (i, Unused; Needles)
1072+ {
1073+ static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool))
1074+ {
1075+ // Test has passed in the previous loop
1076+ return i + 1;
1077+ }
1078+ else
1079+ {
1080+ needles[i].popBack();
1081+ if (needles[i].empty) return i + 1;
1082+ }
1083+ }
1084+ }
1085+ return 0;
1086+}
1087+
1088+/// Ditto
1089+bool endsWith(alias pred = "a == b", R1, R2)(R1 doesThisEnd, R2 withThis)
1090+if (isBidirectionalRange!R1 &&
1091+ isBidirectionalRange!R2 &&
1092+ is(typeof(binaryFun!pred(doesThisEnd.back, withThis.back)) : bool))
1093+{
1094+ alias haystack = doesThisEnd;
1095+ alias needle = withThis;
1096+
1097+ static if (is(typeof(pred) : string))
1098+ enum isDefaultPred = pred == "a == b";
1099+ else
1100+ enum isDefaultPred = false;
1101+
1102+ static if (isDefaultPred && isArray!R1 && isArray!R2 &&
1103+ is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2)))
1104+ {
1105+ if (haystack.length < needle.length) return false;
1106+
1107+ return haystack[$ - needle.length .. $] == needle;
1108+ }
1109+ else
1110+ {
1111+ import std.range : retro;
1112+ return startsWith!pred(retro(doesThisEnd), retro(withThis));
1113+ }
1114+}
1115+
1116+/// Ditto
1117+bool endsWith(alias pred = "a == b", R, E)(R doesThisEnd, E withThis)
1118+if (isBidirectionalRange!R &&
1119+ is(typeof(binaryFun!pred(doesThisEnd.back, withThis)) : bool))
1120+{
1121+ if (doesThisEnd.empty)
1122+ return false;
1123+
1124+ alias predFunc = binaryFun!pred;
1125+
1126+ // auto-decoding special case
1127+ static if (isNarrowString!R)
1128+ {
1129+ // specialize for ASCII as to not change previous behavior
1130+ if (withThis <= 0x7F)
1131+ return predFunc(doesThisEnd[$ - 1], withThis);
1132+ else
1133+ return predFunc(doesThisEnd.back, withThis);
1134+ }
1135+ else
1136+ {
1137+ return predFunc(doesThisEnd.back, withThis);
1138+ }
1139+}
1140+
1141+/// Ditto
1142+bool endsWith(alias pred, R)(R doesThisEnd)
1143+if (isInputRange!R &&
1144+ ifTestable!(typeof(doesThisEnd.front), unaryFun!pred))
1145+{
1146+ return !doesThisEnd.empty && unaryFun!pred(doesThisEnd.back);
1147+}
1148+
1149+///
1150+@safe unittest
1151+{
1152+ import std.ascii : isAlpha;
1153+ assert("abc".endsWith!(a => a.isAlpha));
1154+ assert("abc".endsWith!isAlpha);
1155+
1156+ assert(!"ab1".endsWith!(a => a.isAlpha));
1157+
1158+ assert(!"ab1".endsWith!isAlpha);
1159+ assert(!"".endsWith!(a => a.isAlpha));
1160+
1161+ import std.algorithm.comparison : among;
1162+ assert("abc".endsWith!(a => a.among('c', 'd') != 0));
1163+ assert(!"abc".endsWith!(a => a.among('a', 'b') != 0));
1164+
1165+ assert(endsWith("abc", ""));
1166+ assert(!endsWith("abc", "b"));
1167+ assert(endsWith("abc", "a", 'c') == 2);
1168+ assert(endsWith("abc", "c", "a") == 1);
1169+ assert(endsWith("abc", "c", "c") == 1);
1170+ assert(endsWith("abc", "bc", "c") == 2);
1171+ assert(endsWith("abc", "x", "c", "b") == 2);
1172+ assert(endsWith("abc", "x", "aa", "bc") == 3);
1173+ assert(endsWith("abc", "x", "aaa", "sab") == 0);
1174+ assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3);
1175+}
1176+
1177+@safe unittest
1178+{
1179+ import std.algorithm.iteration : filterBidirectional;
1180+ import std.conv : to;
1181+ import std.meta : AliasSeq;
1182+
1183+ foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
1184+ {
1185+ assert(!endsWith(to!S("abc"), 'a'));
1186+ assert(endsWith(to!S("abc"), 'a', 'c') == 2);
1187+ assert(!endsWith(to!S("abc"), 'x', 'n', 'b'));
1188+ assert(endsWith(to!S("abc"), 'x', 'n', 'c') == 3);
1189+ assert(endsWith(to!S("abc\uFF28"), 'a', '\uFF28', 'c') == 2);
1190+
1191+ foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
1192+ (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
1193+ //Lots of strings
1194+ assert(endsWith(to!S("abc"), to!T("")));
1195+ assert(!endsWith(to!S("abc"), to!T("a")));
1196+ assert(!endsWith(to!S("abc"), to!T("b")));
1197+ assert(endsWith(to!S("abc"), to!T("bc"), 'c') == 2);
1198+ assert(endsWith(to!S("abc"), to!T("a"), "c") == 2);
1199+ assert(endsWith(to!S("abc"), to!T("c"), "a") == 1);
1200+ assert(endsWith(to!S("abc"), to!T("c"), "c") == 1);
1201+ assert(endsWith(to!S("abc"), to!T("x"), 'c', "b") == 2);
1202+ assert(endsWith(to!S("abc"), 'x', to!T("aa"), "bc") == 3);
1203+ assert(endsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0);
1204+ assert(endsWith(to!S("abc"), to!T("x"), "aaa", "c", "sab") == 3);
1205+ assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")));
1206+ assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2);
1207+
1208+ //Unicode
1209+ assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")));
1210+ assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2);
1211+ assert(endsWith(to!S("日本語"), to!T("本語")));
1212+ assert(endsWith(to!S("日本語"), to!T("日本語")));
1213+ assert(!endsWith(to!S("本語"), to!T("日本語")));
1214+
1215+ //Empty
1216+ assert(endsWith(to!S(""), T.init));
1217+ assert(!endsWith(to!S(""), 'a'));
1218+ assert(endsWith(to!S("a"), T.init));
1219+ assert(endsWith(to!S("a"), T.init, "") == 1);
1220+ assert(endsWith(to!S("a"), T.init, 'a') == 1);
1221+ assert(endsWith(to!S("a"), 'a', T.init) == 2);
1222+ }();
1223+ }
1224+
1225+ foreach (T; AliasSeq!(int, short))
1226+ {
1227+ immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
1228+
1229+ //RA range
1230+ assert(endsWith(arr, cast(int[]) null));
1231+ assert(!endsWith(arr, 0));
1232+ assert(!endsWith(arr, 4));
1233+ assert(endsWith(arr, 5));
1234+ assert(endsWith(arr, 0, 4, 5) == 3);
1235+ assert(endsWith(arr, [5]));
1236+ assert(endsWith(arr, [4, 5]));
1237+ assert(endsWith(arr, [4, 5], 7) == 1);
1238+ assert(!endsWith(arr, [2, 4, 5]));
1239+ assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2);
1240+
1241+ //Normal input range
1242+ assert(!endsWith(filterBidirectional!"true"(arr), 4));
1243+ assert(endsWith(filterBidirectional!"true"(arr), 5));
1244+ assert(endsWith(filterBidirectional!"true"(arr), [5]));
1245+ assert(endsWith(filterBidirectional!"true"(arr), [4, 5]));
1246+ assert(endsWith(filterBidirectional!"true"(arr), [4, 5], 7) == 1);
1247+ assert(!endsWith(filterBidirectional!"true"(arr), [2, 4, 5]));
1248+ assert(endsWith(filterBidirectional!"true"(arr), [2, 4, 5], [3, 4, 5]) == 2);
1249+ assert(endsWith(arr, filterBidirectional!"true"([4, 5])));
1250+ assert(endsWith(arr, filterBidirectional!"true"([4, 5]), 7) == 1);
1251+ assert(!endsWith(arr, filterBidirectional!"true"([2, 4, 5])));
1252+ assert(endsWith(arr, [2, 4, 5], filterBidirectional!"true"([3, 4, 5])) == 2);
1253+
1254+ //Non-default pred
1255+ assert(endsWith!("a%10 == b%10")(arr, [14, 15]));
1256+ assert(!endsWith!("a%10 == b%10")(arr, [15, 14]));
1257+ }
1258+}
1259+
1260+/**
1261+Iterates the passed range and selects the extreme element with `less`.
1262+If the extreme element occurs multiple time, the first occurrence will be
1263+returned.
1264+
1265+Params:
1266+ map = custom accessor for the comparison key
1267+ selector = custom mapping for the extrema selection
1268+ seed = custom seed to use as initial element
1269+ r = Range from which the extreme value will be selected
1270+
1271+Returns:
1272+ The extreme value according to `map` and `selector` of the passed-in values.
1273+*/
1274+private auto extremum(alias map, alias selector = "a < b", Range)(Range r)
1275+if (isInputRange!Range && !isInfinite!Range &&
1276+ is(typeof(unaryFun!map(ElementType!(Range).init))))
1277+in
1278+{
1279+ assert(!r.empty, "r is an empty range");
1280+}
1281+body
1282+{
1283+ alias Element = ElementType!Range;
1284+ Unqual!Element seed = r.front;
1285+ r.popFront();
1286+ return extremum!(map, selector)(r, seed);
1287+}
1288+
1289+private auto extremum(alias map, alias selector = "a < b", Range,
1290+ RangeElementType = ElementType!Range)
1291+ (Range r, RangeElementType seedElement)
1292+if (isInputRange!Range && !isInfinite!Range &&
1293+ !is(CommonType!(ElementType!Range, RangeElementType) == void) &&
1294+ is(typeof(unaryFun!map(ElementType!(Range).init))))
1295+{
1296+ alias mapFun = unaryFun!map;
1297+ alias selectorFun = binaryFun!selector;
1298+
1299+ alias Element = ElementType!Range;
1300+ alias CommonElement = CommonType!(Element, RangeElementType);
1301+ Unqual!CommonElement extremeElement = seedElement;
1302+
1303+ alias MapType = Unqual!(typeof(mapFun(CommonElement.init)));
1304+ MapType extremeElementMapped = mapFun(extremeElement);
1305+
1306+ // direct access via a random access range is faster
1307+ static if (isRandomAccessRange!Range)
1308+ {
1309+ foreach (const i; 0 .. r.length)
1310+ {
1311+ MapType mapElement = mapFun(r[i]);
1312+ if (selectorFun(mapElement, extremeElementMapped))
1313+ {
1314+ extremeElement = r[i];
1315+ extremeElementMapped = mapElement;
1316+ }
1317+ }
1318+ }
1319+ else
1320+ {
1321+ while (!r.empty)
1322+ {
1323+ MapType mapElement = mapFun(r.front);
1324+ if (selectorFun(mapElement, extremeElementMapped))
1325+ {
1326+ extremeElement = r.front;
1327+ extremeElementMapped = mapElement;
1328+ }
1329+ r.popFront();
1330+ }
1331+ }
1332+ return extremeElement;
1333+}
1334+
1335+private auto extremum(alias selector = "a < b", Range)(Range r)
1336+ if (isInputRange!Range && !isInfinite!Range &&
1337+ !is(typeof(unaryFun!selector(ElementType!(Range).init))))
1338+{
1339+ alias Element = ElementType!Range;
1340+ Unqual!Element seed = r.front;
1341+ r.popFront();
1342+ return extremum!selector(r, seed);
1343+}
1344+
1345+// if we only have one statement in the loop it can be optimized a lot better
1346+private auto extremum(alias selector = "a < b", Range,
1347+ RangeElementType = ElementType!Range)
1348+ (Range r, RangeElementType seedElement)
1349+ if (isInputRange!Range && !isInfinite!Range &&
1350+ !is(CommonType!(ElementType!Range, RangeElementType) == void) &&
1351+ !is(typeof(unaryFun!selector(ElementType!(Range).init))))
1352+{
1353+ alias Element = ElementType!Range;
1354+ alias CommonElement = CommonType!(Element, RangeElementType);
1355+ Unqual!CommonElement extremeElement = seedElement;
1356+ alias selectorFun = binaryFun!selector;
1357+
1358+ // direct access via a random access range is faster
1359+ static if (isRandomAccessRange!Range)
1360+ {
1361+ foreach (const i; 0 .. r.length)
1362+ {
1363+ if (selectorFun(r[i], extremeElement))
1364+ {
1365+ extremeElement = r[i];
1366+ }
1367+ }
1368+ }
1369+ else
1370+ {
1371+ while (!r.empty)
1372+ {
1373+ if (selectorFun(r.front, extremeElement))
1374+ {
1375+ extremeElement = r.front;
1376+ }
1377+ r.popFront();
1378+ }
1379+ }
1380+ return extremeElement;
1381+}
1382+
1383+@safe pure unittest
1384+{
1385+ // allows a custom map to select the extremum
1386+ assert([[0, 4], [1, 2]].extremum!"a[0]" == [0, 4]);
1387+ assert([[0, 4], [1, 2]].extremum!"a[1]" == [1, 2]);
1388+
1389+ // allows a custom selector for comparison
1390+ assert([[0, 4], [1, 2]].extremum!("a[0]", "a > b") == [1, 2]);
1391+ assert([[0, 4], [1, 2]].extremum!("a[1]", "a > b") == [0, 4]);
1392+
1393+ // use a custom comparator
1394+ import std.math : cmp;
1395+ assert([-2., 0, 5].extremum!cmp == 5.0);
1396+ assert([-2., 0, 2].extremum!`cmp(a, b) < 0` == -2.0);
1397+
1398+ // combine with map
1399+ import std.range : enumerate;
1400+ assert([-3., 0, 5].enumerate.extremum!(`a.value`, cmp) == tuple(2, 5.0));
1401+ assert([-2., 0, 2].enumerate.extremum!(`a.value`, `cmp(a, b) < 0`) == tuple(0, -2.0));
1402+
1403+ // seed with a custom value
1404+ int[] arr;
1405+ assert(arr.extremum(1) == 1);
1406+}
1407+
1408+@safe pure nothrow unittest
1409+{
1410+ // 2d seeds
1411+ int[][] arr2d;
1412+ assert(arr2d.extremum([1]) == [1]);
1413+
1414+ // allow seeds of different types (implicit casting)
1415+ assert(extremum([2, 3, 4], 1.5) == 1.5);
1416+}
1417+
1418+@safe pure unittest
1419+{
1420+ import std.range : enumerate, iota;
1421+
1422+ // forward ranges
1423+ assert(iota(1, 5).extremum() == 1);
1424+ assert(iota(2, 5).enumerate.extremum!"a.value" == tuple(0, 2));
1425+
1426+ // should work with const
1427+ const(int)[] immArr = [2, 1, 3];
1428+ assert(immArr.extremum == 1);
1429+
1430+ // should work with immutable
1431+ immutable(int)[] immArr2 = [2, 1, 3];
1432+ assert(immArr2.extremum == 1);
1433+
1434+ // with strings
1435+ assert(["b", "a", "c"].extremum == "a");
1436+
1437+ // with all dummy ranges
1438+ import std.internal.test.dummyrange;
1439+ foreach (DummyType; AllDummyRanges)
1440+ {
1441+ DummyType d;
1442+ assert(d.extremum == 1);
1443+ assert(d.extremum!(a => a) == 1);
1444+ assert(d.extremum!`a > b` == 10);
1445+ assert(d.extremum!(a => a, `a > b`) == 10);
1446+ }
1447+}
1448+
1449+@nogc @safe nothrow pure unittest
1450+{
1451+ static immutable arr = [7, 3, 4, 2, 1, 8];
1452+ assert(arr.extremum == 1);
1453+
1454+ static immutable arr2d = [[1, 9], [3, 1], [4, 2]];
1455+ assert(arr2d.extremum!"a[1]" == arr2d[1]);
1456+}
1457+
1458+// find
1459+/**
1460+Finds an individual element in an input range. Elements of $(D
1461+haystack) are compared with $(D needle) by using predicate $(D
1462+pred). Performs $(BIGOH walkLength(haystack)) evaluations of $(D
1463+pred).
1464+
1465+To _find the last occurrence of $(D needle) in $(D haystack), call $(D
1466+find(retro(haystack), needle)). See $(REF retro, std,range).
1467+
1468+Params:
1469+
1470+pred = The predicate for comparing each element with the needle, defaulting to
1471+$(D "a == b").
1472+The negated predicate $(D "a != b") can be used to search instead for the first
1473+element $(I not) matching the needle.
1474+
1475+haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1476+searched in.
1477+
1478+needle = The element searched for.
1479+
1480+Constraints:
1481+
1482+$(D isInputRange!InputRange && is(typeof(binaryFun!pred(haystack.front, needle)
1483+: bool)))
1484+
1485+Returns:
1486+
1487+$(D haystack) advanced such that the front element is the one searched for;
1488+that is, until $(D binaryFun!pred(haystack.front, needle)) is $(D true). If no
1489+such position exists, returns an empty $(D haystack).
1490+
1491+See_Also:
1492+ $(HTTP sgi.com/tech/stl/_find.html, STL's _find)
1493+ */
1494+InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)
1495+if (isInputRange!InputRange &&
1496+ is (typeof(binaryFun!pred(haystack.front, needle)) : bool))
1497+{
1498+ alias R = InputRange;
1499+ alias E = Element;
1500+ alias predFun = binaryFun!pred;
1501+ static if (is(typeof(pred == "a == b")))
1502+ enum isDefaultPred = pred == "a == b";
1503+ else
1504+ enum isDefaultPred = false;
1505+ enum isIntegralNeedle = isSomeChar!E || isIntegral!E || isBoolean!E;
1506+
1507+ alias EType = ElementType!R;
1508+
1509+ // If the haystack is a SortedRange we can use binary search to find the needle.
1510+ // Works only for the default find predicate and any SortedRange predicate.
1511+ // 8829 enhancement
1512+ import std.range : SortedRange;
1513+ static if (is(InputRange : SortedRange!TT, TT) && isDefaultPred)
1514+ {
1515+ auto lb = haystack.lowerBound(needle);
1516+ if (lb.length == haystack.length || haystack[lb.length] != needle)
1517+ return haystack[$ .. $];
1518+
1519+ return haystack[lb.length .. $];
1520+ }
1521+ else static if (isNarrowString!R)
1522+ {
1523+ alias EEType = ElementEncodingType!R;
1524+ alias UEEType = Unqual!EEType;
1525+
1526+ //These are two special cases which can search without decoding the UTF stream.
1527+ static if (isDefaultPred && isIntegralNeedle)
1528+ {
1529+ import std.utf : canSearchInCodeUnits;
1530+
1531+ //This special case deals with UTF8 search, when the needle
1532+ //is represented by a single code point.
1533+ //Note: "needle <= 0x7F" properly handles sign via unsigned promotion
1534+ static if (is(UEEType == char))
1535+ {
1536+ if (!__ctfe && canSearchInCodeUnits!char(needle))
1537+ {
1538+ static R trustedMemchr(ref R haystack, ref E needle) @trusted nothrow pure
1539+ {
1540+ import core.stdc.string : memchr;
1541+ auto ptr = memchr(haystack.ptr, needle, haystack.length);
1542+ return ptr ?
1543+ haystack[cast(char*) ptr - haystack.ptr .. $] :
1544+ haystack[$ .. $];
1545+ }
1546+ return trustedMemchr(haystack, needle);
1547+ }
1548+ }
1549+
1550+ //Ditto, but for UTF16
1551+ static if (is(UEEType == wchar))
1552+ {
1553+ if (canSearchInCodeUnits!wchar(needle))
1554+ {
1555+ foreach (i, ref EEType e; haystack)
1556+ {
1557+ if (e == needle)
1558+ return haystack[i .. $];
1559+ }
1560+ return haystack[$ .. $];
1561+ }
1562+ }
1563+ }
1564+
1565+ //Previous conditonal optimizations did not succeed. Fallback to
1566+ //unconditional implementations
1567+ static if (isDefaultPred)
1568+ {
1569+ import std.utf : encode;
1570+
1571+ //In case of default pred, it is faster to do string/string search.
1572+ UEEType[is(UEEType == char) ? 4 : 2] buf;
1573+
1574+ size_t len = encode(buf, needle);
1575+ return find(haystack, buf[0 .. len]);
1576+ }
1577+ else
1578+ {
1579+ import std.utf : decode;
1580+
1581+ //Explicit pred: we must test each character by the book.
1582+ //We choose a manual decoding approach, because it is faster than
1583+ //the built-in foreach, or doing a front/popFront for-loop.
1584+ immutable len = haystack.length;
1585+ size_t i = 0, next = 0;
1586+ while (next < len)
1587+ {
1588+ if (predFun(decode(haystack, next), needle))
1589+ return haystack[i .. $];
1590+ i = next;
1591+ }
1592+ return haystack[$ .. $];
1593+ }
1594+ }
1595+ else static if (isArray!R)
1596+ {
1597+ //10403 optimization
1598+ static if (isDefaultPred && isIntegral!EType && EType.sizeof == 1 && isIntegralNeedle)
1599+ {
1600+ import std.algorithm.comparison : max, min;
1601+
1602+ R findHelper(ref R haystack, ref E needle) @trusted nothrow pure
1603+ {
1604+ import core.stdc.string : memchr;
1605+
1606+ EType* ptr = null;
1607+ //Note: we use "min/max" to handle sign mismatch.
1608+ if (min(EType.min, needle) == EType.min &&
1609+ max(EType.max, needle) == EType.max)
1610+ {
1611+ ptr = cast(EType*) memchr(haystack.ptr, needle,
1612+ haystack.length);
1613+ }
1614+
1615+ return ptr ?
1616+ haystack[ptr - haystack.ptr .. $] :
1617+ haystack[$ .. $];
1618+ }
1619+
1620+ if (!__ctfe)
1621+ return findHelper(haystack, needle);
1622+ }
1623+
1624+ //Default implementation.
1625+ foreach (i, ref e; haystack)
1626+ if (predFun(e, needle))
1627+ return haystack[i .. $];
1628+ return haystack[$ .. $];
1629+ }
1630+ else
1631+ {
1632+ //Everything else. Walk.
1633+ for ( ; !haystack.empty; haystack.popFront() )
1634+ {
1635+ if (predFun(haystack.front, needle))
1636+ break;
1637+ }
1638+ return haystack;
1639+ }
1640+}
1641+
1642+///
1643+@safe unittest
1644+{
1645+ import std.algorithm.comparison : equal;
1646+ import std.container : SList;
1647+ import std.range;
1648+ import std.range.primitives : empty;
1649+
1650+ auto arr = assumeSorted!"a < b"([1, 2, 4, 4, 4, 4, 5, 6, 9]);
1651+ assert(find(arr, 4) == assumeSorted!"a < b"([4, 4, 4, 4, 5, 6, 9]));
1652+ assert(find(arr, 1) == arr);
1653+ assert(find(arr, 9) == assumeSorted!"a < b"([9]));
1654+ assert(find!"a > b"(arr, 4) == assumeSorted!"a < b"([5, 6, 9]));
1655+ assert(find!"a < b"(arr, 4) == arr);
1656+ assert(find(arr, 0).empty());
1657+ assert(find(arr, 10).empty());
1658+ assert(find(arr, 8).empty());
1659+
1660+ auto r = assumeSorted!"a > b"([10, 7, 3, 1, 0, 0]);
1661+ assert(find(r, 3) == assumeSorted!"a > b"([3, 1, 0, 0]));
1662+ assert(find!"a > b"(r, 8) == r);
1663+ assert(find!"a < b"(r, 5) == assumeSorted!"a > b"([3, 1, 0, 0]));
1664+
1665+ assert(find("hello, world", ',') == ", world");
1666+ assert(find([1, 2, 3, 5], 4) == []);
1667+ assert(equal(find(SList!int(1, 2, 3, 4, 5)[], 4), SList!int(4, 5)[]));
1668+ assert(find!"a > b"([1, 2, 3, 5], 2) == [3, 5]);
1669+
1670+ auto a = [ 1, 2, 3 ];
1671+ assert(find(a, 5).empty); // not found
1672+ assert(!find(a, 2).empty); // found
1673+
1674+ // Case-insensitive find of a string
1675+ string[] s = [ "Hello", "world", "!" ];
1676+ assert(!find!("toLower(a) == b")(s, "hello").empty);
1677+}
1678+
1679+@safe unittest
1680+{
1681+ import std.algorithm.comparison : equal;
1682+ import std.container : SList;
1683+
1684+ auto lst = SList!int(1, 2, 5, 7, 3);
1685+ assert(lst.front == 1);
1686+ auto r = find(lst[], 5);
1687+ assert(equal(r, SList!int(5, 7, 3)[]));
1688+ assert(find([1, 2, 3, 5], 4).empty);
1689+ assert(equal(find!"a > b"("hello", 'k'), "llo"));
1690+}
1691+
1692+@safe pure nothrow unittest
1693+{
1694+ assert(!find ([1, 2, 3], 2).empty);
1695+ assert(!find!((a,b)=>a == b)([1, 2, 3], 2).empty);
1696+ assert(!find ([1, 2, 3], 2).empty);
1697+ assert(!find!((a,b)=>a == b)([1, 2, 3], 2).empty);
1698+}
1699+
1700+@safe pure unittest
1701+{
1702+ import std.meta : AliasSeq;
1703+ foreach (R; AliasSeq!(string, wstring, dstring))
1704+ {
1705+ foreach (E; AliasSeq!(char, wchar, dchar))
1706+ {
1707+ assert(find ("hello world", 'w') == "world");
1708+ assert(find!((a,b)=>a == b)("hello world", 'w') == "world");
1709+ assert(find ("日c語", 'c') == "c語");
1710+ assert(find!((a,b)=>a == b)("日c語", 'c') == "c語");
1711+ assert(find ("0123456789", 'A').empty);
1712+ static if (E.sizeof >= 2)
1713+ {
1714+ assert(find ("日本語", '本') == "本語");
1715+ assert(find!((a,b)=>a == b)("日本語", '本') == "本語");
1716+ }
1717+ }
1718+ }
1719+}
1720+
1721+@safe unittest
1722+{
1723+ //CTFE
1724+ static assert(find("abc", 'b') == "bc");
1725+ static assert(find("日b語", 'b') == "b語");
1726+ static assert(find("日本語", '本') == "本語");
1727+ static assert(find([1, 2, 3], 2) == [2, 3]);
1728+
1729+ static assert(find ([1, 2, 3], 2));
1730+ static assert(find!((a,b)=>a == b)([1, 2, 3], 2));
1731+ static assert(find ([1, 2, 3], 2));
1732+ static assert(find!((a,b)=>a == b)([1, 2, 3], 2));
1733+}
1734+
1735+@safe unittest
1736+{
1737+ import std.exception : assertCTFEable;
1738+ import std.meta : AliasSeq;
1739+
1740+ void dg() @safe pure nothrow
1741+ {
1742+ byte[] sarr = [1, 2, 3, 4];
1743+ ubyte[] uarr = [1, 2, 3, 4];
1744+ foreach (arr; AliasSeq!(sarr, uarr))
1745+ {
1746+ foreach (T; AliasSeq!(byte, ubyte, int, uint))
1747+ {
1748+ assert(find(arr, cast(T) 3) == arr[2 .. $]);
1749+ assert(find(arr, cast(T) 9) == arr[$ .. $]);
1750+ }
1751+ assert(find(arr, 256) == arr[$ .. $]);
1752+ }
1753+ }
1754+ dg();
1755+ assertCTFEable!dg;
1756+}
1757+
1758+@safe unittest
1759+{
1760+ // Bugzilla 11603
1761+ enum Foo : ubyte { A }
1762+ assert([Foo.A].find(Foo.A).empty == false);
1763+
1764+ ubyte x = 0;
1765+ assert([x].find(x).empty == false);
1766+}
1767+
1768+/**
1769+Advances the input range $(D haystack) by calling $(D haystack.popFront)
1770+until either $(D pred(haystack.front)), or $(D
1771+haystack.empty). Performs $(BIGOH haystack.length) evaluations of $(D
1772+pred).
1773+
1774+To _find the last element of a
1775+$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) $(D haystack) satisfying
1776+$(D pred), call $(D find!(pred)(retro(haystack))). See $(REF retro, std,range).
1777+
1778+`find` behaves similar to `dropWhile` in other languages.
1779+
1780+Params:
1781+
1782+pred = The predicate for determining if a given element is the one being
1783+searched for.
1784+
1785+haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
1786+search in.
1787+
1788+Returns:
1789+
1790+$(D haystack) advanced such that the front element is the one searched for;
1791+that is, until $(D binaryFun!pred(haystack.front, needle)) is $(D true). If no
1792+such position exists, returns an empty $(D haystack).
1793+
1794+See_Also:
1795+ $(HTTP sgi.com/tech/stl/find_if.html, STL's find_if)
1796+*/
1797+InputRange find(alias pred, InputRange)(InputRange haystack)
1798+if (isInputRange!InputRange)
1799+{
1800+ alias R = InputRange;
1801+ alias predFun = unaryFun!pred;
1802+ static if (isNarrowString!R)
1803+ {
1804+ import std.utf : decode;
1805+
1806+ immutable len = haystack.length;
1807+ size_t i = 0, next = 0;
1808+ while (next < len)
1809+ {
1810+ if (predFun(decode(haystack, next)))
1811+ return haystack[i .. $];
1812+ i = next;
1813+ }
1814+ return haystack[$ .. $];
1815+ }
1816+ else
1817+ {
1818+ //standard range
1819+ for ( ; !haystack.empty; haystack.popFront() )
1820+ {
1821+ if (predFun(haystack.front))
1822+ break;
1823+ }
1824+ return haystack;
1825+ }
1826+}
1827+
1828+///
1829+@safe unittest
1830+{
1831+ auto arr = [ 1, 2, 3, 4, 1 ];
1832+ assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);
1833+
1834+ // with predicate alias
1835+ bool pred(int x) { return x + 1 > 1.5; }
1836+ assert(find!(pred)(arr) == arr);
1837+}
1838+
1839+@safe pure unittest
1840+{
1841+ int[] r = [ 1, 2, 3 ];
1842+ assert(find!(a=>a > 2)(r) == [3]);
1843+ bool pred(int x) { return x + 1 > 1.5; }
1844+ assert(find!(pred)(r) == r);
1845+
1846+ assert(find!(a=>a > 'v')("hello world") == "world");
1847+ assert(find!(a=>a%4 == 0)("日本語") == "本語");
1848+}
1849+
1850+/**
1851+Finds the first occurrence of a forward range in another forward range.
1852+
1853+Performs $(BIGOH walkLength(haystack) * walkLength(needle)) comparisons in the
1854+worst case. There are specializations that improve performance by taking
1855+advantage of $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
1856+or random access in the given ranges (where possible), depending on the statistics
1857+of the two ranges' content.
1858+
1859+Params:
1860+
1861+pred = The predicate to use for comparing respective elements from the haystack
1862+and the needle. Defaults to simple equality $(D "a == b").
1863+
1864+haystack = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
1865+searched in.
1866+
1867+needle = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
1868+searched for.
1869+
1870+Returns:
1871+
1872+$(D haystack) advanced such that $(D needle) is a prefix of it (if no
1873+such position exists, returns $(D haystack) advanced to termination).
1874+ */
1875+R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)
1876+if (isForwardRange!R1 && isForwardRange!R2
1877+ && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool))
1878+{
1879+ static if (!isRandomAccessRange!R1)
1880+ {
1881+ static if (is(typeof(pred == "a == b")) && pred == "a == b" && isSomeString!R1 && isSomeString!R2
1882+ && haystack[0].sizeof == needle[0].sizeof)
1883+ {
1884+ // return cast(R1) find(representation(haystack), representation(needle));
1885+ // Specialization for simple string search
1886+ alias Representation =
1887+ Select!(haystack[0].sizeof == 1, ubyte[],
1888+ Select!(haystack[0].sizeof == 2, ushort[], uint[]));
1889+ // Will use the array specialization
1890+ static TO force(TO, T)(T r) @trusted { return cast(TO) r; }
1891+ return force!R1(.find!(pred, Representation, Representation)
1892+ (force!Representation(haystack), force!Representation(needle)));
1893+ }
1894+ else
1895+ {
1896+ return simpleMindedFind!pred(haystack, needle);
1897+ }
1898+ }
1899+ else static if (!isBidirectionalRange!R2 || !hasSlicing!R1)
1900+ {
1901+ static if (!is(ElementType!R1 == ElementType!R2))
1902+ {
1903+ return simpleMindedFind!pred(haystack, needle);
1904+ }
1905+ else
1906+ {
1907+ // Prepare the search with needle's first element
1908+ if (needle.empty)
1909+ return haystack;
1910+
1911+ haystack = .find!pred(haystack, needle.front);
1912+
1913+ static if (hasLength!R1 && hasLength!R2 && is(typeof(takeNone(haystack)) == R1))
1914+ {
1915+ if (needle.length > haystack.length)
1916+ return takeNone(haystack);
1917+ }
1918+ else
1919+ {
1920+ if (haystack.empty)
1921+ return haystack;
1922+ }
1923+
1924+ needle.popFront();
1925+ size_t matchLen = 1;
1926+
1927+ // Loop invariant: haystack[0 .. matchLen] matches everything in
1928+ // the initial needle that was popped out of needle.
1929+ for (;;)
1930+ {
1931+ // Extend matchLength as much as possible
1932+ for (;;)
1933+ {
1934+ import std.range : takeNone;
1935+
1936+ if (needle.empty || haystack.empty)
1937+ return haystack;
1938+
1939+ static if (hasLength!R1 && is(typeof(takeNone(haystack)) == R1))
1940+ {
1941+ if (matchLen == haystack.length)
1942+ return takeNone(haystack);
1943+ }
1944+
1945+ if (!binaryFun!pred(haystack[matchLen], needle.front))
1946+ break;
1947+
1948+ ++matchLen;
1949+ needle.popFront();
1950+ }
1951+
1952+ auto bestMatch = haystack[0 .. matchLen];
1953+ haystack.popFront();
1954+ haystack = .find!pred(haystack, bestMatch);
1955+ }
1956+ }
1957+ }
1958+ else // static if (hasSlicing!R1 && isBidirectionalRange!R2)
1959+ {
1960+ if (needle.empty) return haystack;
1961+
1962+ static if (hasLength!R2)
1963+ {
1964+ immutable needleLength = needle.length;
1965+ }
1966+ else
1967+ {
1968+ immutable needleLength = walkLength(needle.save);
1969+ }
1970+ if (needleLength > haystack.length)
1971+ {
1972+ return haystack[haystack.length .. haystack.length];
1973+ }
1974+ // Optimization in case the ranges are both SortedRanges.
1975+ // Binary search can be used to find the first occurence
1976+ // of the first element of the needle in haystack.
1977+ // When it is found O(walklength(needle)) steps are performed.
1978+ // 8829 enhancement
1979+ import std.algorithm.comparison : mismatch;
1980+ import std.range : SortedRange;
1981+ static if (is(R1 == R2)
1982+ && is(R1 : SortedRange!TT, TT)
1983+ && pred == "a == b")
1984+ {
1985+ auto needleFirstElem = needle[0];
1986+ auto partitions = haystack.trisect(needleFirstElem);
1987+ auto firstElemLen = partitions[1].length;
1988+ size_t count = 0;
1989+
1990+ if (firstElemLen == 0)
1991+ return haystack[$ .. $];
1992+
1993+ while (needle.front() == needleFirstElem)
1994+ {
1995+ needle.popFront();
1996+ ++count;
1997+
1998+ if (count > firstElemLen)
1999+ return haystack[$ .. $];
2000+ }
2001+
2002+ auto m = mismatch(partitions[2], needle);
2003+
2004+ if (m[1].empty)
2005+ return haystack[partitions[0].length + partitions[1].length - count .. $];
2006+ }
2007+ else static if (isRandomAccessRange!R2)
2008+ {
2009+ immutable lastIndex = needleLength - 1;
2010+ auto last = needle[lastIndex];
2011+ size_t j = lastIndex, skip = 0;
2012+ for (; j < haystack.length;)
2013+ {
2014+ if (!binaryFun!pred(haystack[j], last))
2015+ {
2016+ ++j;
2017+ continue;
2018+ }
2019+ immutable k = j - lastIndex;
2020+ // last elements match
2021+ for (size_t i = 0;; ++i)
2022+ {
2023+ if (i == lastIndex)
2024+ return haystack[k .. haystack.length];
2025+ if (!binaryFun!pred(haystack[k + i], needle[i]))
2026+ break;
2027+ }
2028+ if (skip == 0)
2029+ {
2030+ skip = 1;
2031+ while (skip < needleLength && needle[needleLength - 1 - skip] != needle[needleLength - 1])
2032+ {
2033+ ++skip;
2034+ }
2035+ }
2036+ j += skip;
2037+ }
2038+ }
2039+ else
2040+ {
2041+ // @@@BUG@@@
2042+ // auto needleBack = moveBack(needle);
2043+ // Stage 1: find the step
2044+ size_t step = 1;
2045+ auto needleBack = needle.back;
2046+ needle.popBack();
2047+ for (auto i = needle.save; !i.empty && i.back != needleBack;
2048+ i.popBack(), ++step)
2049+ {
2050+ }
2051+ // Stage 2: linear find
2052+ size_t scout = needleLength - 1;
2053+ for (;;)
2054+ {
2055+ if (scout >= haystack.length)
2056+ break;
2057+ if (!binaryFun!pred(haystack[scout], needleBack))
2058+ {
2059+ ++scout;
2060+ continue;
2061+ }
2062+ // Found a match with the last element in the needle
2063+ auto cand = haystack[scout + 1 - needleLength .. haystack.length];
2064+ if (startsWith!pred(cand, needle))
2065+ {
2066+ // found
2067+ return cand;
2068+ }
2069+ scout += step;
2070+ }
2071+ }
2072+ return haystack[haystack.length .. haystack.length];
2073+ }
2074+}
2075+
2076+///
2077+@safe unittest
2078+{
2079+ import std.container : SList;
2080+ import std.range.primitives : empty;
2081+ import std.typecons : Tuple;
2082+
2083+ assert(find("hello, world", "World").empty);
2084+ assert(find("hello, world", "wo") == "world");
2085+ assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]);
2086+ alias C = Tuple!(int, "x", int, "y");
2087+ auto a = [C(1,0), C(2,0), C(3,1), C(4,0)];
2088+ assert(a.find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]);
2089+ assert(a[1 .. $].find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]);
2090+}
2091+
2092+@safe unittest
2093+{
2094+ import std.container : SList;
2095+ alias C = Tuple!(int, "x", int, "y");
2096+ assert([C(1,0), C(2,0), C(3,1), C(4,0)].find!"a.x == b"(SList!int(2, 3)[]) == [C(2,0), C(3,1), C(4,0)]);
2097+}
2098+
2099+@safe unittest
2100+{
2101+ import std.algorithm.comparison : equal;
2102+ import std.container : SList;
2103+
2104+ auto lst = SList!int(1, 2, 5, 7, 3);
2105+ static assert(isForwardRange!(int[]));
2106+ static assert(isForwardRange!(typeof(lst[])));
2107+ auto r = find(lst[], [2, 5]);
2108+ assert(equal(r, SList!int(2, 5, 7, 3)[]));
2109+}
2110+
2111+@safe unittest
2112+{
2113+ import std.range;
2114+ import std.stdio;
2115+
2116+ auto r1 = assumeSorted([1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 8, 8, 10]);
2117+ auto r2 = assumeSorted([3, 3, 4, 5, 6, 7, 8, 8]);
2118+ auto r3 = assumeSorted([3, 4, 5, 6, 7, 8]);
2119+ auto r4 = assumeSorted([4, 5, 6]);
2120+ auto r5 = assumeSorted([12, 13]);
2121+ auto r6 = assumeSorted([8, 8, 10, 11]);
2122+ auto r7 = assumeSorted([3, 3, 3, 3, 3, 3, 3]);
2123+
2124+ assert(find(r1, r2) == assumeSorted([3, 3, 4, 5, 6, 7, 8, 8, 8, 10]));
2125+ assert(find(r1, r3) == assumeSorted([3, 4, 5, 6, 7, 8, 8, 8, 10]));
2126+ assert(find(r1, r4) == assumeSorted([4, 5, 6, 7, 8, 8, 8, 10]));
2127+ assert(find(r1, r5).empty());
2128+ assert(find(r1, r6).empty());
2129+ assert(find(r1, r7).empty());
2130+}
2131+
2132+@safe unittest
2133+{
2134+ import std.algorithm.comparison : equal;
2135+ // @@@BUG@@@ removing static below makes unittest fail
2136+ static struct BiRange
2137+ {
2138+ int[] payload;
2139+ @property bool empty() { return payload.empty; }
2140+ @property BiRange save() { return this; }
2141+ @property ref int front() { return payload[0]; }
2142+ @property ref int back() { return payload[$ - 1]; }
2143+ void popFront() { return payload.popFront(); }
2144+ void popBack() { return payload.popBack(); }
2145+ }
2146+ auto r = BiRange([1, 2, 3, 10, 11, 4]);
2147+ assert(equal(find(r, [10, 11]), [10, 11, 4]));
2148+}
2149+
2150+@safe unittest
2151+{
2152+ import std.container : SList;
2153+
2154+ assert(find([ 1, 2, 3 ], SList!int(2, 3)[]) == [ 2, 3 ]);
2155+ assert(find([ 1, 2, 1, 2, 3, 3 ], SList!int(2, 3)[]) == [ 2, 3, 3 ]);
2156+}
2157+
2158+//Bug# 8334
2159+@safe unittest
2160+{
2161+ import std.algorithm.iteration : filter;
2162+ import std.range;
2163+
2164+ auto haystack = [1, 2, 3, 4, 1, 9, 12, 42];
2165+ auto needle = [12, 42, 27];
2166+
2167+ //different overload of find, but it's the base case.
2168+ assert(find(haystack, needle).empty);
2169+
2170+ assert(find(haystack, takeExactly(filter!"true"(needle), 3)).empty);
2171+ assert(find(haystack, filter!"true"(needle)).empty);
2172+}
2173+
2174+// Internally used by some find() overloads above
2175+private R1 simpleMindedFind(alias pred, R1, R2)(R1 haystack, scope R2 needle)
2176+{
2177+ enum estimateNeedleLength = hasLength!R1 && !hasLength!R2;
2178+
2179+ static if (hasLength!R1)
2180+ {
2181+ static if (!hasLength!R2)
2182+ size_t estimatedNeedleLength = 0;
2183+ else
2184+ immutable size_t estimatedNeedleLength = needle.length;
2185+ }
2186+
2187+ bool haystackTooShort()
2188+ {
2189+ static if (estimateNeedleLength)
2190+ {
2191+ return haystack.length < estimatedNeedleLength;
2192+ }
2193+ else
2194+ {
2195+ return haystack.empty;
2196+ }
2197+ }
2198+
2199+ searching:
2200+ for (;; haystack.popFront())
2201+ {
2202+ if (haystackTooShort())
2203+ {
2204+ // Failed search
2205+ static if (hasLength!R1)
2206+ {
2207+ static if (is(typeof(haystack[haystack.length ..
2208+ haystack.length]) : R1))
2209+ return haystack[haystack.length .. haystack.length];
2210+ else
2211+ return R1.init;
2212+ }
2213+ else
2214+ {
2215+ assert(haystack.empty);
2216+ return haystack;
2217+ }
2218+ }
2219+ static if (estimateNeedleLength)
2220+ size_t matchLength = 0;
2221+ for (auto h = haystack.save, n = needle.save;
2222+ !n.empty;
2223+ h.popFront(), n.popFront())
2224+ {
2225+ if (h.empty || !binaryFun!pred(h.front, n.front))
2226+ {
2227+ // Failed searching n in h
2228+ static if (estimateNeedleLength)
2229+ {
2230+ if (estimatedNeedleLength < matchLength)
2231+ estimatedNeedleLength = matchLength;
2232+ }
2233+ continue searching;
2234+ }
2235+ static if (estimateNeedleLength)
2236+ ++matchLength;
2237+ }
2238+ break;
2239+ }
2240+ return haystack;
2241+}
2242+
2243+@safe unittest
2244+{
2245+ // Test simpleMindedFind for the case where both haystack and needle have
2246+ // length.
2247+ struct CustomString
2248+ {
2249+ @safe:
2250+ string _impl;
2251+
2252+ // This is what triggers issue 7992.
2253+ @property size_t length() const { return _impl.length; }
2254+ @property void length(size_t len) { _impl.length = len; }
2255+
2256+ // This is for conformance to the forward range API (we deliberately
2257+ // make it non-random access so that we will end up in
2258+ // simpleMindedFind).
2259+ @property bool empty() const { return _impl.empty; }
2260+ @property dchar front() const { return _impl.front; }
2261+ void popFront() { _impl.popFront(); }
2262+ @property CustomString save() { return this; }
2263+ }
2264+
2265+ // If issue 7992 occurs, this will throw an exception from calling
2266+ // popFront() on an empty range.
2267+ auto r = find(CustomString("a"), CustomString("b"));
2268+ assert(r.empty);
2269+}
2270+
2271+/**
2272+Finds two or more $(D needles) into a $(D haystack). The predicate $(D
2273+pred) is used throughout to compare elements. By default, elements are
2274+compared for equality.
2275+
2276+Params:
2277+
2278+pred = The predicate to use for comparing elements.
2279+
2280+haystack = The target of the search. Must be an input range.
2281+If any of $(D needles) is a range with elements comparable to
2282+elements in $(D haystack), then $(D haystack) must be a
2283+$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
2284+such that the search can backtrack.
2285+
2286+needles = One or more items to search for. Each of $(D needles) must
2287+be either comparable to one element in $(D haystack), or be itself a
2288+forward range with elements comparable with elements in
2289+$(D haystack).
2290+
2291+Returns:
2292+
2293+A tuple containing $(D haystack) positioned to match one of the
2294+needles and also the 1-based index of the matching element in $(D
2295+needles) (0 if none of $(D needles) matched, 1 if $(D needles[0])
2296+matched, 2 if $(D needles[1]) matched...). The first needle to be found
2297+will be the one that matches. If multiple needles are found at the
2298+same spot in the range, then the shortest one is the one which matches
2299+(if multiple needles of the same length are found at the same spot (e.g
2300+$(D "a") and $(D 'a')), then the left-most of them in the argument list
2301+matches).
2302+
2303+The relationship between $(D haystack) and $(D needles) simply means
2304+that one can e.g. search for individual $(D int)s or arrays of $(D
2305+int)s in an array of $(D int)s. In addition, if elements are
2306+individually comparable, searches of heterogeneous types are allowed
2307+as well: a $(D double[]) can be searched for an $(D int) or a $(D
2308+short[]), and conversely a $(D long) can be searched for a $(D float)
2309+or a $(D double[]). This makes for efficient searches without the need
2310+to coerce one side of the comparison into the other's side type.
2311+
2312+The complexity of the search is $(BIGOH haystack.length *
2313+max(needles.length)). (For needles that are individual items, length
2314+is considered to be 1.) The strategy used in searching several
2315+subranges at once maximizes cache usage by moving in $(D haystack) as
2316+few times as possible.
2317+ */
2318+Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)
2319+(Range haystack, Ranges needles)
2320+if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles))))
2321+{
2322+ for (;; haystack.popFront())
2323+ {
2324+ size_t r = startsWith!pred(haystack, needles);
2325+ if (r || haystack.empty)
2326+ {
2327+ return tuple(haystack, r);
2328+ }
2329+ }
2330+}
2331+
2332+///
2333+@safe unittest
2334+{
2335+ import std.typecons : tuple;
2336+ int[] a = [ 1, 4, 2, 3 ];
2337+ assert(find(a, 4) == [ 4, 2, 3 ]);
2338+ assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]);
2339+ assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2));
2340+ // Mixed types allowed if comparable
2341+ assert(find(a, 5, [ 1.2, 3.5 ], 2.0) == tuple([ 2, 3 ], 3));
2342+}
2343+
2344+@safe unittest
2345+{
2346+ auto s1 = "Mary has a little lamb";
2347+ assert(find(s1, "has a", "has an") == tuple("has a little lamb", 1));
2348+ assert(find(s1, 't', "has a", "has an") == tuple("has a little lamb", 2));
2349+ assert(find(s1, 't', "has a", 'y', "has an") == tuple("y has a little lamb", 3));
2350+ assert(find("abc", "bc").length == 2);
2351+}
2352+
2353+@safe unittest
2354+{
2355+ import std.algorithm.internal : rndstuff;
2356+ import std.meta : AliasSeq;
2357+ import std.uni : toUpper;
2358+
2359+ int[] a = [ 1, 2, 3 ];
2360+ assert(find(a, 5).empty);
2361+ assert(find(a, 2) == [2, 3]);
2362+
2363+ foreach (T; AliasSeq!(int, double))
2364+ {
2365+ auto b = rndstuff!(T)();
2366+ if (!b.length) continue;
2367+ b[$ / 2] = 200;
2368+ b[$ / 4] = 200;
2369+ assert(find(b, 200).length == b.length - b.length / 4);
2370+ }
2371+
2372+ // Case-insensitive find of a string
2373+ string[] s = [ "Hello", "world", "!" ];
2374+ assert(find!("toUpper(a) == toUpper(b)")(s, "hello").length == 3);
2375+
2376+ static bool f(string a, string b) { return toUpper(a) == toUpper(b); }
2377+ assert(find!(f)(s, "hello").length == 3);
2378+}
2379+
2380+@safe unittest
2381+{
2382+ import std.algorithm.comparison : equal;
2383+ import std.algorithm.internal : rndstuff;
2384+ import std.meta : AliasSeq;
2385+ import std.range : retro;
2386+
2387+ int[] a = [ 1, 2, 3, 2, 6 ];
2388+ assert(find(retro(a), 5).empty);
2389+ assert(equal(find(retro(a), 2), [ 2, 3, 2, 1 ][]));
2390+
2391+ foreach (T; AliasSeq!(int, double))
2392+ {
2393+ auto b = rndstuff!(T)();
2394+ if (!b.length) continue;
2395+ b[$ / 2] = 200;
2396+ b[$ / 4] = 200;
2397+ assert(find(retro(b), 200).length ==
2398+ b.length - (b.length - 1) / 2);
2399+ }
2400+}
2401+
2402+@safe unittest
2403+{
2404+ import std.algorithm.comparison : equal;
2405+ import std.internal.test.dummyrange;
2406+
2407+ int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
2408+ int[] b = [ 1, 2, 3 ];
2409+ assert(find(a, b) == [ 1, 2, 3, 4, 5 ]);
2410+ assert(find(b, a).empty);
2411+
2412+ foreach (DummyType; AllDummyRanges)
2413+ {
2414+ DummyType d;
2415+ auto findRes = find(d, 5);
2416+ assert(equal(findRes, [5,6,7,8,9,10]));
2417+ }
2418+}
2419+
2420+/**
2421+ * Finds $(D needle) in $(D haystack) efficiently using the
2422+ * $(LINK2 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm,
2423+ * Boyer-Moore) method.
2424+ *
2425+ * Params:
2426+ * haystack = A random-access range with length and slicing.
2427+ * needle = A $(LREF BoyerMooreFinder).
2428+ *
2429+ * Returns:
2430+ * $(D haystack) advanced such that $(D needle) is a prefix of it (if no
2431+ * such position exists, returns $(D haystack) advanced to termination).
2432+ */
2433+RandomAccessRange find(RandomAccessRange, alias pred, InputRange)(
2434+ RandomAccessRange haystack, scope BoyerMooreFinder!(pred, InputRange) needle)
2435+{
2436+ return needle.beFound(haystack);
2437+}
2438+
2439+@safe unittest
2440+{
2441+ string h = "/homes/aalexand/d/dmd/bin/../lib/libphobos.a(dmain2.o)"~
2442+ "(.gnu.linkonce.tmain+0x74): In function `main' undefined reference"~
2443+ " to `_Dmain':";
2444+ string[] ns = ["libphobos", "function", " undefined", "`", ":"];
2445+ foreach (n ; ns)
2446+ {
2447+ auto p = find(h, boyerMooreFinder(n));
2448+ assert(!p.empty);
2449+ }
2450+}
2451+
2452+///
2453+@safe unittest
2454+{
2455+ import std.range.primitives : empty;
2456+ int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
2457+ int[] b = [ 1, 2, 3 ];
2458+
2459+ assert(find(a, boyerMooreFinder(b)) == [ 1, 2, 3, 4, 5 ]);
2460+ assert(find(b, boyerMooreFinder(a)).empty);
2461+}
2462+
2463+@safe unittest
2464+{
2465+ auto bm = boyerMooreFinder("for");
2466+ auto match = find("Moor", bm);
2467+ assert(match.empty);
2468+}
2469+
2470+// canFind
2471+/++
2472+Convenience function. Like find, but only returns whether or not the search
2473+was successful.
2474+
2475+See_Also:
2476+$(LREF among) for checking a value against multiple possibilities.
2477+ +/
2478+template canFind(alias pred="a == b")
2479+{
2480+ import std.meta : allSatisfy;
2481+
2482+ /++
2483+ Returns $(D true) if and only if any value $(D v) found in the
2484+ input range $(D range) satisfies the predicate $(D pred).
2485+ Performs (at most) $(BIGOH haystack.length) evaluations of $(D pred).
2486+ +/
2487+ bool canFind(Range)(Range haystack)
2488+ if (is(typeof(find!pred(haystack))))
2489+ {
2490+ return any!pred(haystack);
2491+ }
2492+
2493+ /++
2494+ Returns $(D true) if and only if $(D needle) can be found in $(D
2495+ range). Performs $(BIGOH haystack.length) evaluations of $(D pred).
2496+ +/
2497+ bool canFind(Range, Element)(Range haystack, scope Element needle)
2498+ if (is(typeof(find!pred(haystack, needle))))
2499+ {
2500+ return !find!pred(haystack, needle).empty;
2501+ }
2502+
2503+ /++
2504+ Returns the 1-based index of the first needle found in $(D haystack). If no
2505+ needle is found, then $(D 0) is returned.
2506+
2507+ So, if used directly in the condition of an if statement or loop, the result
2508+ will be $(D true) if one of the needles is found and $(D false) if none are
2509+ found, whereas if the result is used elsewhere, it can either be cast to
2510+ $(D bool) for the same effect or used to get which needle was found first
2511+ without having to deal with the tuple that $(D LREF find) returns for the
2512+ same operation.
2513+ +/
2514+ size_t canFind(Range, Ranges...)(Range haystack, scope Ranges needles)
2515+ if (Ranges.length > 1 &&
2516+ allSatisfy!(isForwardRange, Ranges) &&
2517+ is(typeof(find!pred(haystack, needles))))
2518+ {
2519+ return find!pred(haystack, needles)[1];
2520+ }
2521+}
2522+
2523+///
2524+@safe unittest
2525+{
2526+ assert(canFind([0, 1, 2, 3], 2) == true);
2527+ assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]));
2528+ assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]) == 1);
2529+ assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]));
2530+ assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]) == 2);
2531+
2532+ assert(canFind([0, 1, 2, 3], 4) == false);
2533+ assert(!canFind([0, 1, 2, 3], [1, 3], [2, 4]));
2534+ assert(canFind([0, 1, 2, 3], [1, 3], [2, 4]) == 0);
2535+}
2536+
2537+/**
2538+ * Example using a custom predicate.
2539+ * Note that the needle appears as the second argument of the predicate.
2540+ */
2541+@safe unittest
2542+{
2543+ auto words = [
2544+ "apple",
2545+ "beeswax",
2546+ "cardboard"
2547+ ];
2548+ assert(!canFind(words, "bees"));
2549+ assert( canFind!((string a, string b) => a.startsWith(b))(words, "bees"));
2550+}
2551+
2552+@safe unittest
2553+{
2554+ import std.algorithm.internal : rndstuff;
2555+
2556+ auto a = rndstuff!(int)();
2557+ if (a.length)
2558+ {
2559+ auto b = a[a.length / 2];
2560+ assert(canFind(a, b));
2561+ }
2562+}
2563+
2564+@safe unittest
2565+{
2566+ import std.algorithm.comparison : equal;
2567+ assert(equal!(canFind!"a < b")([[1, 2, 3], [7, 8, 9]], [2, 8]));
2568+}
2569+
2570+// findAdjacent
2571+/**
2572+Advances $(D r) until it finds the first two adjacent elements $(D a),
2573+$(D b) that satisfy $(D pred(a, b)). Performs $(BIGOH r.length)
2574+evaluations of $(D pred).
2575+
2576+Params:
2577+ pred = The predicate to satisfy.
2578+ r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
2579+ search in.
2580+
2581+Returns:
2582+$(D r) advanced to the first occurrence of two adjacent elements that satisfy
2583+the given predicate. If there are no such two elements, returns $(D r) advanced
2584+until empty.
2585+
2586+See_Also:
2587+ $(HTTP sgi.com/tech/stl/adjacent_find.html, STL's adjacent_find)
2588+*/
2589+Range findAdjacent(alias pred = "a == b", Range)(Range r)
2590+if (isForwardRange!(Range))
2591+{
2592+ auto ahead = r.save;
2593+ if (!ahead.empty)
2594+ {
2595+ for (ahead.popFront(); !ahead.empty; r.popFront(), ahead.popFront())
2596+ {
2597+ if (binaryFun!(pred)(r.front, ahead.front)) return r;
2598+ }
2599+ }
2600+ static if (!isInfinite!Range)
2601+ return ahead;
2602+}
2603+
2604+///
2605+@safe unittest
2606+{
2607+ int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ];
2608+ auto r = findAdjacent(a);
2609+ assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]);
2610+ auto p = findAdjacent!("a < b")(a);
2611+ assert(p == [ 7, 8, 9 ]);
2612+
2613+}
2614+
2615+@safe unittest
2616+{
2617+ import std.algorithm.comparison : equal;
2618+ import std.internal.test.dummyrange;
2619+ import std.range;
2620+
2621+ int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ];
2622+ auto p = findAdjacent(a);
2623+ assert(p == [10, 10, 9, 8, 8, 7, 8, 9 ]);
2624+ p = findAdjacent!("a < b")(a);
2625+ assert(p == [7, 8, 9]);
2626+ // empty
2627+ a = [];
2628+ p = findAdjacent(a);
2629+ assert(p.empty);
2630+ // not found
2631+ a = [ 1, 2, 3, 4, 5 ];
2632+ p = findAdjacent(a);
2633+ assert(p.empty);
2634+ p = findAdjacent!"a > b"(a);
2635+ assert(p.empty);
2636+ ReferenceForwardRange!int rfr = new ReferenceForwardRange!int([1, 2, 3, 2, 2, 3]);
2637+ assert(equal(findAdjacent(rfr), [2, 2, 3]));
2638+
2639+ // Issue 9350
2640+ assert(!repeat(1).findAdjacent().empty);
2641+}
2642+
2643+// findAmong
2644+/**
2645+Searches the given range for an element that matches one of the given choices.
2646+
2647+Advances $(D seq) by calling $(D seq.popFront) until either
2648+$(D find!(pred)(choices, seq.front)) is $(D true), or $(D seq) becomes empty.
2649+Performs $(BIGOH seq.length * choices.length) evaluations of $(D pred).
2650+
2651+Params:
2652+ pred = The predicate to use for determining a match.
2653+ seq = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
2654+ search.
2655+ choices = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
2656+ of possible choices.
2657+
2658+Returns:
2659+$(D seq) advanced to the first matching element, or until empty if there are no
2660+matching elements.
2661+
2662+See_Also:
2663+ $(HTTP sgi.com/tech/stl/find_first_of.html, STL's find_first_of)
2664+*/
2665+InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)(
2666+ InputRange seq, ForwardRange choices)
2667+if (isInputRange!InputRange && isForwardRange!ForwardRange)
2668+{
2669+ for (; !seq.empty && find!pred(choices, seq.front).empty; seq.popFront())
2670+ {
2671+ }
2672+ return seq;
2673+}
2674+
2675+///
2676+@safe unittest
2677+{
2678+ int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
2679+ int[] b = [ 3, 1, 2 ];
2680+ assert(findAmong(a, b) == a[2 .. $]);
2681+}
2682+
2683+@safe unittest
2684+{
2685+ int[] a = [ -1, 0, 2, 1, 2, 3, 4, 5 ];
2686+ int[] b = [ 1, 2, 3 ];
2687+ assert(findAmong(a, b) == [2, 1, 2, 3, 4, 5 ]);
2688+ assert(findAmong(b, [ 4, 6, 7 ][]).empty);
2689+ assert(findAmong!("a == b")(a, b).length == a.length - 2);
2690+ assert(findAmong!("a == b")(b, [ 4, 6, 7 ][]).empty);
2691+}
2692+
2693+// findSkip
2694+/**
2695+ * Finds $(D needle) in $(D haystack) and positions $(D haystack)
2696+ * right after the first occurrence of $(D needle).
2697+ *
2698+ * Params:
2699+ * haystack = The
2700+ * $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search
2701+ * in.
2702+ * needle = The
2703+ * $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search
2704+ * for.
2705+ *
2706+ * Returns: $(D true) if the needle was found, in which case $(D haystack) is
2707+ * positioned after the end of the first occurrence of $(D needle); otherwise
2708+ * $(D false), leaving $(D haystack) untouched.
2709+ */
2710+bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle)
2711+if (isForwardRange!R1 && isForwardRange!R2
2712+ && is(typeof(binaryFun!pred(haystack.front, needle.front))))
2713+{
2714+ auto parts = findSplit!pred(haystack, needle);
2715+ if (parts[1].empty) return false;
2716+ // found
2717+ haystack = parts[2];
2718+ return true;
2719+}
2720+
2721+///
2722+@safe unittest
2723+{
2724+ import std.range.primitives : empty;
2725+ // Needle is found; s is replaced by the substring following the first
2726+ // occurrence of the needle.
2727+ string s = "abcdef";
2728+ assert(findSkip(s, "cd") && s == "ef");
2729+
2730+ // Needle is not found; s is left untouched.
2731+ s = "abcdef";
2732+ assert(!findSkip(s, "cxd") && s == "abcdef");
2733+
2734+ // If the needle occurs at the end of the range, the range is left empty.
2735+ s = "abcdef";
2736+ assert(findSkip(s, "def") && s.empty);
2737+}
2738+
2739+/**
2740+These functions find the first occurrence of `needle` in `haystack` and then
2741+split `haystack` as follows.
2742+
2743+`findSplit` returns a tuple `result` containing $(I three) ranges. `result[0]`
2744+is the portion of `haystack` before `needle`, `result[1]` is the portion of
2745+`haystack` that matches `needle`, and `result[2]` is the portion of `haystack`
2746+after the match. If `needle` was not found, `result[0]` comprehends `haystack`
2747+entirely and `result[1]` and `result[2]` are empty.
2748+
2749+`findSplitBefore` returns a tuple `result` containing two ranges. `result[0]` is
2750+the portion of `haystack` before `needle`, and `result[1]` is the balance of
2751+`haystack` starting with the match. If `needle` was not found, `result[0]`
2752+comprehends `haystack` entirely and `result[1]` is empty.
2753+
2754+`findSplitAfter` returns a tuple `result` containing two ranges.
2755+`result[0]` is the portion of `haystack` up to and including the
2756+match, and `result[1]` is the balance of `haystack` starting
2757+after the match. If `needle` was not found, `result[0]` is empty
2758+and `result[1]` is `haystack`.
2759+
2760+In all cases, the concatenation of the returned ranges spans the
2761+entire `haystack`.
2762+
2763+If `haystack` is a random-access range, all three components of the tuple have
2764+the same type as `haystack`. Otherwise, `haystack` must be a
2765+$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and
2766+the type of `result[0]` and `result[1]` is the same as $(REF takeExactly,
2767+std,range).
2768+
2769+Params:
2770+ pred = Predicate to use for comparing needle against haystack.
2771+ haystack = The range to search.
2772+ needle = What to look for.
2773+
2774+Returns:
2775+
2776+A sub-type of `Tuple!()` of the split portions of `haystack` (see above for
2777+details). This sub-type of `Tuple!()` has `opCast` defined for `bool`. This
2778+`opCast` returns `true` when the separating `needle` was found
2779+(`!result[1].empty`) and `false` otherwise. This enables the convenient idiom
2780+shown in the following example.
2781+
2782+Example:
2783+---
2784+if (const split = haystack.findSplit(needle))
2785+{
2786+ doSomethingWithSplit(split);
2787+}
2788+---
2789+ */
2790+auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
2791+if (isForwardRange!R1 && isForwardRange!R2)
2792+{
2793+ static struct Result(S1, S2) if (isForwardRange!S1 &&
2794+ isForwardRange!S2)
2795+ {
2796+ this(S1 pre, S1 separator, S2 post)
2797+ {
2798+ asTuple = typeof(asTuple)(pre, separator, post);
2799+ }
2800+ void opAssign(typeof(asTuple) rhs)
2801+ {
2802+ asTuple = rhs;
2803+ }
2804+ Tuple!(S1, S1, S2) asTuple;
2805+ bool opCast(T : bool)()
2806+ {
2807+ return !asTuple[1].empty;
2808+ }
2809+ alias asTuple this;
2810+ }
2811+
2812+ static if (isSomeString!R1 && isSomeString!R2
2813+ || (isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && hasLength!R2))
2814+ {
2815+ auto balance = find!pred(haystack, needle);
2816+ immutable pos1 = haystack.length - balance.length;
2817+ immutable pos2 = balance.empty ? pos1 : pos1 + needle.length;
2818+ return Result!(typeof(haystack[0 .. pos1]),
2819+ typeof(haystack[pos2 .. haystack.length]))(haystack[0 .. pos1],
2820+ haystack[pos1 .. pos2],
2821+ haystack[pos2 .. haystack.length]);
2822+ }
2823+ else
2824+ {
2825+ import std.range : takeExactly;
2826+ auto original = haystack.save;
2827+ auto h = haystack.save;
2828+ auto n = needle.save;
2829+ size_t pos1, pos2;
2830+ while (!n.empty && !h.empty)
2831+ {
2832+ if (binaryFun!pred(h.front, n.front))
2833+ {
2834+ h.popFront();
2835+ n.popFront();
2836+ ++pos2;
2837+ }
2838+ else
2839+ {
2840+ haystack.popFront();
2841+ n = needle.save;
2842+ h = haystack.save;
2843+ pos2 = ++pos1;
2844+ }
2845+ }
2846+ return Result!(typeof(takeExactly(original, pos1)),
2847+ typeof(h))(takeExactly(original, pos1),
2848+ takeExactly(haystack, pos2 - pos1),
2849+ h);
2850+ }
2851+}
2852+
2853+/// Ditto
2854+auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
2855+if (isForwardRange!R1 && isForwardRange!R2)
2856+{
2857+ static struct Result(S1, S2) if (isForwardRange!S1 &&
2858+ isForwardRange!S2)
2859+ {
2860+ this(S1 pre, S2 post)
2861+ {
2862+ asTuple = typeof(asTuple)(pre, post);
2863+ }
2864+ void opAssign(typeof(asTuple) rhs)
2865+ {
2866+ asTuple = rhs;
2867+ }
2868+ Tuple!(S1, S2) asTuple;
2869+ bool opCast(T : bool)()
2870+ {
2871+ return !asTuple[0].empty;
2872+ }
2873+ alias asTuple this;
2874+ }
2875+
2876+ static if (isSomeString!R1 && isSomeString!R2
2877+ || (isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2))
2878+ {
2879+ auto balance = find!pred(haystack, needle);
2880+ immutable pos = haystack.length - balance.length;
2881+ return Result!(typeof(haystack[0 .. pos]),
2882+ typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos],
2883+ haystack[pos .. haystack.length]);
2884+ }
2885+ else
2886+ {
2887+ import std.range : takeExactly;
2888+ auto original = haystack.save;
2889+ auto h = haystack.save;
2890+ auto n = needle.save;
2891+ size_t pos;
2892+ while (!n.empty && !h.empty)
2893+ {
2894+ if (binaryFun!pred(h.front, n.front))
2895+ {
2896+ h.popFront();
2897+ n.popFront();
2898+ }
2899+ else
2900+ {
2901+ haystack.popFront();
2902+ n = needle.save;
2903+ h = haystack.save;
2904+ ++pos;
2905+ }
2906+ }
2907+ return Result!(typeof(takeExactly(original, pos)),
2908+ typeof(haystack))(takeExactly(original, pos),
2909+ haystack);
2910+ }
2911+}
2912+
2913+/// Ditto
2914+auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
2915+if (isForwardRange!R1 && isForwardRange!R2)
2916+{
2917+ static struct Result(S1, S2) if (isForwardRange!S1 &&
2918+ isForwardRange!S2)
2919+ {
2920+ this(S1 pre, S2 post)
2921+ {
2922+ asTuple = typeof(asTuple)(pre, post);
2923+ }
2924+ void opAssign(typeof(asTuple) rhs)
2925+ {
2926+ asTuple = rhs;
2927+ }
2928+ Tuple!(S1, S2) asTuple;
2929+ bool opCast(T : bool)()
2930+ {
2931+ return !asTuple[1].empty;
2932+ }
2933+ alias asTuple this;
2934+ }
2935+
2936+ static if (isSomeString!R1 && isSomeString!R2
2937+ || isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2)
2938+ {
2939+ auto balance = find!pred(haystack, needle);
2940+ immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length;
2941+ return Result!(typeof(haystack[0 .. pos]),
2942+ typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos],
2943+ haystack[pos .. haystack.length]);
2944+ }
2945+ else
2946+ {
2947+ import std.range : takeExactly;
2948+ auto original = haystack.save;
2949+ auto h = haystack.save;
2950+ auto n = needle.save;
2951+ size_t pos1, pos2;
2952+ while (!n.empty)
2953+ {
2954+ if (h.empty)
2955+ {
2956+ // Failed search
2957+ return Result!(typeof(takeExactly(original, 0)),
2958+ typeof(original))(takeExactly(original, 0),
2959+ original);
2960+ }
2961+ if (binaryFun!pred(h.front, n.front))
2962+ {
2963+ h.popFront();
2964+ n.popFront();
2965+ ++pos2;
2966+ }
2967+ else
2968+ {
2969+ haystack.popFront();
2970+ n = needle.save;
2971+ h = haystack.save;
2972+ pos2 = ++pos1;
2973+ }
2974+ }
2975+ return Result!(typeof(takeExactly(original, pos2)),
2976+ typeof(h))(takeExactly(original, pos2),
2977+ h);
2978+ }
2979+}
2980+
2981+///
2982+@safe pure nothrow unittest
2983+{
2984+ import std.range.primitives : empty;
2985+
2986+ auto a = "Carl Sagan Memorial Station";
2987+ auto r = findSplit(a, "Velikovsky");
2988+ import std.typecons : isTuple;
2989+ static assert(isTuple!(typeof(r.asTuple)));
2990+ static assert(isTuple!(typeof(r)));
2991+ assert(!r);
2992+ assert(r[0] == a);
2993+ assert(r[1].empty);
2994+ assert(r[2].empty);
2995+ r = findSplit(a, " ");
2996+ assert(r[0] == "Carl");
2997+ assert(r[1] == " ");
2998+ assert(r[2] == "Sagan Memorial Station");
2999+ auto r1 = findSplitBefore(a, "Sagan");
3000+ assert(r1);
3001+ assert(r1[0] == "Carl ");
3002+ assert(r1[1] == "Sagan Memorial Station");
3003+ auto r2 = findSplitAfter(a, "Sagan");
3004+ assert(r2);
3005+ assert(r2[0] == "Carl Sagan");
3006+ assert(r2[1] == " Memorial Station");
3007+}
3008+
3009+/// Use $(REF only, std,range) to find single elements:
3010+@safe pure nothrow unittest
3011+{
3012+ import std.range : only;
3013+ assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
3014+}
3015+
3016+@safe pure nothrow unittest
3017+{
3018+ import std.range.primitives : empty;
3019+
3020+ auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
3021+ auto r = findSplit(a, [9, 1]);
3022+ assert(!r);
3023+ assert(r[0] == a);
3024+ assert(r[1].empty);
3025+ assert(r[2].empty);
3026+ r = findSplit(a, [3]);
3027+ assert(r);
3028+ assert(r[0] == a[0 .. 2]);
3029+ assert(r[1] == a[2 .. 3]);
3030+ assert(r[2] == a[3 .. $]);
3031+
3032+ auto r1 = findSplitBefore(a, [9, 1]);
3033+ assert(r1);
3034+ assert(r1[0] == a);
3035+ assert(r1[1].empty);
3036+ r1 = findSplitBefore(a, [3, 4]);
3037+ assert(r1);
3038+ assert(r1[0] == a[0 .. 2]);
3039+ assert(r1[1] == a[2 .. $]);
3040+
3041+ auto r2 = findSplitAfter(a, [9, 1]);
3042+ assert(r2);
3043+ assert(r2[0].empty);
3044+ assert(r2[1] == a);
3045+ r2 = findSplitAfter(a, [3, 4]);
3046+ assert(r2);
3047+ assert(r2[0] == a[0 .. 4]);
3048+ assert(r2[1] == a[4 .. $]);
3049+}
3050+
3051+@safe pure nothrow unittest
3052+{
3053+ import std.algorithm.comparison : equal;
3054+ import std.algorithm.iteration : filter;
3055+
3056+ auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
3057+ auto fwd = filter!"a > 0"(a);
3058+ auto r = findSplit(fwd, [9, 1]);
3059+ assert(!r);
3060+ assert(equal(r[0], a));
3061+ assert(r[1].empty);
3062+ assert(r[2].empty);
3063+ r = findSplit(fwd, [3]);
3064+ assert(r);
3065+ assert(equal(r[0], a[0 .. 2]));
3066+ assert(equal(r[1], a[2 .. 3]));
3067+ assert(equal(r[2], a[3 .. $]));
3068+
3069+ auto r1 = findSplitBefore(fwd, [9, 1]);
3070+ assert(r1);
3071+ assert(equal(r1[0], a));
3072+ assert(r1[1].empty);
3073+ r1 = findSplitBefore(fwd, [3, 4]);
3074+ assert(r1);
3075+ assert(equal(r1[0], a[0 .. 2]));
3076+ assert(equal(r1[1], a[2 .. $]));
3077+
3078+ auto r2 = findSplitAfter(fwd, [9, 1]);
3079+ assert(r2);
3080+ assert(r2[0].empty);
3081+ assert(equal(r2[1], a));
3082+ r2 = findSplitAfter(fwd, [3, 4]);
3083+ assert(r2);
3084+ assert(equal(r2[0], a[0 .. 4]));
3085+ assert(equal(r2[1], a[4 .. $]));
3086+}
3087+
3088+@safe pure nothrow @nogc unittest
3089+{
3090+ auto str = "sep,one,sep,two";
3091+
3092+ auto split = str.findSplitAfter(",");
3093+ assert(split[0] == "sep,");
3094+
3095+ split = split[1].findSplitAfter(",");
3096+ assert(split[0] == "one,");
3097+
3098+ split = split[1].findSplitBefore(",");
3099+ assert(split[0] == "sep");
3100+}
3101+
3102+@safe pure nothrow @nogc unittest
3103+{
3104+ auto str = "sep,one,sep,two";
3105+
3106+ auto split = str.findSplitBefore(",two");
3107+ assert(split[0] == "sep,one,sep");
3108+ assert(split[1] == ",two");
3109+
3110+ split = split[0].findSplitBefore(",sep");
3111+ assert(split[0] == "sep,one");
3112+ assert(split[1] == ",sep");
3113+
3114+ split = split[0].findSplitAfter(",");
3115+ assert(split[0] == "sep,");
3116+ assert(split[1] == "one");
3117+}
3118+
3119+// minCount
3120+/**
3121+
3122+Computes the minimum (respectively maximum) of `range` along with its number of
3123+occurrences. Formally, the minimum is a value `x` in `range` such that $(D
3124+pred(a, x)) is `false` for all values `a` in `range`. Conversely, the maximum is
3125+a value `x` in `range` such that $(D pred(x, a)) is `false` for all values `a`
3126+in `range` (note the swapped arguments to `pred`).
3127+
3128+These functions may be used for computing arbitrary extrema by choosing `pred`
3129+appropriately. For corrrect functioning, `pred` must be a strict partial order,
3130+i.e. transitive (if $(D pred(a, b) && pred(b, c)) then $(D pred(a, c))) and
3131+irreflexive ($(D pred(a, a)) is `false`). The $(LUCKY trichotomy property of
3132+inequality) is not required: these algoritms consider elements `a` and `b` equal
3133+(for the purpose of counting) if `pred` puts them in the same equivalence class,
3134+i.e. $(D !pred(a, b) && !pred(b, a)).
3135+
3136+Params:
3137+ pred = The ordering predicate to use to determine the extremum (minimum
3138+ or maximum).
3139+ range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to count.
3140+
3141+Returns: The minimum, respectively maximum element of a range together with the
3142+number it occurs in the range.
3143+
3144+Throws: `Exception` if `range.empty`.
3145+ */
3146+Tuple!(ElementType!Range, size_t)
3147+minCount(alias pred = "a < b", Range)(Range range)
3148+if (isInputRange!Range && !isInfinite!Range &&
3149+ is(typeof(binaryFun!pred(range.front, range.front))))
3150+{
3151+ import std.algorithm.internal : algoFormat;
3152+ import std.exception : enforce;
3153+
3154+ alias T = ElementType!Range;
3155+ alias UT = Unqual!T;
3156+ alias RetType = Tuple!(T, size_t);
3157+
3158+ static assert(is(typeof(RetType(range.front, 1))),
3159+ algoFormat("Error: Cannot call minCount on a %s, because it is not possible "~
3160+ "to copy the result value (a %s) into a Tuple.", Range.stringof, T.stringof));
3161+
3162+ enforce(!range.empty, "Can't count elements from an empty range");
3163+ size_t occurrences = 1;
3164+
3165+ static if (isForwardRange!Range)
3166+ {
3167+ Range least = range.save;
3168+ for (range.popFront(); !range.empty; range.popFront())
3169+ {
3170+ if (binaryFun!pred(least.front, range.front))
3171+ {
3172+ assert(!binaryFun!pred(range.front, least.front),
3173+ "min/maxPos: predicate must be a strict partial order.");
3174+ continue;
3175+ }
3176+ if (binaryFun!pred(range.front, least.front))
3177+ {
3178+ // change the min
3179+ least = range.save;
3180+ occurrences = 1;
3181+ }
3182+ else
3183+ ++occurrences;
3184+ }
3185+ return RetType(least.front, occurrences);
3186+ }
3187+ else static if (isAssignable!(UT, T) || (!hasElaborateAssign!UT && isAssignable!UT))
3188+ {
3189+ UT v = UT.init;
3190+ static if (isAssignable!(UT, T)) v = range.front;
3191+ else v = cast(UT) range.front;
3192+
3193+ for (range.popFront(); !range.empty; range.popFront())
3194+ {
3195+ if (binaryFun!pred(*cast(T*)&v, range.front)) continue;
3196+ if (binaryFun!pred(range.front, *cast(T*)&v))
3197+ {
3198+ // change the min
3199+ static if (isAssignable!(UT, T)) v = range.front;
3200+ else v = cast(UT) range.front; //Safe because !hasElaborateAssign!UT
3201+ occurrences = 1;
3202+ }
3203+ else
3204+ ++occurrences;
3205+ }
3206+ return RetType(*cast(T*)&v, occurrences);
3207+ }
3208+ else static if (hasLvalueElements!Range)
3209+ {
3210+ import std.algorithm.internal : addressOf;
3211+ T* p = addressOf(range.front);
3212+ for (range.popFront(); !range.empty; range.popFront())
3213+ {
3214+ if (binaryFun!pred(*p, range.front)) continue;
3215+ if (binaryFun!pred(range.front, *p))
3216+ {
3217+ // change the min
3218+ p = addressOf(range.front);
3219+ occurrences = 1;
3220+ }
3221+ else
3222+ ++occurrences;
3223+ }
3224+ return RetType(*p, occurrences);
3225+ }
3226+ else
3227+ static assert(false,
3228+ algoFormat("Sorry, can't find the minCount of a %s: Don't know how "~
3229+ "to keep track of the smallest %s element.", Range.stringof, T.stringof));
3230+}
3231+
3232+/// Ditto
3233+Tuple!(ElementType!Range, size_t)
3234+maxCount(alias pred = "a < b", Range)(Range range)
3235+if (isInputRange!Range && !isInfinite!Range &&
3236+ is(typeof(binaryFun!pred(range.front, range.front))))
3237+{
3238+ return range.minCount!((a, b) => binaryFun!pred(b, a));
3239+}
3240+
3241+///
3242+@safe unittest
3243+{
3244+ import std.conv : text;
3245+ import std.typecons : tuple;
3246+
3247+ int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3248+ // Minimum is 1 and occurs 3 times
3249+ assert(a.minCount == tuple(1, 3));
3250+ // Maximum is 4 and occurs 2 times
3251+ assert(a.maxCount == tuple(4, 2));
3252+}
3253+
3254+@system unittest
3255+{
3256+ import std.conv : text;
3257+ import std.exception : assertThrown;
3258+ import std.internal.test.dummyrange;
3259+
3260+ int[][] b = [ [4], [2, 4], [4], [4] ];
3261+ auto c = minCount!("a[0] < b[0]")(b);
3262+ assert(c == tuple([2, 4], 1), text(c[0]));
3263+
3264+ //Test empty range
3265+ assertThrown(minCount(b[$..$]));
3266+
3267+ //test with reference ranges. Test both input and forward.
3268+ assert(minCount(new ReferenceInputRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2));
3269+ assert(minCount(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2));
3270+}
3271+
3272+@system unittest
3273+{
3274+ import std.conv : text;
3275+ import std.meta : AliasSeq;
3276+
3277+ static struct R(T) //input range
3278+ {
3279+ T[] arr;
3280+ alias arr this;
3281+ }
3282+
3283+ immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3284+ R!(immutable int) b = R!(immutable int)(a);
3285+
3286+ assert(minCount(a) == tuple(1, 3));
3287+ assert(minCount(b) == tuple(1, 3));
3288+ assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(a) == tuple(4, 2));
3289+ assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(b) == tuple(4, 2));
3290+
3291+ immutable(int[])[] c = [ [4], [2, 4], [4], [4] ];
3292+ assert(minCount!("a[0] < b[0]")(c) == tuple([2, 4], 1), text(c[0]));
3293+
3294+ static struct S1
3295+ {
3296+ int i;
3297+ }
3298+ alias IS1 = immutable(S1);
3299+ static assert( isAssignable!S1);
3300+ static assert( isAssignable!(S1, IS1));
3301+
3302+ static struct S2
3303+ {
3304+ int* p;
3305+ this(ref immutable int i) immutable {p = &i;}
3306+ this(ref int i) {p = &i;}
3307+ @property ref inout(int) i() inout {return *p;}
3308+ bool opEquals(const S2 other) const {return i == other.i;}
3309+ }
3310+ alias IS2 = immutable(S2);
3311+ static assert( isAssignable!S2);
3312+ static assert(!isAssignable!(S2, IS2));
3313+ static assert(!hasElaborateAssign!S2);
3314+
3315+ static struct S3
3316+ {
3317+ int i;
3318+ void opAssign(ref S3 other) @disable;
3319+ }
3320+ static assert(!isAssignable!S3);
3321+
3322+ foreach (Type; AliasSeq!(S1, IS1, S2, IS2, S3))
3323+ {
3324+ static if (is(Type == immutable)) alias V = immutable int;
3325+ else alias V = int;
3326+ V one = 1, two = 2;
3327+ auto r1 = [Type(two), Type(one), Type(one)];
3328+ auto r2 = R!Type(r1);
3329+ assert(minCount!"a.i < b.i"(r1) == tuple(Type(one), 2));
3330+ assert(minCount!"a.i < b.i"(r2) == tuple(Type(one), 2));
3331+ assert(one == 1 && two == 2);
3332+ }
3333+}
3334+
3335+/**
3336+Iterates the passed range and returns the minimal element.
3337+A custom mapping function can be passed to `map`.
3338+In other languages this is sometimes called `argmin`.
3339+
3340+Complexity: O(n)
3341+ Exactly `n - 1` comparisons are needed.
3342+
3343+Params:
3344+ map = custom accessor for the comparison key
3345+ r = range from which the minimal element will be selected
3346+ seed = custom seed to use as initial element
3347+
3348+Returns: The minimal element of the passed-in range.
3349+
3350+See_Also:
3351+ $(REF min, std,algorithm,comparison)
3352+*/
3353+auto minElement(alias map, Range)(Range r)
3354+if (isInputRange!Range && !isInfinite!Range)
3355+{
3356+ return extremum!map(r);
3357+}
3358+
3359+/// ditto
3360+auto minElement(Range)(Range r)
3361+ if (isInputRange!Range && !isInfinite!Range)
3362+{
3363+ return extremum(r);
3364+}
3365+
3366+/// ditto
3367+auto minElement(alias map, Range, RangeElementType = ElementType!Range)
3368+ (Range r, RangeElementType seed)
3369+if (isInputRange!Range && !isInfinite!Range &&
3370+ !is(CommonType!(ElementType!Range, RangeElementType) == void))
3371+{
3372+ return extremum!map(r, seed);
3373+}
3374+
3375+/// ditto
3376+auto minElement(Range, RangeElementType = ElementType!Range)
3377+ (Range r, RangeElementType seed)
3378+ if (isInputRange!Range && !isInfinite!Range &&
3379+ !is(CommonType!(ElementType!Range, RangeElementType) == void))
3380+{
3381+ return extremum(r, seed);
3382+}
3383+
3384+///
3385+@safe pure unittest
3386+{
3387+ import std.range : enumerate;
3388+ import std.typecons : tuple;
3389+
3390+ assert([2, 1, 4, 3].minElement == 1);
3391+
3392+ // allows to get the index of an element too
3393+ assert([5, 3, 7, 9].enumerate.minElement!"a.value" == tuple(1, 3));
3394+
3395+ // any custom accessor can be passed
3396+ assert([[0, 4], [1, 2]].minElement!"a[1]" == [1, 2]);
3397+
3398+ // can be seeded
3399+ int[] arr;
3400+ assert(arr.minElement(1) == 1);
3401+}
3402+
3403+@safe pure unittest
3404+{
3405+ import std.range : enumerate, iota;
3406+ // supports mapping
3407+ assert([3, 4, 5, 1, 2].enumerate.minElement!"a.value" == tuple(3, 1));
3408+ assert([5, 2, 4].enumerate.minElement!"a.value" == tuple(1, 2));
3409+
3410+ // forward ranges
3411+ assert(iota(1, 5).minElement() == 1);
3412+ assert(iota(2, 5).enumerate.minElement!"a.value" == tuple(0, 2));
3413+
3414+ // should work with const
3415+ const(int)[] immArr = [2, 1, 3];
3416+ assert(immArr.minElement == 1);
3417+
3418+ // should work with immutable
3419+ immutable(int)[] immArr2 = [2, 1, 3];
3420+ assert(immArr2.minElement == 1);
3421+
3422+ // with strings
3423+ assert(["b", "a", "c"].minElement == "a");
3424+
3425+ // with all dummy ranges
3426+ import std.internal.test.dummyrange;
3427+ foreach (DummyType; AllDummyRanges)
3428+ {
3429+ DummyType d;
3430+ assert(d.minElement == 1);
3431+ assert(d.minElement!(a => a) == 1);
3432+ }
3433+
3434+ // with empty, but seeded ranges
3435+ int[] arr;
3436+ assert(arr.minElement(42) == 42);
3437+ assert(arr.minElement!(a => a)(42) == 42);
3438+}
3439+
3440+@nogc @safe nothrow pure unittest
3441+{
3442+ static immutable arr = [7, 3, 4, 2, 1, 8];
3443+ assert(arr.minElement == 1);
3444+
3445+ static immutable arr2d = [[1, 9], [3, 1], [4, 2]];
3446+ assert(arr2d.minElement!"a[1]" == arr2d[1]);
3447+}
3448+
3449+/**
3450+Iterates the passed range and returns the maximal element.
3451+A custom mapping function can be passed to `map`.
3452+In other languages this is sometimes called `argmax`.
3453+
3454+Complexity:
3455+ Exactly `n - 1` comparisons are needed.
3456+
3457+Params:
3458+ map = custom accessor for the comparison key
3459+ r = range from which the maximum will be selected
3460+ seed = custom seed to use as initial element
3461+
3462+Returns: The maximal element of the passed-in range.
3463+
3464+See_Also:
3465+ $(REF max, std,algorithm,comparison)
3466+*/
3467+auto maxElement(alias map, Range)(Range r)
3468+if (isInputRange!Range && !isInfinite!Range)
3469+{
3470+ return extremum!(map, "a > b")(r);
3471+}
3472+
3473+/// ditto
3474+auto maxElement(Range)(Range r)
3475+if (isInputRange!Range && !isInfinite!Range)
3476+{
3477+ return extremum!`a > b`(r);
3478+}
3479+
3480+/// ditto
3481+auto maxElement(alias map, Range, RangeElementType = ElementType!Range)
3482+ (Range r, RangeElementType seed)
3483+if (isInputRange!Range && !isInfinite!Range &&
3484+ !is(CommonType!(ElementType!Range, RangeElementType) == void))
3485+{
3486+ return extremum!(map, "a > b")(r, seed);
3487+}
3488+
3489+/// ditto
3490+auto maxElement(Range, RangeElementType = ElementType!Range)
3491+ (Range r, RangeElementType seed)
3492+if (isInputRange!Range && !isInfinite!Range &&
3493+ !is(CommonType!(ElementType!Range, RangeElementType) == void))
3494+{
3495+ return extremum!`a > b`(r, seed);
3496+}
3497+
3498+///
3499+@safe pure unittest
3500+{
3501+ import std.range : enumerate;
3502+ import std.typecons : tuple;
3503+ assert([2, 1, 4, 3].maxElement == 4);
3504+
3505+ // allows to get the index of an element too
3506+ assert([2, 1, 4, 3].enumerate.maxElement!"a.value" == tuple(2, 4));
3507+
3508+ // any custom accessor can be passed
3509+ assert([[0, 4], [1, 2]].maxElement!"a[1]" == [0, 4]);
3510+
3511+ // can be seeded
3512+ int[] arr;
3513+ assert(arr.minElement(1) == 1);
3514+}
3515+
3516+@safe pure unittest
3517+{
3518+ import std.range : enumerate, iota;
3519+
3520+ // supports mapping
3521+ assert([3, 4, 5, 1, 2].enumerate.maxElement!"a.value" == tuple(2, 5));
3522+ assert([5, 2, 4].enumerate.maxElement!"a.value" == tuple(0, 5));
3523+
3524+ // forward ranges
3525+ assert(iota(1, 5).maxElement() == 4);
3526+ assert(iota(2, 5).enumerate.maxElement!"a.value" == tuple(2, 4));
3527+ assert(iota(4, 14).enumerate.maxElement!"a.value" == tuple(9, 13));
3528+
3529+ // should work with const
3530+ const(int)[] immArr = [2, 3, 1];
3531+ assert(immArr.maxElement == 3);
3532+
3533+ // should work with immutable
3534+ immutable(int)[] immArr2 = [2, 3, 1];
3535+ assert(immArr2.maxElement == 3);
3536+
3537+ // with strings
3538+ assert(["a", "c", "b"].maxElement == "c");
3539+
3540+ // with all dummy ranges
3541+ import std.internal.test.dummyrange;
3542+ foreach (DummyType; AllDummyRanges)
3543+ {
3544+ DummyType d;
3545+ assert(d.maxElement == 10);
3546+ assert(d.maxElement!(a => a) == 10);
3547+ }
3548+
3549+ // with empty, but seeded ranges
3550+ int[] arr;
3551+ assert(arr.maxElement(42) == 42);
3552+ assert(arr.maxElement!(a => a)(42) == 42);
3553+
3554+}
3555+
3556+@nogc @safe nothrow pure unittest
3557+{
3558+ static immutable arr = [7, 3, 8, 2, 1, 4];
3559+ assert(arr.maxElement == 8);
3560+
3561+ static immutable arr2d = [[1, 3], [3, 9], [4, 2]];
3562+ assert(arr2d.maxElement!"a[1]" == arr2d[1]);
3563+}
3564+
3565+// minPos
3566+/**
3567+Computes a subrange of `range` starting at the first occurrence of `range`'s
3568+minimum (respectively maximum) and with the same ending as `range`, or the
3569+empty range if `range` itself is empty.
3570+
3571+Formally, the minimum is a value `x` in `range` such that $(D pred(a, x)) is
3572+`false` for all values `a` in `range`. Conversely, the maximum is a value `x` in
3573+`range` such that $(D pred(x, a)) is `false` for all values `a` in `range` (note
3574+the swapped arguments to `pred`).
3575+
3576+These functions may be used for computing arbitrary extrema by choosing `pred`
3577+appropriately. For corrrect functioning, `pred` must be a strict partial order,
3578+i.e. transitive (if $(D pred(a, b) && pred(b, c)) then $(D pred(a, c))) and
3579+irreflexive ($(D pred(a, a)) is `false`).
3580+
3581+Params:
3582+ pred = The ordering predicate to use to determine the extremum (minimum or
3583+ maximum) element.
3584+ range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to search.
3585+
3586+Returns: The position of the minimum (respectively maximum) element of forward
3587+range `range`, i.e. a subrange of `range` starting at the position of its
3588+smallest (respectively largest) element and with the same ending as `range`.
3589+
3590+*/
3591+Range minPos(alias pred = "a < b", Range)(Range range)
3592+if (isForwardRange!Range && !isInfinite!Range &&
3593+ is(typeof(binaryFun!pred(range.front, range.front))))
3594+{
3595+ static if (hasSlicing!Range && isRandomAccessRange!Range && hasLength!Range)
3596+ {
3597+ // Prefer index-based access
3598+ size_t pos = 0;
3599+ foreach (i; 1 .. range.length)
3600+ {
3601+ if (binaryFun!pred(range[i], range[pos]))
3602+ {
3603+ pos = i;
3604+ }
3605+ }
3606+ return range[pos .. range.length];
3607+ }
3608+ else
3609+ {
3610+ auto result = range.save;
3611+ if (range.empty) return result;
3612+ for (range.popFront(); !range.empty; range.popFront())
3613+ {
3614+ // Note: Unlike minCount, we do not care to find equivalence, so a
3615+ // single pred call is enough.
3616+ if (binaryFun!pred(range.front, result.front))
3617+ {
3618+ // change the min
3619+ result = range.save;
3620+ }
3621+ }
3622+ return result;
3623+ }
3624+}
3625+
3626+/// Ditto
3627+Range maxPos(alias pred = "a < b", Range)(Range range)
3628+if (isForwardRange!Range && !isInfinite!Range &&
3629+ is(typeof(binaryFun!pred(range.front, range.front))))
3630+{
3631+ return range.minPos!((a, b) => binaryFun!pred(b, a));
3632+}
3633+
3634+///
3635+@safe unittest
3636+{
3637+ int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3638+ // Minimum is 1 and first occurs in position 3
3639+ assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]);
3640+ // Maximum is 4 and first occurs in position 2
3641+ assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]);
3642+}
3643+
3644+@safe unittest
3645+{
3646+ import std.algorithm.comparison : equal;
3647+ import std.internal.test.dummyrange;
3648+
3649+ int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3650+ //Test that an empty range works
3651+ int[] b = a[$..$];
3652+ assert(equal(minPos(b), b));
3653+
3654+ //test with reference range.
3655+ assert( equal( minPos(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])), [0, 2, 0] ) );
3656+}
3657+
3658+@system unittest
3659+{
3660+ //Rvalue range
3661+ import std.algorithm.comparison : equal;
3662+ import std.container : Array;
3663+
3664+ assert(Array!int(2, 3, 4, 1, 2, 4, 1, 1, 2)
3665+ []
3666+ .minPos()
3667+ .equal([ 1, 2, 4, 1, 1, 2 ]));
3668+}
3669+
3670+@safe unittest
3671+{
3672+ //BUG 9299
3673+ immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3674+ // Minimum is 1 and first occurs in position 3
3675+ assert(minPos(a) == [ 1, 2, 4, 1, 1, 2 ]);
3676+ // Maximum is 4 and first occurs in position 5
3677+ assert(minPos!("a > b")(a) == [ 4, 1, 2, 4, 1, 1, 2 ]);
3678+
3679+ immutable(int[])[] b = [ [4], [2, 4], [4], [4] ];
3680+ assert(minPos!("a[0] < b[0]")(b) == [ [2, 4], [4], [4] ]);
3681+}
3682+
3683+/**
3684+Computes the index of the first occurrence of `range`'s minimum element.
3685+
3686+Params:
3687+ pred = The ordering predicate to use to determine the minimum element.
3688+ range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3689+ to search.
3690+
3691+Complexity: O(n)
3692+ Exactly `n - 1` comparisons are needed.
3693+
3694+Returns:
3695+ The index of the first encounter of the minimum element in `range`. If the
3696+ `range` is empty, -1 is returned.
3697+
3698+See_Also:
3699+ $(REF min, std,algorithm,comparison), $(LREF minCount), $(LREF minElement), $(LREF minPos)
3700+ */
3701+sizediff_t minIndex(alias pred = "a < b", Range)(Range range)
3702+if (isForwardRange!Range && !isInfinite!Range &&
3703+ is(typeof(binaryFun!pred(range.front, range.front))))
3704+{
3705+ if (range.empty) return -1;
3706+
3707+ sizediff_t minPos = 0;
3708+
3709+ static if (isRandomAccessRange!Range && hasLength!Range)
3710+ {
3711+ foreach (i; 1 .. range.length)
3712+ {
3713+ if (binaryFun!pred(range[i], range[minPos]))
3714+ {
3715+ minPos = i;
3716+ }
3717+ }
3718+ }
3719+ else
3720+ {
3721+ sizediff_t curPos = 0;
3722+ Unqual!(typeof(range.front)) min = range.front;
3723+ for (range.popFront(); !range.empty; range.popFront())
3724+ {
3725+ ++curPos;
3726+ if (binaryFun!pred(range.front, min))
3727+ {
3728+ min = range.front;
3729+ minPos = curPos;
3730+ }
3731+ }
3732+ }
3733+ return minPos;
3734+}
3735+
3736+///
3737+@safe pure nothrow unittest
3738+{
3739+ int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2];
3740+
3741+ // Minimum is 1 and first occurs in position 3
3742+ assert(a.minIndex == 3);
3743+ // Get maximum index with minIndex
3744+ assert(a.minIndex!"a > b" == 2);
3745+
3746+ // Range is empty, so return value is -1
3747+ int[] b;
3748+ assert(b.minIndex == -1);
3749+
3750+ // Works with more custom types
3751+ struct Dog { int age; }
3752+ Dog[] dogs = [Dog(10), Dog(5), Dog(15)];
3753+ assert(dogs.minIndex!"a.age < b.age" == 1);
3754+}
3755+
3756+@safe pure unittest
3757+{
3758+ // should work with const
3759+ const(int)[] immArr = [2, 1, 3];
3760+ assert(immArr.minIndex == 1);
3761+
3762+ // Works for const ranges too
3763+ const int[] c = [2, 5, 4, 1, 2, 3];
3764+ assert(c.minIndex == 3);
3765+
3766+ // should work with immutable
3767+ immutable(int)[] immArr2 = [2, 1, 3];
3768+ assert(immArr2.minIndex == 1);
3769+
3770+ // with strings
3771+ assert(["b", "a", "c"].minIndex == 1);
3772+
3773+ // infinite range
3774+ import std.range : cycle;
3775+ static assert(!__traits(compiles, cycle([1]).minIndex));
3776+
3777+ // with all dummy ranges
3778+ import std.internal.test.dummyrange : AllDummyRanges;
3779+ foreach (DummyType; AllDummyRanges)
3780+ {
3781+ static if (isForwardRange!DummyType && !isInfinite!DummyType)
3782+ {
3783+ DummyType d;
3784+ d.arr = [5, 3, 7, 2, 1, 4];
3785+ assert(d.minIndex == 4);
3786+
3787+ d.arr = [];
3788+ assert(d.minIndex == -1);
3789+ }
3790+ }
3791+}
3792+
3793+@nogc @safe nothrow pure unittest
3794+{
3795+ static immutable arr = [7, 3, 8, 2, 1, 4];
3796+ assert(arr.minIndex == 4);
3797+
3798+ static immutable arr2d = [[1, 3], [3, 9], [4, 2]];
3799+ assert(arr2d.minIndex!"a[1] < b[1]" == 2);
3800+}
3801+
3802+/**
3803+Computes the index of the first occurrence of `range`'s maximum element.
3804+
3805+Complexity: O(n)
3806+ Exactly `n - 1` comparisons are needed.
3807+
3808+Params:
3809+ pred = The ordering predicate to use to determine the maximum element.
3810+ range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to search.
3811+
3812+Returns:
3813+ The index of the first encounter of the maximum in `range`. If the
3814+ `range` is empty, -1 is returned.
3815+
3816+See_Also:
3817+ $(REF max, std,algorithm,comparison), $(LREF maxCount), $(LREF maxElement), $(LREF maxPos)
3818+ */
3819+sizediff_t maxIndex(alias pred = "a < b", Range)(Range range)
3820+if (isInputRange!Range && !isInfinite!Range &&
3821+ is(typeof(binaryFun!pred(range.front, range.front))))
3822+{
3823+ return range.minIndex!((a, b) => binaryFun!pred(b, a));
3824+}
3825+
3826+///
3827+@safe pure nothrow unittest
3828+{
3829+ // Maximum is 4 and first occurs in position 2
3830+ int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2];
3831+ assert(a.maxIndex == 2);
3832+
3833+ // Empty range
3834+ int[] b;
3835+ assert(b.maxIndex == -1);
3836+
3837+ // Works with more custom types
3838+ struct Dog { int age; }
3839+ Dog[] dogs = [Dog(10), Dog(15), Dog(5)];
3840+ assert(dogs.maxIndex!"a.age < b.age" == 1);
3841+}
3842+
3843+@safe pure unittest
3844+{
3845+ // should work with const
3846+ const(int)[] immArr = [5, 1, 3];
3847+ assert(immArr.maxIndex == 0);
3848+
3849+ // Works for const ranges too
3850+ const int[] c = [2, 5, 4, 1, 2, 3];
3851+ assert(c.maxIndex == 1);
3852+
3853+
3854+ // should work with immutable
3855+ immutable(int)[] immArr2 = [2, 1, 3];
3856+ assert(immArr2.maxIndex == 2);
3857+
3858+ // with strings
3859+ assert(["b", "a", "c"].maxIndex == 2);
3860+
3861+ // infinite range
3862+ import std.range : cycle;
3863+ static assert(!__traits(compiles, cycle([1]).maxIndex));
3864+
3865+ // with all dummy ranges
3866+ import std.internal.test.dummyrange : AllDummyRanges;
3867+ foreach (DummyType; AllDummyRanges)
3868+ {
3869+ static if (isForwardRange!DummyType && !isInfinite!DummyType)
3870+ {
3871+ DummyType d;
3872+
3873+ d.arr = [5, 3, 7, 2, 1, 4];
3874+ assert(d.maxIndex == 2);
3875+
3876+ d.arr = [];
3877+ assert(d.maxIndex == -1);
3878+ }
3879+ }
3880+}
3881+
3882+@nogc @safe nothrow pure unittest
3883+{
3884+ static immutable arr = [7, 3, 8, 2, 1, 4];
3885+ assert(arr.maxIndex == 2);
3886+
3887+ static immutable arr2d = [[1, 3], [3, 9], [4, 2]];
3888+ assert(arr2d.maxIndex!"a[1] < b[1]" == 1);
3889+}
3890+
3891+/**
3892+Skip over the initial portion of the first given range that matches the second
3893+range, or if no second range is given skip over the elements that fullfil pred.
3894+Do nothing if there is no match.
3895+
3896+Params:
3897+ pred = The predicate that determines whether elements from each respective
3898+ range match. Defaults to equality $(D "a == b").
3899+ r1 = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
3900+ move forward.
3901+ r2 = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3902+ representing the initial segment of $(D r1) to skip over.
3903+
3904+Returns:
3905+true if the initial segment of $(D r1) matches $(D r2) or $(D pred) evaluates to true,
3906+and $(D r1) has been advanced to the point past this segment; otherwise false, and
3907+$(D r1) is left in its original position.
3908+ */
3909+bool skipOver(R1, R2)(ref R1 r1, R2 r2)
3910+if (isForwardRange!R1 && isInputRange!R2
3911+ && is(typeof(r1.front == r2.front)))
3912+{
3913+ static if (is(typeof(r1[0 .. $] == r2) : bool)
3914+ && is(typeof(r2.length > r1.length) : bool)
3915+ && is(typeof(r1 = r1[r2.length .. $])))
3916+ {
3917+ if (r2.length > r1.length || r1[0 .. r2.length] != r2)
3918+ {
3919+ return false;
3920+ }
3921+ r1 = r1[r2.length .. $];
3922+ return true;
3923+ }
3924+ else
3925+ {
3926+ return skipOver!((a, b) => a == b)(r1, r2);
3927+ }
3928+}
3929+
3930+/// Ditto
3931+bool skipOver(alias pred, R1, R2)(ref R1 r1, R2 r2)
3932+if (is(typeof(binaryFun!pred(r1.front, r2.front))) &&
3933+ isForwardRange!R1 &&
3934+ isInputRange!R2)
3935+{
3936+ static if (hasLength!R1 && hasLength!R2)
3937+ {
3938+ // Shortcut opportunity!
3939+ if (r2.length > r1.length)
3940+ return false;
3941+ }
3942+ auto r = r1.save;
3943+ while (!r2.empty && !r.empty && binaryFun!pred(r.front, r2.front))
3944+ {
3945+ r.popFront();
3946+ r2.popFront();
3947+ }
3948+ if (r2.empty)
3949+ r1 = r;
3950+ return r2.empty;
3951+}
3952+
3953+/// Ditto
3954+bool skipOver(alias pred, R)(ref R r1)
3955+if (isForwardRange!R &&
3956+ ifTestable!(typeof(r1.front), unaryFun!pred))
3957+{
3958+ if (r1.empty || !unaryFun!pred(r1.front))
3959+ return false;
3960+
3961+ do
3962+ r1.popFront();
3963+ while (!r1.empty && unaryFun!pred(r1.front));
3964+ return true;
3965+}
3966+
3967+///
3968+@safe unittest
3969+{
3970+ import std.algorithm.comparison : equal;
3971+
3972+ auto s1 = "Hello world";
3973+ assert(!skipOver(s1, "Ha"));
3974+ assert(s1 == "Hello world");
3975+ assert(skipOver(s1, "Hell") && s1 == "o world");
3976+
3977+ string[] r1 = ["abc", "def", "hij"];
3978+ dstring[] r2 = ["abc"d];
3979+ assert(!skipOver!((a, b) => a.equal(b))(r1, ["def"d]));
3980+ assert(r1 == ["abc", "def", "hij"]);
3981+ assert(skipOver!((a, b) => a.equal(b))(r1, r2));
3982+ assert(r1 == ["def", "hij"]);
3983+
3984+ import std.ascii : isWhite;
3985+ import std.range.primitives : empty;
3986+
3987+ auto s2 = "\t\tvalue";
3988+ auto s3 = "";
3989+ auto s4 = "\t\t\t";
3990+ assert(s2.skipOver!isWhite && s2 == "value");
3991+ assert(!s3.skipOver!isWhite);
3992+ assert(s4.skipOver!isWhite && s3.empty);
3993+}
3994+
3995+/**
3996+Skip over the first element of the given range if it matches the given element,
3997+otherwise do nothing.
3998+
3999+Params:
4000+ pred = The predicate that determines whether an element from the range
4001+ matches the given element.
4002+
4003+ r = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to skip
4004+ over.
4005+
4006+ e = The element to match.
4007+
4008+Returns:
4009+true if the first element matches the given element according to the given
4010+predicate, and the range has been advanced by one element; otherwise false, and
4011+the range is left untouched.
4012+ */
4013+bool skipOver(R, E)(ref R r, E e)
4014+if (isInputRange!R && is(typeof(r.front == e) : bool))
4015+{
4016+ return skipOver!((a, b) => a == b)(r, e);
4017+}
4018+
4019+/// Ditto
4020+bool skipOver(alias pred, R, E)(ref R r, E e)
4021+if (is(typeof(binaryFun!pred(r.front, e))) && isInputRange!R)
4022+{
4023+ if (r.empty || !binaryFun!pred(r.front, e))
4024+ return false;
4025+ r.popFront();
4026+ return true;
4027+}
4028+
4029+///
4030+@safe unittest
4031+{
4032+ import std.algorithm.comparison : equal;
4033+
4034+ auto s1 = "Hello world";
4035+ assert(!skipOver(s1, 'a'));
4036+ assert(s1 == "Hello world");
4037+ assert(skipOver(s1, 'H') && s1 == "ello world");
4038+
4039+ string[] r = ["abc", "def", "hij"];
4040+ dstring e = "abc"d;
4041+ assert(!skipOver!((a, b) => a.equal(b))(r, "def"d));
4042+ assert(r == ["abc", "def", "hij"]);
4043+ assert(skipOver!((a, b) => a.equal(b))(r, e));
4044+ assert(r == ["def", "hij"]);
4045+
4046+ auto s2 = "";
4047+ assert(!s2.skipOver('a'));
4048+}
4049+
4050+/**
4051+Checks whether the given
4052+$(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one
4053+of) the given needle(s) or, if no needles are given,
4054+if its front element fulfils predicate $(D pred).
4055+
4056+Params:
4057+
4058+ pred = Predicate to use in comparing the elements of the haystack and the
4059+ needle(s). Mandatory if no needles are given.
4060+
4061+ doesThisStart = The input range to check.
4062+
4063+ withOneOfThese = The needles against which the range is to be checked,
4064+ which may be individual elements or input ranges of elements.
4065+
4066+ withThis = The single needle to check, which may be either a single element
4067+ or an input range of elements.
4068+
4069+Returns:
4070+
4071+0 if the needle(s) do not occur at the beginning of the given range;
4072+otherwise the position of the matching needle, that is, 1 if the range starts
4073+with $(D withOneOfThese[0]), 2 if it starts with $(D withOneOfThese[1]), and so
4074+on.
4075+
4076+In the case where $(D doesThisStart) starts with multiple of the ranges or
4077+elements in $(D withOneOfThese), then the shortest one matches (if there are
4078+two which match which are of the same length (e.g. $(D "a") and $(D 'a')), then
4079+the left-most of them in the argument
4080+list matches).
4081+
4082+In the case when no needle parameters are given, return $(D true) iff front of
4083+$(D doesThisStart) fulfils predicate $(D pred).
4084+ */
4085+uint startsWith(alias pred = "a == b", Range, Needles...)(Range doesThisStart, Needles withOneOfThese)
4086+if (isInputRange!Range && Needles.length > 1 &&
4087+ is(typeof(.startsWith!pred(doesThisStart, withOneOfThese[0])) : bool ) &&
4088+ is(typeof(.startsWith!pred(doesThisStart, withOneOfThese[1 .. $])) : uint))
4089+{
4090+ alias haystack = doesThisStart;
4091+ alias needles = withOneOfThese;
4092+
4093+ // Make one pass looking for empty ranges in needles
4094+ foreach (i, Unused; Needles)
4095+ {
4096+ // Empty range matches everything
4097+ static if (!is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool))
4098+ {
4099+ if (needles[i].empty) return i + 1;
4100+ }
4101+ }
4102+
4103+ for (; !haystack.empty; haystack.popFront())
4104+ {
4105+ foreach (i, Unused; Needles)
4106+ {
4107+ static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool))
4108+ {
4109+ // Single-element
4110+ if (binaryFun!pred(haystack.front, needles[i]))
4111+ {
4112+ // found, but instead of returning, we just stop searching.
4113+ // This is to account for one-element
4114+ // range matches (consider startsWith("ab", "a",
4115+ // 'a') should return 1, not 2).
4116+ break;
4117+ }
4118+ }
4119+ else
4120+ {
4121+ if (binaryFun!pred(haystack.front, needles[i].front))
4122+ {
4123+ continue;
4124+ }
4125+ }
4126+
4127+ // This code executed on failure to match
4128+ // Out with this guy, check for the others
4129+ uint result = startsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]);
4130+ if (result > i) ++result;
4131+ return result;
4132+ }
4133+
4134+ // If execution reaches this point, then the front matches for all
4135+ // needle ranges, or a needle element has been matched.
4136+ // What we need to do now is iterate, lopping off the front of
4137+ // the range and checking if the result is empty, or finding an
4138+ // element needle and returning.
4139+ // If neither happens, we drop to the end and loop.
4140+ foreach (i, Unused; Needles)
4141+ {
4142+ static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool))
4143+ {
4144+ // Test has passed in the previous loop
4145+ return i + 1;
4146+ }
4147+ else
4148+ {
4149+ needles[i].popFront();
4150+ if (needles[i].empty) return i + 1;
4151+ }
4152+ }
4153+ }
4154+ return 0;
4155+}
4156+
4157+/// Ditto
4158+bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis)
4159+if (isInputRange!R1 &&
4160+ isInputRange!R2 &&
4161+ is(typeof(binaryFun!pred(doesThisStart.front, withThis.front)) : bool))
4162+{
4163+ alias haystack = doesThisStart;
4164+ alias needle = withThis;
4165+
4166+ static if (is(typeof(pred) : string))
4167+ enum isDefaultPred = pred == "a == b";
4168+ else
4169+ enum isDefaultPred = false;
4170+
4171+ //Note: While narrow strings don't have a "true" length, for a narrow string to start with another
4172+ //narrow string *of the same type*, it must have *at least* as many code units.
4173+ static if ((hasLength!R1 && hasLength!R2) ||
4174+ (isNarrowString!R1 && isNarrowString!R2 && ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof))
4175+ {
4176+ if (haystack.length < needle.length)
4177+ return false;
4178+ }
4179+
4180+ static if (isDefaultPred && isArray!R1 && isArray!R2 &&
4181+ is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2)))
4182+ {
4183+ //Array slice comparison mode
4184+ return haystack[0 .. needle.length] == needle;
4185+ }
4186+ else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2)
4187+ {
4188+ //RA dual indexing mode
4189+ foreach (j; 0 .. needle.length)
4190+ {
4191+ if (!binaryFun!pred(haystack[j], needle[j]))
4192+ // not found
4193+ return false;
4194+ }
4195+ // found!
4196+ return true;
4197+ }
4198+ else
4199+ {
4200+ //Standard input range mode
4201+ if (needle.empty) return true;
4202+ static if (hasLength!R1 && hasLength!R2)
4203+ {
4204+ //We have previously checked that haystack.length > needle.length,
4205+ //So no need to check haystack.empty during iteration
4206+ for ( ; ; haystack.popFront() )
4207+ {
4208+ if (!binaryFun!pred(haystack.front, needle.front)) break;
4209+ needle.popFront();
4210+ if (needle.empty) return true;
4211+ }
4212+ }
4213+ else
4214+ {
4215+ for ( ; !haystack.empty ; haystack.popFront() )
4216+ {
4217+ if (!binaryFun!pred(haystack.front, needle.front)) break;
4218+ needle.popFront();
4219+ if (needle.empty) return true;
4220+ }
4221+ }
4222+ return false;
4223+ }
4224+}
4225+
4226+/// Ditto
4227+bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis)
4228+if (isInputRange!R &&
4229+ is(typeof(binaryFun!pred(doesThisStart.front, withThis)) : bool))
4230+{
4231+ if (doesThisStart.empty)
4232+ return false;
4233+
4234+ alias predFunc = binaryFun!pred;
4235+
4236+ // auto-decoding special case
4237+ static if (isNarrowString!R)
4238+ {
4239+ // specialize for ASCII as to not change previous behavior
4240+ if (withThis <= 0x7F)
4241+ return predFunc(doesThisStart[0], withThis);
4242+ else
4243+ return predFunc(doesThisStart.front, withThis);
4244+ }
4245+ else
4246+ {
4247+ return predFunc(doesThisStart.front, withThis);
4248+ }
4249+}
4250+
4251+/// Ditto
4252+bool startsWith(alias pred, R)(R doesThisStart)
4253+if (isInputRange!R &&
4254+ ifTestable!(typeof(doesThisStart.front), unaryFun!pred))
4255+{
4256+ return !doesThisStart.empty && unaryFun!pred(doesThisStart.front);
4257+}
4258+
4259+///
4260+@safe unittest
4261+{
4262+ import std.ascii : isAlpha;
4263+
4264+ assert("abc".startsWith!(a => a.isAlpha));
4265+ assert("abc".startsWith!isAlpha);
4266+ assert(!"1ab".startsWith!(a => a.isAlpha));
4267+ assert(!"".startsWith!(a => a.isAlpha));
4268+
4269+ import std.algorithm.comparison : among;
4270+ assert("abc".startsWith!(a => a.among('a', 'b') != 0));
4271+ assert(!"abc".startsWith!(a => a.among('b', 'c') != 0));
4272+
4273+ assert(startsWith("abc", ""));
4274+ assert(startsWith("abc", "a"));
4275+ assert(!startsWith("abc", "b"));
4276+ assert(startsWith("abc", 'a', "b") == 1);
4277+ assert(startsWith("abc", "b", "a") == 2);
4278+ assert(startsWith("abc", "a", "a") == 1);
4279+ assert(startsWith("abc", "ab", "a") == 2);
4280+ assert(startsWith("abc", "x", "a", "b") == 2);
4281+ assert(startsWith("abc", "x", "aa", "ab") == 3);
4282+ assert(startsWith("abc", "x", "aaa", "sab") == 0);
4283+ assert(startsWith("abc", "x", "aaa", "a", "sab") == 3);
4284+
4285+ import std.typecons : Tuple;
4286+ alias C = Tuple!(int, "x", int, "y");
4287+ assert(startsWith!"a.x == b"([ C(1,1), C(1,2), C(2,2) ], [1, 1]));
4288+ assert(startsWith!"a.x == b"([ C(1,1), C(2,1), C(2,2) ], [1, 1], [1, 2], [1, 3]) == 2);
4289+}
4290+
4291+@safe unittest
4292+{
4293+ import std.algorithm.iteration : filter;
4294+ import std.conv : to;
4295+ import std.meta : AliasSeq;
4296+ import std.range;
4297+
4298+ foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
4299+ {
4300+ assert(!startsWith(to!S("abc"), 'c'));
4301+ assert(startsWith(to!S("abc"), 'a', 'c') == 1);
4302+ assert(!startsWith(to!S("abc"), 'x', 'n', 'b'));
4303+ assert(startsWith(to!S("abc"), 'x', 'n', 'a') == 3);
4304+ assert(startsWith(to!S("\uFF28abc"), 'a', '\uFF28', 'c') == 2);
4305+
4306+ foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
4307+ (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
4308+ //Lots of strings
4309+ assert(startsWith(to!S("abc"), to!T("")));
4310+ assert(startsWith(to!S("ab"), to!T("a")));
4311+ assert(startsWith(to!S("abc"), to!T("a")));
4312+ assert(!startsWith(to!S("abc"), to!T("b")));
4313+ assert(!startsWith(to!S("abc"), to!T("b"), "bc", "abcd", "xyz"));
4314+ assert(startsWith(to!S("abc"), to!T("ab"), 'a') == 2);
4315+ assert(startsWith(to!S("abc"), to!T("a"), "b") == 1);
4316+ assert(startsWith(to!S("abc"), to!T("b"), "a") == 2);
4317+ assert(startsWith(to!S("abc"), to!T("a"), 'a') == 1);
4318+ assert(startsWith(to!S("abc"), 'a', to!T("a")) == 1);
4319+ assert(startsWith(to!S("abc"), to!T("x"), "a", "b") == 2);
4320+ assert(startsWith(to!S("abc"), to!T("x"), "aa", "ab") == 3);
4321+ assert(startsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0);
4322+ assert(startsWith(to!S("abc"), 'a'));
4323+ assert(!startsWith(to!S("abc"), to!T("sab")));
4324+ assert(startsWith(to!S("abc"), 'x', to!T("aaa"), 'a', "sab") == 3);
4325+
4326+ //Unicode
4327+ assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("\uFF28el")));
4328+ assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("Hel"), to!T("\uFF28el")) == 2);
4329+ assert(startsWith(to!S("日本語"), to!T("日本")));
4330+ assert(startsWith(to!S("日本語"), to!T("日本語")));
4331+ assert(!startsWith(to!S("日本"), to!T("日本語")));
4332+
4333+ //Empty
4334+ assert(startsWith(to!S(""), T.init));
4335+ assert(!startsWith(to!S(""), 'a'));
4336+ assert(startsWith(to!S("a"), T.init));
4337+ assert(startsWith(to!S("a"), T.init, "") == 1);
4338+ assert(startsWith(to!S("a"), T.init, 'a') == 1);
4339+ assert(startsWith(to!S("a"), 'a', T.init) == 2);
4340+ }();
4341+ }
4342+
4343+ //Length but no RA
4344+ assert(!startsWith("abc".takeExactly(3), "abcd".takeExactly(4)));
4345+ assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(3)));
4346+ assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(1)));
4347+
4348+ foreach (T; AliasSeq!(int, short))
4349+ {
4350+ immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
4351+
4352+ //RA range
4353+ assert(startsWith(arr, cast(int[]) null));
4354+ assert(!startsWith(arr, 5));
4355+ assert(!startsWith(arr, 1));
4356+ assert(startsWith(arr, 0));
4357+ assert(startsWith(arr, 5, 0, 1) == 2);
4358+ assert(startsWith(arr, [0]));
4359+ assert(startsWith(arr, [0, 1]));
4360+ assert(startsWith(arr, [0, 1], 7) == 1);
4361+ assert(!startsWith(arr, [0, 1, 7]));
4362+ assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2);
4363+
4364+ //Normal input range
4365+ assert(!startsWith(filter!"true"(arr), 1));
4366+ assert(startsWith(filter!"true"(arr), 0));
4367+ assert(startsWith(filter!"true"(arr), [0]));
4368+ assert(startsWith(filter!"true"(arr), [0, 1]));
4369+ assert(startsWith(filter!"true"(arr), [0, 1], 7) == 1);
4370+ assert(!startsWith(filter!"true"(arr), [0, 1, 7]));
4371+ assert(startsWith(filter!"true"(arr), [0, 1, 7], [0, 1, 2]) == 2);
4372+ assert(startsWith(arr, filter!"true"([0, 1])));
4373+ assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1);
4374+ assert(!startsWith(arr, filter!"true"([0, 1, 7])));
4375+ assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2);
4376+
4377+ //Non-default pred
4378+ assert(startsWith!("a%10 == b%10")(arr, [10, 11]));
4379+ assert(!startsWith!("a%10 == b%10")(arr, [10, 12]));
4380+ }
4381+}
4382+
4383+/* (Not yet documented.)
4384+Consume all elements from $(D r) that are equal to one of the elements
4385+$(D es).
4386+ */
4387+private void skipAll(alias pred = "a == b", R, Es...)(ref R r, Es es)
4388+//if (is(typeof(binaryFun!pred(r1.front, es[0]))))
4389+{
4390+ loop:
4391+ for (; !r.empty; r.popFront())
4392+ {
4393+ foreach (i, E; Es)
4394+ {
4395+ if (binaryFun!pred(r.front, es[i]))
4396+ {
4397+ continue loop;
4398+ }
4399+ }
4400+ break;
4401+ }
4402+}
4403+
4404+@safe unittest
4405+{
4406+ auto s1 = "Hello world";
4407+ skipAll(s1, 'H', 'e');
4408+ assert(s1 == "llo world");
4409+}
4410+
4411+/**
4412+Interval option specifier for `until` (below) and others.
4413+
4414+If set to $(D OpenRight.yes), then the interval is open to the right
4415+(last element is not included).
4416+
4417+Otherwise if set to $(D OpenRight.no), then the interval is closed to the right
4418+(last element included).
4419+ */
4420+alias OpenRight = Flag!"openRight";
4421+
4422+/**
4423+Lazily iterates $(D range) _until the element $(D e) for which
4424+$(D pred(e, sentinel)) is true.
4425+
4426+This is similar to `takeWhile` in other languages.
4427+
4428+Params:
4429+ pred = Predicate to determine when to stop.
4430+ range = The $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives)
4431+ to iterate over.
4432+ sentinel = The element to stop at.
4433+ openRight = Determines whether the element for which the given predicate is
4434+ true should be included in the resulting range ($(D No.openRight)), or
4435+ not ($(D Yes.openRight)).
4436+
4437+Returns:
4438+ An $(REF_ALTTEXT input _range, isInputRange, std,_range,primitives) that
4439+ iterates over the original range's elements, but ends when the specified
4440+ predicate becomes true. If the original range is a
4441+ $(REF_ALTTEXT forward _range, isForwardRange, std,_range,primitives) or
4442+ higher, this range will be a forward range.
4443+ */
4444+Until!(pred, Range, Sentinel)
4445+until(alias pred = "a == b", Range, Sentinel)
4446+(Range range, Sentinel sentinel, OpenRight openRight = Yes.openRight)
4447+if (!is(Sentinel == OpenRight))
4448+{
4449+ return typeof(return)(range, sentinel, openRight);
4450+}
4451+
4452+/// Ditto
4453+Until!(pred, Range, void)
4454+until(alias pred, Range)
4455+(Range range, OpenRight openRight = Yes.openRight)
4456+{
4457+ return typeof(return)(range, openRight);
4458+}
4459+
4460+/// ditto
4461+struct Until(alias pred, Range, Sentinel)
4462+if (isInputRange!Range)
4463+{
4464+ private Range _input;
4465+ static if (!is(Sentinel == void))
4466+ private Sentinel _sentinel;
4467+ private OpenRight _openRight;
4468+ private bool _done;
4469+
4470+ static if (!is(Sentinel == void))
4471+ ///
4472+ this(Range input, Sentinel sentinel,
4473+ OpenRight openRight = Yes.openRight)
4474+ {
4475+ _input = input;
4476+ _sentinel = sentinel;
4477+ _openRight = openRight;
4478+ _done = _input.empty || openRight && predSatisfied();
4479+ }
4480+ else
4481+ ///
4482+ this(Range input, OpenRight openRight = Yes.openRight)
4483+ {
4484+ _input = input;
4485+ _openRight = openRight;
4486+ _done = _input.empty || openRight && predSatisfied();
4487+ }
4488+
4489+ ///
4490+ @property bool empty()
4491+ {
4492+ return _done;
4493+ }
4494+
4495+ ///
4496+ @property auto ref front()
4497+ {
4498+ assert(!empty);
4499+ return _input.front;
4500+ }
4501+
4502+ private bool predSatisfied()
4503+ {
4504+ static if (is(Sentinel == void))
4505+ return cast(bool) unaryFun!pred(_input.front);
4506+ else
4507+ return cast(bool) startsWith!pred(_input, _sentinel);
4508+ }
4509+
4510+ ///
4511+ void popFront()
4512+ {
4513+ assert(!empty);
4514+ if (!_openRight)
4515+ {
4516+ _done = predSatisfied();
4517+ _input.popFront();
4518+ _done = _done || _input.empty;
4519+ }
4520+ else
4521+ {
4522+ _input.popFront();
4523+ _done = _input.empty || predSatisfied();
4524+ }
4525+ }
4526+
4527+ static if (isForwardRange!Range)
4528+ {
4529+ static if (!is(Sentinel == void))
4530+ ///
4531+ @property Until save()
4532+ {
4533+ Until result = this;
4534+ result._input = _input.save;
4535+ result._sentinel = _sentinel;
4536+ result._openRight = _openRight;
4537+ result._done = _done;
4538+ return result;
4539+ }
4540+ else
4541+ ///
4542+ @property Until save()
4543+ {
4544+ Until result = this;
4545+ result._input = _input.save;
4546+ result._openRight = _openRight;
4547+ result._done = _done;
4548+ return result;
4549+ }
4550+ }
4551+}
4552+
4553+///
4554+@safe unittest
4555+{
4556+ import std.algorithm.comparison : equal;
4557+ import std.typecons : No;
4558+ int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
4559+ assert(equal(a.until(7), [1, 2, 4]));
4560+ assert(equal(a.until(7, No.openRight), [1, 2, 4, 7]));
4561+}
4562+
4563+@safe unittest
4564+{
4565+ import std.algorithm.comparison : equal;
4566+ int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
4567+
4568+ static assert(isForwardRange!(typeof(a.until(7))));
4569+ static assert(isForwardRange!(typeof(until!"a == 2"(a, No.openRight))));
4570+
4571+ assert(equal(a.until(7), [1, 2, 4]));
4572+ assert(equal(a.until([7, 2]), [1, 2, 4, 7]));
4573+ assert(equal(a.until(7, No.openRight), [1, 2, 4, 7]));
4574+ assert(equal(until!"a == 2"(a, No.openRight), [1, 2]));
4575+}
4576+
4577+@system unittest // bugzilla 13171
4578+{
4579+ import std.algorithm.comparison : equal;
4580+ import std.range;
4581+ auto a = [1, 2, 3, 4];
4582+ assert(equal(refRange(&a).until(3, No.openRight), [1, 2, 3]));
4583+ assert(a == [4]);
4584+}
4585+
4586+@safe unittest // Issue 10460
4587+{
4588+ import std.algorithm.comparison : equal;
4589+ auto a = [1, 2, 3, 4];
4590+ foreach (ref e; a.until(3))
4591+ e = 0;
4592+ assert(equal(a, [0, 0, 3, 4]));
4593+}
4594+
4595+@safe unittest // Issue 13124
4596+{
4597+ import std.algorithm.comparison : among, equal;
4598+ auto s = "hello how\nare you";
4599+ assert(equal(s.until!(c => c.among!('\n', '\r')), "hello how"));
4600+}
gcc/libphobos/src/std/algorithm/setops.d+1521−0
@@ -0,0 +1,1521 @@
1+// Written in the D programming language.
2+/**
3+This is a submodule of $(MREF std, algorithm).
4+It contains generic algorithms that implement set operations.
5+
6+The functions $(LREF multiwayMerge), $(LREF multiwayUnion), $(LREF setDifference),
7+$(LREF setIntersection), $(LREF setSymmetricDifference) expect a range of sorted
8+ranges as input.
9+
10+All algorithms are generalized to accept as input not only sets but also
11+$(HTTP https://en.wikipedia.org/wiki/Multiset, multisets). Each algorithm
12+documents behaviour in the presence of duplicated inputs.
13+
14+$(SCRIPT inhibitQuickIndex = 1;)
15+$(BOOKTABLE Cheat Sheet,
16+$(TR $(TH Function Name) $(TH Description))
17+$(T2 cartesianProduct,
18+ Computes Cartesian product of two ranges.)
19+$(T2 largestPartialIntersection,
20+ Copies out the values that occur most frequently in a range of ranges.)
21+$(T2 largestPartialIntersectionWeighted,
22+ Copies out the values that occur most frequently (multiplied by
23+ per-value weights) in a range of ranges.)
24+$(T2 multiwayMerge,
25+ Merges a range of sorted ranges.)
26+$(T2 multiwayUnion,
27+ Computes the union of a range of sorted ranges.)
28+$(T2 setDifference,
29+ Lazily computes the set difference of two or more sorted ranges.)
30+$(T2 setIntersection,
31+ Lazily computes the intersection of two or more sorted ranges.)
32+$(T2 setSymmetricDifference,
33+ Lazily computes the symmetric set difference of two or more sorted
34+ ranges.)
35+)
36+
37+Copyright: Andrei Alexandrescu 2008-.
38+
39+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
40+
41+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
42+
43+Source: $(PHOBOSSRC std/algorithm/_setops.d)
44+
45+Macros:
46+T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
47+ */
48+module std.algorithm.setops;
49+
50+import std.range.primitives;
51+
52+// FIXME
53+import std.functional; // : unaryFun, binaryFun;
54+import std.traits;
55+// FIXME
56+import std.meta; // : AliasSeq, staticMap, allSatisfy, anySatisfy;
57+
58+import std.algorithm.sorting; // : Merge;
59+import std.typecons : No;
60+
61+// cartesianProduct
62+/**
63+Lazily computes the Cartesian product of two or more ranges. The product is a
64+_range of tuples of elements from each respective range.
65+
66+The conditions for the two-range case are as follows:
67+
68+If both ranges are finite, then one must be (at least) a
69+$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and the
70+other an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
71+
72+If one _range is infinite and the other finite, then the finite _range must
73+be a forward _range, and the infinite range can be an input _range.
74+
75+If both ranges are infinite, then both must be forward ranges.
76+
77+When there are more than two ranges, the above conditions apply to each
78+adjacent pair of ranges.
79+
80+Params:
81+ range1 = The first range
82+ range2 = The second range
83+ ranges = Two or more non-infinite forward ranges
84+ otherRanges = Zero or more non-infinite forward ranges
85+
86+Returns:
87+ A forward range of $(REF Tuple, std,typecons) representing elements of the
88+ cartesian product of the given ranges.
89+*/
90+auto cartesianProduct(R1, R2)(R1 range1, R2 range2)
91+if (!allSatisfy!(isForwardRange, R1, R2) ||
92+ anySatisfy!(isInfinite, R1, R2))
93+{
94+ import std.algorithm.iteration : map, joiner;
95+
96+ static if (isInfinite!R1 && isInfinite!R2)
97+ {
98+ static if (isForwardRange!R1 && isForwardRange!R2)
99+ {
100+ import std.range : zip, repeat, take, chain, sequence;
101+
102+ // This algorithm traverses the cartesian product by alternately
103+ // covering the right and bottom edges of an increasing square area
104+ // over the infinite table of combinations. This schedule allows us
105+ // to require only forward ranges.
106+ return zip(sequence!"n"(cast(size_t) 0), range1.save, range2.save,
107+ repeat(range1), repeat(range2))
108+ .map!(function(a) => chain(
109+ zip(repeat(a[1]), take(a[4].save, a[0])),
110+ zip(take(a[3].save, a[0]+1), repeat(a[2]))
111+ ))()
112+ .joiner();
113+ }
114+ else static assert(0, "cartesianProduct of infinite ranges requires "~
115+ "forward ranges");
116+ }
117+ else static if (isInputRange!R1 && isForwardRange!R2 && !isInfinite!R2)
118+ {
119+ import std.range : zip, repeat;
120+ return joiner(map!((ElementType!R1 a) => zip(repeat(a), range2.save))
121+ (range1));
122+ }
123+ else static if (isInputRange!R2 && isForwardRange!R1 && !isInfinite!R1)
124+ {
125+ import std.range : zip, repeat;
126+ return joiner(map!((ElementType!R2 a) => zip(range1.save, repeat(a)))
127+ (range2));
128+ }
129+ else static assert(0, "cartesianProduct involving finite ranges must "~
130+ "have at least one finite forward range");
131+}
132+
133+///
134+@safe unittest
135+{
136+ import std.algorithm.searching : canFind;
137+ import std.range;
138+ import std.typecons : tuple;
139+
140+ auto N = sequence!"n"(0); // the range of natural numbers
141+ auto N2 = cartesianProduct(N, N); // the range of all pairs of natural numbers
142+
143+ // Various arbitrary number pairs can be found in the range in finite time.
144+ assert(canFind(N2, tuple(0, 0)));
145+ assert(canFind(N2, tuple(123, 321)));
146+ assert(canFind(N2, tuple(11, 35)));
147+ assert(canFind(N2, tuple(279, 172)));
148+}
149+
150+///
151+@safe unittest
152+{
153+ import std.algorithm.searching : canFind;
154+ import std.typecons : tuple;
155+
156+ auto B = [ 1, 2, 3 ];
157+ auto C = [ 4, 5, 6 ];
158+ auto BC = cartesianProduct(B, C);
159+
160+ foreach (n; [[1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6],
161+ [2, 6], [3, 6]])
162+ {
163+ assert(canFind(BC, tuple(n[0], n[1])));
164+ }
165+}
166+
167+@safe unittest
168+{
169+ // Test cartesian product of two infinite ranges
170+ import std.algorithm.searching : canFind;
171+ import std.range;
172+ import std.typecons : tuple;
173+
174+ auto Even = sequence!"2*n"(0);
175+ auto Odd = sequence!"2*n+1"(0);
176+ auto EvenOdd = cartesianProduct(Even, Odd);
177+
178+ foreach (pair; [[0, 1], [2, 1], [0, 3], [2, 3], [4, 1], [4, 3], [0, 5],
179+ [2, 5], [4, 5], [6, 1], [6, 3], [6, 5]])
180+ {
181+ assert(canFind(EvenOdd, tuple(pair[0], pair[1])));
182+ }
183+
184+ // This should terminate in finite time
185+ assert(canFind(EvenOdd, tuple(124, 73)));
186+ assert(canFind(EvenOdd, tuple(0, 97)));
187+ assert(canFind(EvenOdd, tuple(42, 1)));
188+}
189+
190+@safe unittest
191+{
192+ // Test cartesian product of an infinite input range and a finite forward
193+ // range.
194+ import std.algorithm.searching : canFind;
195+ import std.range;
196+ import std.typecons : tuple;
197+
198+ auto N = sequence!"n"(0);
199+ auto M = [100, 200, 300];
200+ auto NM = cartesianProduct(N,M);
201+
202+ foreach (pair; [[0, 100], [0, 200], [0, 300], [1, 100], [1, 200], [1, 300],
203+ [2, 100], [2, 200], [2, 300], [3, 100], [3, 200],
204+ [3, 300]])
205+ {
206+ assert(canFind(NM, tuple(pair[0], pair[1])));
207+ }
208+
209+ // We can't solve the halting problem, so we can only check a finite
210+ // initial segment here.
211+ assert(!canFind(NM.take(100), tuple(100, 0)));
212+ assert(!canFind(NM.take(100), tuple(1, 1)));
213+ assert(!canFind(NM.take(100), tuple(100, 200)));
214+
215+ auto MN = cartesianProduct(M,N);
216+ foreach (pair; [[100, 0], [200, 0], [300, 0], [100, 1], [200, 1], [300, 1],
217+ [100, 2], [200, 2], [300, 2], [100, 3], [200, 3],
218+ [300, 3]])
219+ {
220+ assert(canFind(MN, tuple(pair[0], pair[1])));
221+ }
222+
223+ // We can't solve the halting problem, so we can only check a finite
224+ // initial segment here.
225+ assert(!canFind(MN.take(100), tuple(0, 100)));
226+ assert(!canFind(MN.take(100), tuple(0, 1)));
227+ assert(!canFind(MN.take(100), tuple(100, 200)));
228+}
229+
230+@safe unittest
231+{
232+ import std.algorithm.searching : canFind;
233+ import std.typecons : tuple;
234+
235+ // Test cartesian product of two finite ranges.
236+ auto X = [1, 2, 3];
237+ auto Y = [4, 5, 6];
238+ auto XY = cartesianProduct(X, Y);
239+ auto Expected = [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4],
240+ [3, 5], [3, 6]];
241+
242+ // Verify Expected ⊆ XY
243+ foreach (pair; Expected)
244+ {
245+ assert(canFind(XY, tuple(pair[0], pair[1])));
246+ }
247+
248+ // Verify XY ⊆ Expected
249+ foreach (pair; XY)
250+ {
251+ assert(canFind(Expected, [pair[0], pair[1]]));
252+ }
253+
254+ // And therefore, by set comprehension, XY == Expected
255+}
256+
257+@safe unittest
258+{
259+ import std.algorithm.comparison : equal;
260+ import std.algorithm.iteration : map;
261+ import std.algorithm.searching : canFind;
262+ import std.typecons : tuple;
263+
264+ import std.range;
265+ auto N = sequence!"n"(0);
266+
267+ // To force the template to fall to the second case, we wrap N in a struct
268+ // that doesn't allow bidirectional access.
269+ struct FwdRangeWrapper(R)
270+ {
271+ R impl;
272+
273+ // Input range API
274+ @property auto front() { return impl.front; }
275+ void popFront() { impl.popFront(); }
276+ static if (isInfinite!R)
277+ enum empty = false;
278+ else
279+ @property bool empty() { return impl.empty; }
280+
281+ // Forward range API
282+ @property auto save() { return typeof(this)(impl.save); }
283+ }
284+ auto fwdWrap(R)(R range) { return FwdRangeWrapper!R(range); }
285+
286+ // General test: two infinite bidirectional ranges
287+ auto N2 = cartesianProduct(N, N);
288+
289+ assert(canFind(N2, tuple(0, 0)));
290+ assert(canFind(N2, tuple(123, 321)));
291+ assert(canFind(N2, tuple(11, 35)));
292+ assert(canFind(N2, tuple(279, 172)));
293+
294+ // Test first case: forward range with bidirectional range
295+ auto fwdN = fwdWrap(N);
296+ auto N2_a = cartesianProduct(fwdN, N);
297+
298+ assert(canFind(N2_a, tuple(0, 0)));
299+ assert(canFind(N2_a, tuple(123, 321)));
300+ assert(canFind(N2_a, tuple(11, 35)));
301+ assert(canFind(N2_a, tuple(279, 172)));
302+
303+ // Test second case: bidirectional range with forward range
304+ auto N2_b = cartesianProduct(N, fwdN);
305+
306+ assert(canFind(N2_b, tuple(0, 0)));
307+ assert(canFind(N2_b, tuple(123, 321)));
308+ assert(canFind(N2_b, tuple(11, 35)));
309+ assert(canFind(N2_b, tuple(279, 172)));
310+
311+ // Test third case: finite forward range with (infinite) input range
312+ static struct InpRangeWrapper(R)
313+ {
314+ R impl;
315+
316+ // Input range API
317+ @property auto front() { return impl.front; }
318+ void popFront() { impl.popFront(); }
319+ static if (isInfinite!R)
320+ enum empty = false;
321+ else
322+ @property bool empty() { return impl.empty; }
323+ }
324+ auto inpWrap(R)(R r) { return InpRangeWrapper!R(r); }
325+
326+ auto inpN = inpWrap(N);
327+ auto B = [ 1, 2, 3 ];
328+ auto fwdB = fwdWrap(B);
329+ auto BN = cartesianProduct(fwdB, inpN);
330+
331+ assert(equal(map!"[a[0],a[1]]"(BN.take(10)), [[1, 0], [2, 0], [3, 0],
332+ [1, 1], [2, 1], [3, 1], [1, 2], [2, 2], [3, 2], [1, 3]]));
333+
334+ // Test fourth case: (infinite) input range with finite forward range
335+ auto NB = cartesianProduct(inpN, fwdB);
336+
337+ assert(equal(map!"[a[0],a[1]]"(NB.take(10)), [[0, 1], [0, 2], [0, 3],
338+ [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1]]));
339+
340+ // General finite range case
341+ auto C = [ 4, 5, 6 ];
342+ auto BC = cartesianProduct(B, C);
343+
344+ foreach (n; [[1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6],
345+ [2, 6], [3, 6]])
346+ {
347+ assert(canFind(BC, tuple(n[0], n[1])));
348+ }
349+}
350+
351+// Issue 13091
352+pure nothrow @safe @nogc unittest
353+{
354+ int[1] a = [1];
355+ foreach (t; cartesianProduct(a[], a[])) {}
356+}
357+
358+/// ditto
359+auto cartesianProduct(RR...)(RR ranges)
360+if (ranges.length >= 2 &&
361+ allSatisfy!(isForwardRange, RR) &&
362+ !anySatisfy!(isInfinite, RR))
363+{
364+ // This overload uses a much less template-heavy implementation when
365+ // all ranges are finite forward ranges, which is the most common use
366+ // case, so that we don't run out of resources too quickly.
367+ //
368+ // For infinite ranges or non-forward ranges, we fall back to the old
369+ // implementation which expands an exponential number of templates.
370+ import std.typecons : tuple;
371+
372+ static struct Result
373+ {
374+ RR ranges;
375+ RR current;
376+ bool empty = true;
377+
378+ this(RR _ranges)
379+ {
380+ ranges = _ranges;
381+ empty = false;
382+ foreach (i, r; ranges)
383+ {
384+ current[i] = r.save;
385+ if (current[i].empty)
386+ empty = true;
387+ }
388+ }
389+ @property auto front()
390+ {
391+ import std.algorithm.internal : algoFormat;
392+ import std.range : iota;
393+ return mixin(algoFormat("tuple(%(current[%d].front%|,%))",
394+ iota(0, current.length)));
395+ }
396+ void popFront()
397+ {
398+ foreach_reverse (i, ref r; current)
399+ {
400+ r.popFront();
401+ if (!r.empty) break;
402+
403+ static if (i == 0)
404+ empty = true;
405+ else
406+ r = ranges[i].save; // rollover
407+ }
408+ }
409+ @property Result save()
410+ {
411+ Result copy = this;
412+ foreach (i, r; ranges)
413+ {
414+ copy.ranges[i] = r.save;
415+ copy.current[i] = current[i].save;
416+ }
417+ return copy;
418+ }
419+ }
420+ static assert(isForwardRange!Result);
421+
422+ return Result(ranges);
423+}
424+
425+@safe unittest
426+{
427+ // Issue 10693: cartesian product of empty ranges should be empty.
428+ int[] a, b, c, d, e;
429+ auto cprod = cartesianProduct(a,b,c,d,e);
430+ assert(cprod.empty);
431+ foreach (_; cprod) {} // should not crash
432+
433+ // Test case where only one of the ranges is empty: the result should still
434+ // be empty.
435+ int[] p=[1], q=[];
436+ auto cprod2 = cartesianProduct(p,p,p,q,p);
437+ assert(cprod2.empty);
438+ foreach (_; cprod2) {} // should not crash
439+}
440+
441+@safe unittest
442+{
443+ // .init value of cartesianProduct should be empty
444+ auto cprod = cartesianProduct([0,0], [1,1], [2,2]);
445+ assert(!cprod.empty);
446+ assert(cprod.init.empty);
447+}
448+
449+@safe unittest
450+{
451+ // Issue 13393
452+ assert(!cartesianProduct([0],[0],[0]).save.empty);
453+}
454+
455+/// ditto
456+auto cartesianProduct(R1, R2, RR...)(R1 range1, R2 range2, RR otherRanges)
457+if (!allSatisfy!(isForwardRange, R1, R2, RR) ||
458+ anySatisfy!(isInfinite, R1, R2, RR))
459+{
460+ /* We implement the n-ary cartesian product by recursively invoking the
461+ * binary cartesian product. To make the resulting range nicer, we denest
462+ * one level of tuples so that a ternary cartesian product, for example,
463+ * returns 3-element tuples instead of nested 2-element tuples.
464+ */
465+ import std.algorithm.internal : algoFormat;
466+ import std.algorithm.iteration : map;
467+ import std.range : iota;
468+
469+ enum string denest = algoFormat("tuple(a[0], %(a[1][%d]%|,%))",
470+ iota(0, otherRanges.length+1));
471+ return map!denest(
472+ cartesianProduct(range1, cartesianProduct(range2, otherRanges))
473+ );
474+}
475+
476+@safe unittest
477+{
478+ import std.algorithm.searching : canFind;
479+ import std.range;
480+ import std.typecons : tuple, Tuple;
481+
482+ auto N = sequence!"n"(0);
483+ auto N3 = cartesianProduct(N, N, N);
484+
485+ // Check that tuples are properly denested
486+ assert(is(ElementType!(typeof(N3)) == Tuple!(size_t,size_t,size_t)));
487+
488+ assert(canFind(N3, tuple(0, 27, 7)));
489+ assert(canFind(N3, tuple(50, 23, 71)));
490+ assert(canFind(N3, tuple(9, 3, 0)));
491+}
492+
493+@safe unittest
494+{
495+ import std.algorithm.searching : canFind;
496+ import std.range;
497+ import std.typecons : tuple, Tuple;
498+
499+ auto N = sequence!"n"(0);
500+ auto N4 = cartesianProduct(N, N, N, N);
501+
502+ // Check that tuples are properly denested
503+ assert(is(ElementType!(typeof(N4)) == Tuple!(size_t,size_t,size_t,size_t)));
504+
505+ assert(canFind(N4, tuple(1, 2, 3, 4)));
506+ assert(canFind(N4, tuple(4, 3, 2, 1)));
507+ assert(canFind(N4, tuple(10, 31, 7, 12)));
508+}
509+
510+// Issue 9878
511+///
512+@safe unittest
513+{
514+ import std.algorithm.comparison : equal;
515+ import std.typecons : tuple;
516+
517+ auto A = [ 1, 2, 3 ];
518+ auto B = [ 'a', 'b', 'c' ];
519+ auto C = [ "x", "y", "z" ];
520+ auto ABC = cartesianProduct(A, B, C);
521+
522+ assert(ABC.equal([
523+ tuple(1, 'a', "x"), tuple(1, 'a', "y"), tuple(1, 'a', "z"),
524+ tuple(1, 'b', "x"), tuple(1, 'b', "y"), tuple(1, 'b', "z"),
525+ tuple(1, 'c', "x"), tuple(1, 'c', "y"), tuple(1, 'c', "z"),
526+ tuple(2, 'a', "x"), tuple(2, 'a', "y"), tuple(2, 'a', "z"),
527+ tuple(2, 'b', "x"), tuple(2, 'b', "y"), tuple(2, 'b', "z"),
528+ tuple(2, 'c', "x"), tuple(2, 'c', "y"), tuple(2, 'c', "z"),
529+ tuple(3, 'a', "x"), tuple(3, 'a', "y"), tuple(3, 'a', "z"),
530+ tuple(3, 'b', "x"), tuple(3, 'b', "y"), tuple(3, 'b', "z"),
531+ tuple(3, 'c', "x"), tuple(3, 'c', "y"), tuple(3, 'c', "z")
532+ ]));
533+}
534+
535+pure @safe nothrow @nogc unittest
536+{
537+ import std.range.primitives : isForwardRange;
538+ int[2] A = [1,2];
539+ auto C = cartesianProduct(A[], A[], A[]);
540+ assert(isForwardRange!(typeof(C)));
541+
542+ C.popFront();
543+ auto front1 = C.front;
544+ auto D = C.save;
545+ C.popFront();
546+ assert(D.front == front1);
547+}
548+
549+// Issue 13935
550+@safe unittest
551+{
552+ import std.algorithm.iteration : map;
553+ auto seq = [1, 2].map!(x => x);
554+ foreach (pair; cartesianProduct(seq, seq)) {}
555+}
556+
557+// largestPartialIntersection
558+/**
559+Given a range of sorted $(REF_ALTTEXT forward ranges, isForwardRange, std,range,primitives)
560+$(D ror), copies to $(D tgt) the elements that are common to most ranges, along with their number
561+of occurrences. All ranges in $(D ror) are assumed to be sorted by $(D
562+less). Only the most frequent $(D tgt.length) elements are returned.
563+
564+Params:
565+ less = The predicate the ranges are sorted by.
566+ ror = A range of forward ranges sorted by `less`.
567+ tgt = The target range to copy common elements to.
568+ sorted = Whether the elements copied should be in sorted order.
569+
570+The function $(D largestPartialIntersection) is useful for
571+e.g. searching an $(LINK2 https://en.wikipedia.org/wiki/Inverted_index,
572+inverted index) for the documents most
573+likely to contain some terms of interest. The complexity of the search
574+is $(BIGOH n * log(tgt.length)), where $(D n) is the sum of lengths of
575+all input ranges. This approach is faster than keeping an associative
576+array of the occurrences and then selecting its top items, and also
577+requires less memory ($(D largestPartialIntersection) builds its
578+result directly in $(D tgt) and requires no extra memory).
579+
580+If at least one of the ranges is a multiset, then all occurences
581+of a duplicate element are taken into account. The result is
582+equivalent to merging all ranges and picking the most frequent
583+$(D tgt.length) elements.
584+
585+Warning: Because $(D largestPartialIntersection) does not allocate
586+extra memory, it will leave $(D ror) modified. Namely, $(D
587+largestPartialIntersection) assumes ownership of $(D ror) and
588+discretionarily swaps and advances elements of it. If you want $(D
589+ror) to preserve its contents after the call, you may want to pass a
590+duplicate to $(D largestPartialIntersection) (and perhaps cache the
591+duplicate in between calls).
592+ */
593+void largestPartialIntersection
594+(alias less = "a < b", RangeOfRanges, Range)
595+(RangeOfRanges ror, Range tgt, SortOutput sorted = No.sortOutput)
596+{
597+ struct UnitWeights
598+ {
599+ static int opIndex(ElementType!(ElementType!RangeOfRanges)) { return 1; }
600+ }
601+ return largestPartialIntersectionWeighted!less(ror, tgt, UnitWeights(),
602+ sorted);
603+}
604+
605+///
606+@system unittest
607+{
608+ import std.typecons : tuple, Tuple;
609+
610+ // Figure which number can be found in most arrays of the set of
611+ // arrays below.
612+ double[][] a =
613+ [
614+ [ 1, 4, 7, 8 ],
615+ [ 1, 7 ],
616+ [ 1, 7, 8],
617+ [ 4 ],
618+ [ 7 ],
619+ ];
620+ auto b = new Tuple!(double, uint)[1];
621+ // it will modify the input range, hence we need to create a duplicate
622+ largestPartialIntersection(a.dup, b);
623+ // First member is the item, second is the occurrence count
624+ assert(b[0] == tuple(7.0, 4u));
625+ // 7.0 occurs in 4 out of 5 inputs, more than any other number
626+
627+ // If more of the top-frequent numbers are needed, just create a larger
628+ // tgt range
629+ auto c = new Tuple!(double, uint)[2];
630+ largestPartialIntersection(a, c);
631+ assert(c[0] == tuple(1.0, 3u));
632+ // 1.0 occurs in 3 inputs
633+
634+ // multiset
635+ double[][] x =
636+ [
637+ [1, 1, 1, 1, 4, 7, 8],
638+ [1, 7],
639+ [1, 7, 8],
640+ [4, 7],
641+ [7]
642+ ];
643+ auto y = new Tuple!(double, uint)[2];
644+ largestPartialIntersection(x.dup, y);
645+ // 7.0 occurs 5 times
646+ assert(y[0] == tuple(7.0, 5u));
647+ // 1.0 occurs 6 times
648+ assert(y[1] == tuple(1.0, 6u));
649+}
650+
651+import std.algorithm.sorting : SortOutput; // FIXME
652+
653+// largestPartialIntersectionWeighted
654+/**
655+Similar to $(D largestPartialIntersection), but associates a weight
656+with each distinct element in the intersection.
657+
658+If at least one of the ranges is a multiset, then all occurences
659+of a duplicate element are taken into account. The result
660+is equivalent to merging all input ranges and picking the highest
661+$(D tgt.length), weight-based ranking elements.
662+
663+Params:
664+ less = The predicate the ranges are sorted by.
665+ ror = A range of $(REF_ALTTEXT forward ranges, isForwardRange, std,range,primitives)
666+ sorted by `less`.
667+ tgt = The target range to copy common elements to.
668+ weights = An associative array mapping elements to weights.
669+ sorted = Whether the elements copied should be in sorted order.
670+
671+*/
672+void largestPartialIntersectionWeighted
673+(alias less = "a < b", RangeOfRanges, Range, WeightsAA)
674+(RangeOfRanges ror, Range tgt, WeightsAA weights, SortOutput sorted = No.sortOutput)
675+{
676+ import std.algorithm.iteration : group;
677+ import std.algorithm.sorting : topNCopy;
678+
679+ if (tgt.empty) return;
680+ alias InfoType = ElementType!Range;
681+ bool heapComp(InfoType a, InfoType b)
682+ {
683+ return weights[a[0]] * a[1] > weights[b[0]] * b[1];
684+ }
685+ topNCopy!heapComp(group(multiwayMerge!less(ror)), tgt, sorted);
686+}
687+
688+///
689+@system unittest
690+{
691+ import std.typecons : tuple, Tuple;
692+
693+ // Figure which number can be found in most arrays of the set of
694+ // arrays below, with specific per-element weights
695+ double[][] a =
696+ [
697+ [ 1, 4, 7, 8 ],
698+ [ 1, 7 ],
699+ [ 1, 7, 8],
700+ [ 4 ],
701+ [ 7 ],
702+ ];
703+ auto b = new Tuple!(double, uint)[1];
704+ double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ];
705+ largestPartialIntersectionWeighted(a, b, weights);
706+ // First member is the item, second is the occurrence count
707+ assert(b[0] == tuple(4.0, 2u));
708+ // 4.0 occurs 2 times -> 4.6 (2 * 2.3)
709+ // 7.0 occurs 3 times -> 4.4 (3 * 1.1)
710+
711+ // multiset
712+ double[][] x =
713+ [
714+ [ 1, 1, 1, 4, 7, 8 ],
715+ [ 1, 7 ],
716+ [ 1, 7, 8],
717+ [ 4 ],
718+ [ 7 ],
719+ ];
720+ auto y = new Tuple!(double, uint)[1];
721+ largestPartialIntersectionWeighted(x, y, weights);
722+ assert(y[0] == tuple(1.0, 5u));
723+ // 1.0 occurs 5 times -> 1.2 * 5 = 6
724+}
725+
726+@system unittest
727+{
728+ import std.conv : text;
729+ import std.typecons : tuple, Tuple, Yes;
730+
731+ double[][] a =
732+ [
733+ [ 1, 4, 7, 8 ],
734+ [ 1, 7 ],
735+ [ 1, 7, 8],
736+ [ 4 ],
737+ [ 7 ],
738+ ];
739+ auto b = new Tuple!(double, uint)[2];
740+ largestPartialIntersection(a, b, Yes.sortOutput);
741+ assert(b == [ tuple(7.0, 4u), tuple(1.0, 3u) ][], text(b));
742+ assert(a[0].empty);
743+}
744+
745+@system unittest
746+{
747+ import std.conv : text;
748+ import std.typecons : tuple, Tuple, Yes;
749+
750+ string[][] a =
751+ [
752+ [ "1", "4", "7", "8" ],
753+ [ "1", "7" ],
754+ [ "1", "7", "8"],
755+ [ "4" ],
756+ [ "7" ],
757+ ];
758+ auto b = new Tuple!(string, uint)[2];
759+ largestPartialIntersection(a, b, Yes.sortOutput);
760+ assert(b == [ tuple("7", 4u), tuple("1", 3u) ][], text(b));
761+}
762+
763+@system unittest
764+{
765+ import std.typecons : tuple, Tuple;
766+
767+ // Figure which number can be found in most arrays of the set of
768+ // arrays below, with specific per-element weights
769+ double[][] a =
770+ [
771+ [ 1, 4, 7, 8 ],
772+ [ 1, 7 ],
773+ [ 1, 7, 8],
774+ [ 4 ],
775+ [ 7 ],
776+ ];
777+ auto b = new Tuple!(double, uint)[1];
778+ double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ];
779+ largestPartialIntersectionWeighted(a, b, weights);
780+ // First member is the item, second is the occurrence count
781+ assert(b[0] == tuple(4.0, 2u));
782+}
783+
784+@system unittest
785+{
786+ import std.container : Array;
787+ import std.typecons : Tuple;
788+
789+ alias T = Tuple!(uint, uint);
790+ const Array!T arrayOne = Array!T( [ T(1,2), T(3,4) ] );
791+ const Array!T arrayTwo = Array!T([ T(1,2), T(3,4) ] );
792+
793+ assert(arrayOne == arrayTwo);
794+}
795+
796+// MultiwayMerge
797+/**
798+Merges multiple sets. The input sets are passed as a
799+range of ranges and each is assumed to be sorted by $(D
800+less). Computation is done lazily, one union element at a time. The
801+complexity of one $(D popFront) operation is $(BIGOH
802+log(ror.length)). However, the length of $(D ror) decreases as ranges
803+in it are exhausted, so the complexity of a full pass through $(D
804+MultiwayMerge) is dependent on the distribution of the lengths of ranges
805+contained within $(D ror). If all ranges have the same length $(D n)
806+(worst case scenario), the complexity of a full pass through $(D
807+MultiwayMerge) is $(BIGOH n * ror.length * log(ror.length)), i.e., $(D
808+log(ror.length)) times worse than just spanning all ranges in
809+turn. The output comes sorted (unstably) by $(D less).
810+
811+The length of the resulting range is the sum of all lengths of
812+the ranges passed as input. This means that all elements (duplicates
813+included) are transferred to the resulting range.
814+
815+For backward compatibility, `multiwayMerge` is available under
816+the name `nWayUnion` and `MultiwayMerge` under the name of `NWayUnion` .
817+Future code should use `multiwayMerge` and `MultiwayMerge` as `nWayUnion`
818+and `NWayUnion` will be deprecated.
819+
820+Params:
821+ less = Predicate the given ranges are sorted by.
822+ ror = A range of ranges sorted by `less` to compute the union for.
823+
824+Returns:
825+ A range of the union of the ranges in `ror`.
826+
827+Warning: Because $(D MultiwayMerge) does not allocate extra memory, it
828+will leave $(D ror) modified. Namely, $(D MultiwayMerge) assumes ownership
829+of $(D ror) and discretionarily swaps and advances elements of it. If
830+you want $(D ror) to preserve its contents after the call, you may
831+want to pass a duplicate to $(D MultiwayMerge) (and perhaps cache the
832+duplicate in between calls).
833+ */
834+struct MultiwayMerge(alias less, RangeOfRanges)
835+{
836+ import std.container : BinaryHeap;
837+
838+ private alias ElementType = .ElementType!(.ElementType!RangeOfRanges);
839+ private alias comp = binaryFun!less;
840+ private RangeOfRanges _ror;
841+
842+ ///
843+ static bool compFront(.ElementType!RangeOfRanges a,
844+ .ElementType!RangeOfRanges b)
845+ {
846+ // revert comparison order so we get the smallest elements first
847+ return comp(b.front, a.front);
848+ }
849+ private BinaryHeap!(RangeOfRanges, compFront) _heap;
850+
851+ ///
852+ this(RangeOfRanges ror)
853+ {
854+ import std.algorithm.mutation : remove, SwapStrategy;
855+
856+ // Preemptively get rid of all empty ranges in the input
857+ // No need for stability either
858+ _ror = remove!("a.empty", SwapStrategy.unstable)(ror);
859+ //Build the heap across the range
860+ _heap.acquire(_ror);
861+ }
862+
863+ ///
864+ @property bool empty() { return _ror.empty; }
865+
866+ ///
867+ @property auto ref front()
868+ {
869+ return _heap.front.front;
870+ }
871+
872+ ///
873+ void popFront()
874+ {
875+ _heap.removeFront();
876+ // let's look at the guy just popped
877+ _ror.back.popFront();
878+ if (_ror.back.empty)
879+ {
880+ _ror.popBack();
881+ // nothing else to do: the empty range is not in the
882+ // heap and not in _ror
883+ return;
884+ }
885+ // Put the popped range back in the heap
886+ _heap.conditionalInsert(_ror.back) || assert(false);
887+ }
888+}
889+
890+/// Ditto
891+MultiwayMerge!(less, RangeOfRanges) multiwayMerge
892+(alias less = "a < b", RangeOfRanges)
893+(RangeOfRanges ror)
894+{
895+ return typeof(return)(ror);
896+}
897+
898+///
899+@system unittest
900+{
901+ import std.algorithm.comparison : equal;
902+
903+ double[][] a =
904+ [
905+ [ 1, 4, 7, 8 ],
906+ [ 1, 7 ],
907+ [ 1, 7, 8],
908+ [ 4 ],
909+ [ 7 ],
910+ ];
911+ auto witness = [
912+ 1, 1, 1, 4, 4, 7, 7, 7, 7, 8, 8
913+ ];
914+ assert(equal(multiwayMerge(a), witness));
915+
916+ double[][] b =
917+ [
918+ // range with duplicates
919+ [ 1, 1, 4, 7, 8 ],
920+ [ 7 ],
921+ [ 1, 7, 8],
922+ [ 4 ],
923+ [ 7 ],
924+ ];
925+ // duplicates are propagated to the resulting range
926+ assert(equal(multiwayMerge(b), witness));
927+}
928+
929+alias nWayUnion = multiwayMerge;
930+alias NWayUnion = MultiwayMerge;
931+
932+/**
933+Computes the union of multiple ranges. The input ranges are passed
934+as a range of ranges and each is assumed to be sorted by $(D
935+less). Computation is done lazily, one union element at a time.
936+`multiwayUnion(ror)` is functionally equivalent to `multiwayMerge(ror).uniq`.
937+
938+"The output of multiwayUnion has no duplicates even when its inputs contain duplicates."
939+
940+Params:
941+ less = Predicate the given ranges are sorted by.
942+ ror = A range of ranges sorted by `less` to compute the intersection for.
943+
944+Returns:
945+ A range of the union of the ranges in `ror`.
946+
947+See also: $(LREF multiwayMerge)
948+ */
949+auto multiwayUnion(alias less = "a < b", RangeOfRanges)(RangeOfRanges ror)
950+{
951+ import std.algorithm.iteration : uniq;
952+ return ror.multiwayMerge.uniq;
953+}
954+
955+///
956+@system unittest
957+{
958+ import std.algorithm.comparison : equal;
959+
960+ // sets
961+ double[][] a =
962+ [
963+ [ 1, 4, 7, 8 ],
964+ [ 1, 7 ],
965+ [ 1, 7, 8],
966+ [ 4 ],
967+ [ 7 ],
968+ ];
969+
970+ auto witness = [1, 4, 7, 8];
971+ assert(equal(multiwayUnion(a), witness));
972+
973+ // multisets
974+ double[][] b =
975+ [
976+ [ 1, 1, 1, 4, 7, 8 ],
977+ [ 1, 7 ],
978+ [ 1, 7, 7, 8],
979+ [ 4 ],
980+ [ 7 ],
981+ ];
982+ assert(equal(multiwayUnion(b), witness));
983+}
984+
985+/**
986+Lazily computes the difference of $(D r1) and $(D r2). The two ranges
987+are assumed to be sorted by $(D less). The element types of the two
988+ranges must have a common type.
989+
990+
991+In the case of multisets, considering that element `a` appears `x`
992+times in $(D r1) and `y` times and $(D r2), the number of occurences
993+of `a` in the resulting range is going to be `x-y` if x > y or 0 othwerise.
994+
995+Params:
996+ less = Predicate the given ranges are sorted by.
997+ r1 = The first range.
998+ r2 = The range to subtract from `r1`.
999+
1000+Returns:
1001+ A range of the difference of `r1` and `r2`.
1002+
1003+See_also: $(LREF setSymmetricDifference)
1004+ */
1005+struct SetDifference(alias less = "a < b", R1, R2)
1006+if (isInputRange!(R1) && isInputRange!(R2))
1007+{
1008+private:
1009+ R1 r1;
1010+ R2 r2;
1011+ alias comp = binaryFun!(less);
1012+
1013+ void adjustPosition()
1014+ {
1015+ while (!r1.empty)
1016+ {
1017+ if (r2.empty || comp(r1.front, r2.front)) break;
1018+ if (comp(r2.front, r1.front))
1019+ {
1020+ r2.popFront();
1021+ }
1022+ else
1023+ {
1024+ // both are equal
1025+ r1.popFront();
1026+ r2.popFront();
1027+ }
1028+ }
1029+ }
1030+
1031+public:
1032+ ///
1033+ this(R1 r1, R2 r2)
1034+ {
1035+ this.r1 = r1;
1036+ this.r2 = r2;
1037+ // position to the first element
1038+ adjustPosition();
1039+ }
1040+
1041+ ///
1042+ void popFront()
1043+ {
1044+ r1.popFront();
1045+ adjustPosition();
1046+ }
1047+
1048+ ///
1049+ @property auto ref front()
1050+ {
1051+ assert(!empty);
1052+ return r1.front;
1053+ }
1054+
1055+ static if (isForwardRange!R1 && isForwardRange!R2)
1056+ {
1057+ ///
1058+ @property typeof(this) save()
1059+ {
1060+ auto ret = this;
1061+ ret.r1 = r1.save;
1062+ ret.r2 = r2.save;
1063+ return ret;
1064+ }
1065+ }
1066+
1067+ ///
1068+ @property bool empty() { return r1.empty; }
1069+}
1070+
1071+/// Ditto
1072+SetDifference!(less, R1, R2) setDifference(alias less = "a < b", R1, R2)
1073+(R1 r1, R2 r2)
1074+{
1075+ return typeof(return)(r1, r2);
1076+}
1077+
1078+///
1079+@safe unittest
1080+{
1081+ import std.algorithm.comparison : equal;
1082+ import std.range.primitives : isForwardRange;
1083+
1084+ //sets
1085+ int[] a = [ 1, 2, 4, 5, 7, 9 ];
1086+ int[] b = [ 0, 1, 2, 4, 7, 8 ];
1087+ assert(equal(setDifference(a, b), [5, 9]));
1088+ static assert(isForwardRange!(typeof(setDifference(a, b))));
1089+
1090+ // multisets
1091+ int[] x = [1, 1, 1, 2, 3];
1092+ int[] y = [1, 1, 2, 4, 5];
1093+ auto r = setDifference(x, y);
1094+ assert(equal(r, [1, 3]));
1095+ assert(setDifference(r, x).empty);
1096+}
1097+
1098+@safe unittest // Issue 10460
1099+{
1100+ import std.algorithm.comparison : equal;
1101+
1102+ int[] a = [1, 2, 3, 4, 5];
1103+ int[] b = [2, 4];
1104+ foreach (ref e; setDifference(a, b))
1105+ e = 0;
1106+ assert(equal(a, [0, 2, 0, 4, 0]));
1107+}
1108+
1109+/**
1110+Lazily computes the intersection of two or more input ranges $(D
1111+ranges). The ranges are assumed to be sorted by $(D less). The element
1112+types of the ranges must have a common type.
1113+
1114+In the case of multisets, the range with the minimum number of
1115+occurences of a given element, propagates the number of
1116+occurences of this element to the resulting range.
1117+
1118+Params:
1119+ less = Predicate the given ranges are sorted by.
1120+ ranges = The ranges to compute the intersection for.
1121+
1122+Returns:
1123+ A range containing the intersection of the given ranges.
1124+ */
1125+struct SetIntersection(alias less = "a < b", Rs...)
1126+if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) &&
1127+ !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1128+{
1129+private:
1130+ Rs _input;
1131+ alias comp = binaryFun!less;
1132+ alias ElementType = CommonType!(staticMap!(.ElementType, Rs));
1133+
1134+ // Positions to the first elements that are all equal
1135+ void adjustPosition()
1136+ {
1137+ if (empty) return;
1138+
1139+ size_t done = Rs.length;
1140+ static if (Rs.length > 1) while (true)
1141+ {
1142+ foreach (i, ref r; _input)
1143+ {
1144+ alias next = _input[(i + 1) % Rs.length];
1145+
1146+ if (comp(next.front, r.front))
1147+ {
1148+ do
1149+ {
1150+ next.popFront();
1151+ if (next.empty) return;
1152+ } while (comp(next.front, r.front));
1153+ done = Rs.length;
1154+ }
1155+ if (--done == 0) return;
1156+ }
1157+ }
1158+ }
1159+
1160+public:
1161+ ///
1162+ this(Rs input)
1163+ {
1164+ this._input = input;
1165+ // position to the first element
1166+ adjustPosition();
1167+ }
1168+
1169+ ///
1170+ @property bool empty()
1171+ {
1172+ foreach (ref r; _input)
1173+ {
1174+ if (r.empty) return true;
1175+ }
1176+ return false;
1177+ }
1178+
1179+ ///
1180+ void popFront()
1181+ {
1182+ assert(!empty);
1183+ static if (Rs.length > 1) foreach (i, ref r; _input)
1184+ {
1185+ alias next = _input[(i + 1) % Rs.length];
1186+ assert(!comp(r.front, next.front));
1187+ }
1188+
1189+ foreach (ref r; _input)
1190+ {
1191+ r.popFront();
1192+ }
1193+ adjustPosition();
1194+ }
1195+
1196+ ///
1197+ @property ElementType front()
1198+ {
1199+ assert(!empty);
1200+ return _input[0].front;
1201+ }
1202+
1203+ static if (allSatisfy!(isForwardRange, Rs))
1204+ {
1205+ ///
1206+ @property SetIntersection save()
1207+ {
1208+ auto ret = this;
1209+ foreach (i, ref r; _input)
1210+ {
1211+ ret._input[i] = r.save;
1212+ }
1213+ return ret;
1214+ }
1215+ }
1216+}
1217+
1218+/// Ditto
1219+SetIntersection!(less, Rs) setIntersection(alias less = "a < b", Rs...)(Rs ranges)
1220+if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) &&
1221+ !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1222+{
1223+ return typeof(return)(ranges);
1224+}
1225+
1226+///
1227+@safe unittest
1228+{
1229+ import std.algorithm.comparison : equal;
1230+
1231+ // sets
1232+ int[] a = [ 1, 2, 4, 5, 7, 9 ];
1233+ int[] b = [ 0, 1, 2, 4, 7, 8 ];
1234+ int[] c = [ 0, 1, 4, 5, 7, 8 ];
1235+ assert(equal(setIntersection(a, a), a));
1236+ assert(equal(setIntersection(a, b), [1, 2, 4, 7]));
1237+ assert(equal(setIntersection(a, b, c), [1, 4, 7]));
1238+
1239+ // multisets
1240+ int[] d = [ 1, 1, 2, 2, 7, 7 ];
1241+ int[] e = [ 1, 1, 1, 7];
1242+ assert(equal(setIntersection(a, d), [1, 2, 7]));
1243+ assert(equal(setIntersection(d, e), [1, 1, 7]));
1244+}
1245+
1246+@safe unittest
1247+{
1248+ import std.algorithm.comparison : equal;
1249+ import std.algorithm.iteration : filter;
1250+
1251+ int[] a = [ 1, 2, 4, 5, 7, 9 ];
1252+ int[] b = [ 0, 1, 2, 4, 7, 8 ];
1253+ int[] c = [ 0, 1, 4, 5, 7, 8 ];
1254+ int[] d = [ 1, 3, 4 ];
1255+ int[] e = [ 4, 5 ];
1256+
1257+ assert(equal(setIntersection(a, a), a));
1258+ assert(equal(setIntersection(a, a, a), a));
1259+ assert(equal(setIntersection(a, b), [1, 2, 4, 7]));
1260+ assert(equal(setIntersection(a, b, c), [1, 4, 7]));
1261+ assert(equal(setIntersection(a, b, c, d), [1, 4]));
1262+ assert(equal(setIntersection(a, b, c, d, e), [4]));
1263+
1264+ auto inpA = a.filter!(_ => true), inpB = b.filter!(_ => true);
1265+ auto inpC = c.filter!(_ => true), inpD = d.filter!(_ => true);
1266+ assert(equal(setIntersection(inpA, inpB, inpC, inpD), [1, 4]));
1267+
1268+ assert(equal(setIntersection(a, b, b, a), [1, 2, 4, 7]));
1269+ assert(equal(setIntersection(a, c, b), [1, 4, 7]));
1270+ assert(equal(setIntersection(b, a, c), [1, 4, 7]));
1271+ assert(equal(setIntersection(b, c, a), [1, 4, 7]));
1272+ assert(equal(setIntersection(c, a, b), [1, 4, 7]));
1273+ assert(equal(setIntersection(c, b, a), [1, 4, 7]));
1274+}
1275+
1276+/**
1277+Lazily computes the symmetric difference of $(D r1) and $(D r2),
1278+i.e. the elements that are present in exactly one of $(D r1) and $(D
1279+r2). The two ranges are assumed to be sorted by $(D less), and the
1280+output is also sorted by $(D less). The element types of the two
1281+ranges must have a common type.
1282+
1283+If both ranges are sets (without duplicated elements), the resulting
1284+range is going to be a set. If at least one of the ranges is a multiset,
1285+the number of occurences of an element `x` in the resulting range is `abs(a-b)`
1286+where `a` is the number of occurences of `x` in $(D r1), `b` is the number of
1287+occurences of `x` in $(D r2), and `abs` is the absolute value.
1288+
1289+If both arguments are ranges of L-values of the same type then
1290+$(D SetSymmetricDifference) will also be a range of L-values of
1291+that type.
1292+
1293+Params:
1294+ less = Predicate the given ranges are sorted by.
1295+ r1 = The first range.
1296+ r2 = The second range.
1297+
1298+Returns:
1299+ A range of the symmetric difference between `r1` and `r2`.
1300+
1301+See_also: $(LREF setDifference)
1302+ */
1303+struct SetSymmetricDifference(alias less = "a < b", R1, R2)
1304+if (isInputRange!(R1) && isInputRange!(R2))
1305+{
1306+private:
1307+ R1 r1;
1308+ R2 r2;
1309+ //bool usingR2;
1310+ alias comp = binaryFun!(less);
1311+
1312+ void adjustPosition()
1313+ {
1314+ while (!r1.empty && !r2.empty)
1315+ {
1316+ if (comp(r1.front, r2.front) || comp(r2.front, r1.front))
1317+ {
1318+ break;
1319+ }
1320+ // equal, pop both
1321+ r1.popFront();
1322+ r2.popFront();
1323+ }
1324+ }
1325+
1326+public:
1327+ ///
1328+ this(R1 r1, R2 r2)
1329+ {
1330+ this.r1 = r1;
1331+ this.r2 = r2;
1332+ // position to the first element
1333+ adjustPosition();
1334+ }
1335+
1336+ ///
1337+ void popFront()
1338+ {
1339+ assert(!empty);
1340+ if (r1.empty) r2.popFront();
1341+ else if (r2.empty) r1.popFront();
1342+ else
1343+ {
1344+ // neither is empty
1345+ if (comp(r1.front, r2.front))
1346+ {
1347+ r1.popFront();
1348+ }
1349+ else
1350+ {
1351+ assert(comp(r2.front, r1.front));
1352+ r2.popFront();
1353+ }
1354+ }
1355+ adjustPosition();
1356+ }
1357+
1358+ ///
1359+ @property auto ref front()
1360+ {
1361+ assert(!empty);
1362+ immutable chooseR1 = r2.empty || !r1.empty && comp(r1.front, r2.front);
1363+ assert(chooseR1 || r1.empty || comp(r2.front, r1.front));
1364+ return chooseR1 ? r1.front : r2.front;
1365+ }
1366+
1367+ static if (isForwardRange!R1 && isForwardRange!R2)
1368+ {
1369+ ///
1370+ @property typeof(this) save()
1371+ {
1372+ auto ret = this;
1373+ ret.r1 = r1.save;
1374+ ret.r2 = r2.save;
1375+ return ret;
1376+ }
1377+ }
1378+
1379+ ///
1380+ ref auto opSlice() { return this; }
1381+
1382+ ///
1383+ @property bool empty() { return r1.empty && r2.empty; }
1384+}
1385+
1386+/// Ditto
1387+SetSymmetricDifference!(less, R1, R2)
1388+setSymmetricDifference(alias less = "a < b", R1, R2)
1389+(R1 r1, R2 r2)
1390+{
1391+ return typeof(return)(r1, r2);
1392+}
1393+
1394+///
1395+@safe unittest
1396+{
1397+ import std.algorithm.comparison : equal;
1398+ import std.range.primitives : isForwardRange;
1399+
1400+ // sets
1401+ int[] a = [ 1, 2, 4, 5, 7, 9 ];
1402+ int[] b = [ 0, 1, 2, 4, 7, 8 ];
1403+ assert(equal(setSymmetricDifference(a, b), [0, 5, 8, 9][]));
1404+ static assert(isForwardRange!(typeof(setSymmetricDifference(a, b))));
1405+
1406+ //mutisets
1407+ int[] c = [1, 1, 1, 1, 2, 2, 2, 4, 5, 6];
1408+ int[] d = [1, 1, 2, 2, 2, 2, 4, 7, 9];
1409+ assert(equal(setSymmetricDifference(c, d), setSymmetricDifference(d, c)));
1410+ assert(equal(setSymmetricDifference(c, d), [1, 1, 2, 5, 6, 7, 9]));
1411+}
1412+
1413+@safe unittest // Issue 10460
1414+{
1415+ import std.algorithm.comparison : equal;
1416+
1417+ int[] a = [1, 2];
1418+ double[] b = [2.0, 3.0];
1419+ int[] c = [2, 3];
1420+
1421+ alias R1 = typeof(setSymmetricDifference(a, b));
1422+ static assert(is(ElementType!R1 == double));
1423+ static assert(!hasLvalueElements!R1);
1424+
1425+ alias R2 = typeof(setSymmetricDifference(a, c));
1426+ static assert(is(ElementType!R2 == int));
1427+ static assert(hasLvalueElements!R2);
1428+
1429+ assert(equal(setSymmetricDifference(a, b), [1.0, 3.0]));
1430+ assert(equal(setSymmetricDifference(a, c), [1, 3]));
1431+}
1432+
1433+/++
1434+TODO: once SetUnion got deprecated we can provide the usual definition
1435+(= merge + filter after uniqs)
1436+See: https://github.com/dlang/phobos/pull/4249
1437+/**
1438+Lazily computes the union of two or more ranges $(D rs). The ranges
1439+are assumed to be sorted by $(D less). Elements in the output are
1440+unique. The element types of all ranges must have a common type.
1441+
1442+Params:
1443+ less = Predicate the given ranges are sorted by.
1444+ rs = The ranges to compute the union for.
1445+
1446+Returns:
1447+ A range containing the unique union of the given ranges.
1448+
1449+See_Also:
1450+ $(REF merge, std,algorithm,sorting)
1451+ */
1452+auto setUnion(alias less = "a < b", Rs...)
1453+(Rs rs)
1454+{
1455+ import std.algorithm.iteration : uniq;
1456+ import std.algorithm.sorting : merge;
1457+ return merge!(less, Rs)(rs).uniq;
1458+}
1459+
1460+///
1461+@safe pure nothrow unittest
1462+ ///
1463+{
1464+ import std.algorithm.comparison : equal;
1465+
1466+ int[] a = [1, 3, 5];
1467+ int[] b = [2, 3, 4];
1468+ assert(a.setUnion(b).equal([1, 2, 3, 4, 5]));
1469+}
1470+
1471+@safe pure nothrow unittest
1472+{
1473+ import std.algorithm.comparison : equal;
1474+
1475+ int[] a = [ 1, 2, 4, 5, 7, 9 ];
1476+ int[] b = [ 0, 1, 2, 4, 7, 8 ];
1477+ double[] c = [ 10.5 ];
1478+
1479+ assert(equal(setUnion(a, b), [0, 1, 2, 4, 5, 7, 8, 9][]));
1480+ assert(equal(setUnion(a, c, b),
1481+ [0, 1, 2, 4, 5, 7, 8, 9, 10.5][]));
1482+}
1483+
1484+@safe unittest
1485+{
1486+ // save
1487+ import std.range : dropOne;
1488+ int[] a = [0, 1, 2];
1489+ int[] b = [0, 3];
1490+ auto arr = a.setUnion(b);
1491+ assert(arr.front == 0);
1492+ assert(arr.save.dropOne.front == 1);
1493+ assert(arr.front == 0);
1494+}
1495+
1496+@nogc @safe pure nothrow unittest
1497+{
1498+ import std.algorithm.comparison : equal;
1499+
1500+ static immutable a = [1, 3, 5];
1501+ static immutable b = [2, 4];
1502+ static immutable r = [1, 2, 3, 4, 5];
1503+ assert(a.setUnion(b).equal(r));
1504+}
1505+
1506+@safe pure nothrow unittest
1507+{
1508+ import std.algorithm.comparison : equal;
1509+ import std.internal.test.dummyrange;
1510+ import std.range : iota;
1511+
1512+ auto dummyResult1 = [1, 1.5, 2, 3, 4, 5, 5.5, 6, 7, 8, 9, 10];
1513+ auto dummyResult2 = iota(1, 11);
1514+ foreach (DummyType; AllDummyRanges)
1515+ {
1516+ DummyType d;
1517+ assert(d.setUnion([1, 1.5, 5.5]).equal(dummyResult1));
1518+ assert(d.setUnion(d).equal(dummyResult2));
1519+ }
1520+}
1521+++/
gcc/libphobos/src/std/algorithm/sorting.d+4468−0
@@ -0,0 +1,4468 @@
1+// Written in the D programming language.
2+/**
3+This is a submodule of $(MREF std, algorithm).
4+It contains generic _sorting algorithms.
5+
6+$(SCRIPT inhibitQuickIndex = 1;)
7+$(BOOKTABLE Cheat Sheet,
8+$(TR $(TH Function Name) $(TH Description))
9+$(T2 completeSort,
10+ If $(D a = [10, 20, 30]) and $(D b = [40, 6, 15]), then
11+ $(D completeSort(a, b)) leaves $(D a = [6, 10, 15]) and $(D b = [20,
12+ 30, 40]).
13+ The range $(D a) must be sorted prior to the call, and as a result the
14+ combination $(D $(REF chain, std,range)(a, b)) is sorted.)
15+$(T2 isPartitioned,
16+ $(D isPartitioned!"a < 0"([-1, -2, 1, 0, 2])) returns $(D true) because
17+ the predicate is $(D true) for a portion of the range and $(D false)
18+ afterwards.)
19+$(T2 isSorted,
20+ $(D isSorted([1, 1, 2, 3])) returns $(D true).)
21+$(T2 isStrictlyMonotonic,
22+ $(D isStrictlyMonotonic([1, 1, 2, 3])) returns $(D false).)
23+$(T2 ordered,
24+ $(D ordered(1, 1, 2, 3)) returns $(D true).)
25+$(T2 strictlyOrdered,
26+ $(D strictlyOrdered(1, 1, 2, 3)) returns $(D false).)
27+$(T2 makeIndex,
28+ Creates a separate index for a range.)
29+$(T2 merge,
30+ Lazily merges two or more sorted ranges.)
31+$(T2 multiSort,
32+ Sorts by multiple keys.)
33+$(T2 nextEvenPermutation,
34+ Computes the next lexicographically greater even permutation of a range
35+ in-place.)
36+$(T2 nextPermutation,
37+ Computes the next lexicographically greater permutation of a range
38+ in-place.)
39+$(T2 partialSort,
40+ If $(D a = [5, 4, 3, 2, 1]), then $(D partialSort(a, 3)) leaves
41+ $(D a[0 .. 3] = [1, 2, 3]).
42+ The other elements of $(D a) are left in an unspecified order.)
43+$(T2 partition,
44+ Partitions a range according to a unary predicate.)
45+$(T2 partition3,
46+ Partitions a range according to a binary predicate in three parts (less
47+ than, equal, greater than the given pivot). Pivot is not given as an
48+ index, but instead as an element independent from the range's content.)
49+$(T2 pivotPartition,
50+ Partitions a range according to a binary predicate in two parts: less
51+ than or equal, and greater than or equal to the given pivot, passed as
52+ an index in the range.)
53+$(T2 schwartzSort,
54+ Sorts with the help of the $(LINK2 https://en.wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform).)
55+$(T2 sort,
56+ Sorts.)
57+$(T2 topN,
58+ Separates the top elements in a range.)
59+$(T2 topNCopy,
60+ Copies out the top elements of a range.)
61+$(T2 topNIndex,
62+ Builds an index of the top elements of a range.)
63+)
64+
65+Copyright: Andrei Alexandrescu 2008-.
66+
67+License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
68+
69+Authors: $(HTTP erdani.com, Andrei Alexandrescu)
70+
71+Source: $(PHOBOSSRC std/algorithm/_sorting.d)
72+
73+Macros:
74+T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
75+ */
76+module std.algorithm.sorting;
77+
78+import std.algorithm.mutation : SwapStrategy;
79+import std.functional; // : unaryFun, binaryFun;
80+import std.range.primitives;
81+import std.typecons : Flag;
82+// FIXME
83+import std.meta; // : allSatisfy;
84+import std.range; // : SortedRange;
85+import std.traits;
86+
87+/**
88+Specifies whether the output of certain algorithm is desired in sorted
89+format.
90+
91+If set to $(D SortOutput.no), the output should not be sorted.
92+
93+Otherwise if set to $(D SortOutput.yes), the output should be sorted.
94+ */
95+alias SortOutput = Flag!"sortOutput";
96+
97+// completeSort
98+/**
99+Sorts the random-access range $(D chain(lhs, rhs)) according to
100+predicate $(D less). The left-hand side of the range $(D lhs) is
101+assumed to be already sorted; $(D rhs) is assumed to be unsorted. The
102+exact strategy chosen depends on the relative sizes of $(D lhs) and
103+$(D rhs). Performs $(BIGOH lhs.length + rhs.length * log(rhs.length))
104+(best case) to $(BIGOH (lhs.length + rhs.length) * log(lhs.length +
105+rhs.length)) (worst-case) evaluations of $(D swap).
106+
107+Params:
108+ less = The predicate to sort by.
109+ ss = The swapping strategy to use.
110+ lhs = The sorted, left-hand side of the random access range to be sorted.
111+ rhs = The unsorted, right-hand side of the random access range to be
112+ sorted.
113+*/
114+void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
115+ RandomAccessRange1, RandomAccessRange2)(SortedRange!(RandomAccessRange1, less) lhs, RandomAccessRange2 rhs)
116+if (hasLength!(RandomAccessRange2) && hasSlicing!(RandomAccessRange2))
117+{
118+ import std.algorithm.mutation : bringToFront;
119+ import std.range : chain, assumeSorted;
120+ // Probably this algorithm can be optimized by using in-place
121+ // merge
122+ auto lhsOriginal = lhs.release();
123+ foreach (i; 0 .. rhs.length)
124+ {
125+ auto sortedSoFar = chain(lhsOriginal, rhs[0 .. i]);
126+ auto ub = assumeSorted!less(sortedSoFar).upperBound(rhs[i]);
127+ if (!ub.length) continue;
128+ bringToFront(ub.release(), rhs[i .. i + 1]);
129+ }
130+}
131+
132+///
133+@safe unittest
134+{
135+ import std.range : assumeSorted;
136+ int[] a = [ 1, 2, 3 ];
137+ int[] b = [ 4, 0, 6, 5 ];
138+ completeSort(assumeSorted(a), b);
139+ assert(a == [ 0, 1, 2 ]);
140+ assert(b == [ 3, 4, 5, 6 ]);
141+}
142+
143+// isSorted
144+/**
145+Checks whether a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
146+is sorted according to the comparison operation $(D less). Performs $(BIGOH r.length)
147+evaluations of $(D less).
148+
149+Unlike `isSorted`, `isStrictlyMonotonic` does not allow for equal values,
150+i.e. values for which both `less(a, b)` and `less(b, a)` are false.
151+
152+With either function, the predicate must be a strict ordering just like with
153+`isSorted`. For example, using `"a <= b"` instead of `"a < b"` is
154+incorrect and will cause failed assertions.
155+
156+Params:
157+ less = Predicate the range should be sorted by.
158+ r = Forward range to check for sortedness.
159+
160+Returns:
161+ `true` if the range is sorted, false otherwise. `isSorted` allows
162+ duplicates, `isStrictlyMonotonic` not.
163+*/
164+bool isSorted(alias less = "a < b", Range)(Range r)
165+if (isForwardRange!(Range))
166+{
167+ if (r.empty) return true;
168+
169+ static if (isRandomAccessRange!Range && hasLength!Range)
170+ {
171+ immutable limit = r.length - 1;
172+ foreach (i; 0 .. limit)
173+ {
174+ if (!binaryFun!less(r[i + 1], r[i])) continue;
175+ assert(
176+ !binaryFun!less(r[i], r[i + 1]),
177+ "Predicate for isSorted is not antisymmetric. Both" ~
178+ " pred(a, b) and pred(b, a) are true for certain values.");
179+ return false;
180+ }
181+ }
182+ else
183+ {
184+ auto ahead = r.save;
185+ ahead.popFront();
186+ size_t i;
187+
188+ for (; !ahead.empty; ahead.popFront(), r.popFront(), ++i)
189+ {
190+ if (!binaryFun!less(ahead.front, r.front)) continue;
191+ // Check for antisymmetric predicate
192+ assert(
193+ !binaryFun!less(r.front, ahead.front),
194+ "Predicate for isSorted is not antisymmetric. Both" ~
195+ " pred(a, b) and pred(b, a) are true for certain values.");
196+ return false;
197+ }
198+ }
199+ return true;
200+}
201+
202+///
203+@safe unittest
204+{
205+ assert([1, 1, 2].isSorted);
206+ // strictly monotonic doesn't allow duplicates
207+ assert(![1, 1, 2].isStrictlyMonotonic);
208+
209+ int[] arr = [4, 3, 2, 1];
210+ assert(!isSorted(arr));
211+ assert(!isStrictlyMonotonic(arr));
212+
213+ assert(isSorted!"a > b"(arr));
214+ assert(isStrictlyMonotonic!"a > b"(arr));
215+
216+ sort(arr);
217+ assert(isSorted(arr));
218+ assert(isStrictlyMonotonic(arr));
219+}
220+
221+@safe unittest
222+{
223+ import std.conv : to;
224+
225+ // Issue 9457
226+ auto x = "abcd";
227+ assert(isSorted(x));
228+ auto y = "acbd";
229+ assert(!isSorted(y));
230+
231+ int[] a = [1, 2, 3];
232+ assert(isSorted(a));
233+ int[] b = [1, 3, 2];
234+ assert(!isSorted(b));
235+
236+ // ignores duplicates
237+ int[] c = [1, 1, 2];
238+ assert(isSorted(c));
239+
240+ dchar[] ds = "コーヒーが好きです"d.dup;
241+ sort(ds);
242+ string s = to!string(ds);
243+ assert(isSorted(ds)); // random-access
244+ assert(isSorted(s)); // bidirectional
245+}
246+
247+@nogc @safe nothrow pure unittest
248+{
249+ static immutable a = [1, 2, 3];
250+ assert(a.isSorted);
251+}
252+
253+/// ditto
254+bool isStrictlyMonotonic(alias less = "a < b", Range)(Range r)
255+if (isForwardRange!Range)
256+{
257+ import std.algorithm.searching : findAdjacent;
258+ return findAdjacent!((a,b) => !binaryFun!less(a,b))(r).empty;
259+}
260+
261+@safe unittest
262+{
263+ import std.conv : to;
264+
265+ assert("abcd".isStrictlyMonotonic);
266+ assert(!"aacd".isStrictlyMonotonic);
267+ assert(!"acb".isStrictlyMonotonic);
268+
269+ assert([1, 2, 3].isStrictlyMonotonic);
270+ assert(![1, 3, 2].isStrictlyMonotonic);
271+ assert(![1, 1, 2].isStrictlyMonotonic);
272+
273+ // ー occurs twice -> can't be strict
274+ dchar[] ds = "コーヒーが好きです"d.dup;
275+ sort(ds);
276+ string s = to!string(ds);
277+ assert(!isStrictlyMonotonic(ds)); // random-access
278+ assert(!isStrictlyMonotonic(s)); // bidirectional
279+
280+ dchar[] ds2 = "コーヒが好きです"d.dup;
281+ sort(ds2);
282+ string s2 = to!string(ds2);
283+ assert(isStrictlyMonotonic(ds2)); // random-access
284+ assert(isStrictlyMonotonic(s2)); // bidirectional
285+}
286+
287+@nogc @safe nothrow pure unittest
288+{
289+ static immutable a = [1, 2, 3];
290+ assert(a.isStrictlyMonotonic);
291+}
292+
293+/**
294+Like $(D isSorted), returns $(D true) if the given $(D values) are ordered
295+according to the comparison operation $(D less). Unlike $(D isSorted), takes values
296+directly instead of structured in a range.
297+
298+$(D ordered) allows repeated values, e.g. $(D ordered(1, 1, 2)) is $(D true). To verify
299+that the values are ordered strictly monotonically, use $(D strictlyOrdered);
300+$(D strictlyOrdered(1, 1, 2)) is $(D false).
301+
302+With either function, the predicate must be a strict ordering. For example,
303+using $(D "a <= b") instead of $(D "a < b") is incorrect and will cause failed
304+assertions.
305+
306+Params:
307+ values = The tested value
308+ less = The comparison predicate
309+
310+Returns:
311+ $(D true) if the values are ordered; $(D ordered) allows for duplicates,
312+ $(D strictlyOrdered) does not.
313+*/
314+
315+bool ordered(alias less = "a < b", T...)(T values)
316+if ((T.length == 2 && is(typeof(binaryFun!less(values[1], values[0])) : bool))
317+ ||
318+ (T.length > 2 && is(typeof(ordered!less(values[0 .. 1 + $ / 2])))
319+ && is(typeof(ordered!less(values[$ / 2 .. $]))))
320+ )
321+{
322+ foreach (i, _; T[0 .. $ - 1])
323+ {
324+ if (binaryFun!less(values[i + 1], values[i]))
325+ {
326+ assert(!binaryFun!less(values[i], values[i + 1]),
327+ __FUNCTION__ ~ ": incorrect non-strict predicate.");
328+ return false;
329+ }
330+ }
331+ return true;
332+}
333+
334+/// ditto
335+bool strictlyOrdered(alias less = "a < b", T...)(T values)
336+if (is(typeof(ordered!less(values))))
337+{
338+ foreach (i, _; T[0 .. $ - 1])
339+ {
340+ if (!binaryFun!less(values[i], values[i + 1]))
341+ {
342+ return false;
343+ }
344+ assert(!binaryFun!less(values[i + 1], values[i]),
345+ __FUNCTION__ ~ ": incorrect non-strict predicate.");
346+ }
347+ return true;
348+}
349+
350+///
351+@safe unittest
352+{
353+ assert(ordered(42, 42, 43));
354+ assert(!strictlyOrdered(43, 42, 45));
355+ assert(ordered(42, 42, 43));
356+ assert(!strictlyOrdered(42, 42, 43));
357+ assert(!ordered(43, 42, 45));
358+ // Ordered lexicographically
359+ assert(ordered("Jane", "Jim", "Joe"));
360+ assert(strictlyOrdered("Jane", "Jim", "Joe"));
361+ // Incidentally also ordered by length decreasing
362+ assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
363+ // ... but not strictly so: "Jim" and "Joe" have the same length
364+ assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
365+}
366+
367+// partition
368+/**
369+Partitions a range in two using the given $(D predicate).
370+Specifically, reorders the range $(D r = [left, right$(RPAREN)) using $(D swap)
371+such that all elements $(D i) for which $(D predicate(i)) is $(D true) come
372+before all elements $(D j) for which $(D predicate(j)) returns $(D false).
373+
374+Performs $(BIGOH r.length) (if unstable or semistable) or $(BIGOH
375+r.length * log(r.length)) (if stable) evaluations of $(D less) and $(D
376+swap). The unstable version computes the minimum possible evaluations
377+of $(D swap) (roughly half of those performed by the semistable
378+version).
379+
380+Params:
381+ predicate = The predicate to partition by.
382+ ss = The swapping strategy to employ.
383+ r = The random-access range to partition.
384+
385+Returns:
386+
387+The right part of $(D r) after partitioning.
388+
389+If $(D ss == SwapStrategy.stable), $(D partition) preserves the relative
390+ordering of all elements $(D a), $(D b) in $(D r) for which $(D predicate(a) ==
391+predicate(b)). If $(D ss == SwapStrategy.semistable), $(D partition) preserves
392+the relative ordering of all elements $(D a), $(D b) in the left part of $(D r)
393+for which $(D predicate(a) == predicate(b)).
394+
395+See_Also:
396+ STL's $(HTTP sgi.com/tech/stl/_partition.html, _partition)$(BR)
397+ STL's $(HTTP sgi.com/tech/stl/stable_partition.html, stable_partition)
398+*/
399+Range partition(alias predicate, SwapStrategy ss, Range)(Range r)
400+if (ss == SwapStrategy.stable && isRandomAccessRange!(Range) && hasLength!Range && hasSlicing!Range)
401+{
402+ import std.algorithm.mutation : bringToFront;
403+
404+ alias pred = unaryFun!(predicate);
405+ if (r.empty) return r;
406+
407+ if (r.length == 1)
408+ {
409+ if (pred(r.front)) r.popFront();
410+ return r;
411+ }
412+ const middle = r.length / 2;
413+ alias recurse = .partition!(pred, ss, Range);
414+ auto lower = recurse(r[0 .. middle]);
415+ auto upper = recurse(r[middle .. r.length]);
416+ bringToFront(lower, r[middle .. r.length - upper.length]);
417+ return r[r.length - lower.length - upper.length .. r.length];
418+}
419+
420+///ditto
421+Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)
422+if (ss != SwapStrategy.stable && isInputRange!Range && hasSwappableElements!Range)
423+{
424+ import std.algorithm.mutation : swap;
425+ alias pred = unaryFun!(predicate);
426+
427+ static if (ss == SwapStrategy.semistable)
428+ {
429+ if (r.empty) return r;
430+
431+ for (; !r.empty; r.popFront())
432+ {
433+ // skip the initial portion of "correct" elements
434+ if (pred(r.front)) continue;
435+ // hit the first "bad" element
436+ auto result = r;
437+ for (r.popFront(); !r.empty; r.popFront())
438+ {
439+ if (!pred(r.front)) continue;
440+ swap(result.front, r.front);
441+ result.popFront();
442+ }
443+ return result;
444+ }
445+
446+ return r;
447+ }
448+ else
449+ {
450+ // Inspired from www.stepanovpapers.com/PAM3-partition_notes.pdf,
451+ // section "Bidirectional Partition Algorithm (Hoare)"
452+ static if (isDynamicArray!Range)
453+ {
454+ import std.algorithm.mutation : swapAt;
455+ // For dynamic arrays prefer index-based manipulation
456+ if (!r.length) return r;
457+ size_t lo = 0, hi = r.length - 1;
458+ for (;;)
459+ {
460+ for (;;)
461+ {
462+ if (lo > hi) return r[lo .. r.length];
463+ if (!pred(r[lo])) break;
464+ ++lo;
465+ }
466+ // found the left bound
467+ assert(lo <= hi);
468+ for (;;)
469+ {
470+ if (lo == hi) return r[lo .. r.length];
471+ if (pred(r[hi])) break;
472+ --hi;
473+ }
474+ // found the right bound, swap & make progress
475+ r.swapAt(lo++, hi--);
476+ }
477+ }
478+ else
479+ {
480+ import std.algorithm.mutation : swap;
481+ auto result = r;
482+ for (;;)
483+ {
484+ for (;;)
485+ {
486+ if (r.empty) return result;
487+ if (!pred(r.front)) break;
488+ r.popFront();
489+ result.popFront();
490+ }
491+ // found the left bound
492+ assert(!r.empty);
493+ for (;;)
494+ {
495+ if (pred(r.back)) break;
496+ r.popBack();
497+ if (r.empty) return result;
498+ }
499+ // found the right bound, swap & make progress
500+ static if (is(typeof(swap(r.front, r.back))))
501+ {
502+ swap(r.front, r.back);
503+ }
504+ else
505+ {
506+ auto t1 = r.moveFront(), t2 = r.moveBack();
507+ r.front = t2;
508+ r.back = t1;
509+ }
510+ r.popFront();
511+ result.popFront();
512+ r.popBack();
513+ }
514+ }
515+ }
516+}
517+
518+///
519+@safe unittest
520+{
521+ import std.algorithm.mutation : SwapStrategy;
522+ import std.algorithm.searching : count, find;
523+ import std.conv : text;
524+ import std.range.primitives : empty;
525+
526+ auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
527+ auto arr = Arr.dup;
528+ static bool even(int a) { return (a & 1) == 0; }
529+ // Partition arr such that even numbers come first
530+ auto r = partition!(even)(arr);
531+ // Now arr is separated in evens and odds.
532+ // Numbers may have become shuffled due to instability
533+ assert(r == arr[5 .. $]);
534+ assert(count!(even)(arr[0 .. 5]) == 5);
535+ assert(find!(even)(r).empty);
536+
537+ // Can also specify the predicate as a string.
538+ // Use 'a' as the predicate argument name
539+ arr[] = Arr[];
540+ r = partition!(q{(a & 1) == 0})(arr);
541+ assert(r == arr[5 .. $]);
542+
543+ // Now for a stable partition:
544+ arr[] = Arr[];
545+ r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr);
546+ // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1
547+ assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]);
548+
549+ // In case the predicate needs to hold its own state, use a delegate:
550+ arr[] = Arr[];
551+ int x = 3;
552+ // Put stuff greater than 3 on the left
553+ bool fun(int a) { return a > x; }
554+ r = partition!(fun, SwapStrategy.semistable)(arr);
555+ // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2
556+ assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]);
557+}
558+
559+@safe unittest
560+{
561+ import std.algorithm.internal : rndstuff;
562+ static bool even(int a) { return (a & 1) == 0; }
563+
564+ // test with random data
565+ auto a = rndstuff!int();
566+ partition!even(a);
567+ assert(isPartitioned!even(a));
568+ auto b = rndstuff!string();
569+ partition!`a.length < 5`(b);
570+ assert(isPartitioned!`a.length < 5`(b));
571+}
572+
573+// pivotPartition
574+/**
575+
576+Partitions `r` around `pivot` using comparison function `less`, algorithm akin
577+to $(LINK2 https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme,
578+Hoare partition). Specifically, permutes elements of `r` and returns
579+an index $(D k < r.length) such that:
580+
581+$(UL
582+
583+$(LI `r[pivot]` is swapped to `r[k]`)
584+
585+$(LI All elements `e` in subrange $(D r[0 .. k]) satisfy $(D !less(r[k], e))
586+(i.e. `r[k]` is greater than or equal to each element to its left according to
587+predicate `less`))
588+
589+$(LI All elements `e` in subrange $(D r[0 .. k]) satisfy $(D !less(e,
590+r[k])) (i.e. `r[k]` is less than or equal to each element to its right
591+according to predicate `less`)))
592+
593+If `r` contains equivalent elements, multiple permutations of `r` satisfy these
594+constraints. In such cases, `pivotPartition` attempts to distribute equivalent
595+elements fairly to the left and right of `k` such that `k` stays close to $(D
596+r.length / 2).
597+
598+Params:
599+less = The predicate used for comparison, modeled as a
600+ $(LINK2 https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings,
601+ strict weak ordering) (irreflexive, antisymmetric, transitive, and implying a transitive
602+ equivalence)
603+r = The range being partitioned
604+pivot = The index of the pivot for partitioning, must be less than `r.length` or
605+`0` is `r.length` is `0`
606+
607+Returns:
608+The new position of the pivot
609+
610+See_Also:
611+$(HTTP jgrcs.info/index.php/jgrcs/article/view/142, Engineering of a Quicksort
612+Partitioning Algorithm), D. Abhyankar, Journal of Global Research in Computer
613+Science, February 2011. $(HTTPS youtube.com/watch?v=AxnotgLql0k, ACCU 2016
614+Keynote), Andrei Alexandrescu.
615+*/
616+size_t pivotPartition(alias less = "a < b", Range)
617+(Range r, size_t pivot)
618+if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range)
619+{
620+ assert(pivot < r.length || r.length == 0 && pivot == 0);
621+ if (r.length <= 1) return 0;
622+ import std.algorithm.mutation : swapAt, move;
623+ alias lt = binaryFun!less;
624+
625+ // Pivot at the front
626+ r.swapAt(pivot, 0);
627+
628+ // Fork implementation depending on nothrow copy, assignment, and
629+ // comparison. If all of these are nothrow, use the specialized
630+ // implementation discussed at https://youtube.com/watch?v=AxnotgLql0k.
631+ static if (is(typeof(
632+ () nothrow { auto x = r.front; x = r.front; return lt(x, x); }
633+ )))
634+ {
635+ auto p = r[0];
636+ // Plant the pivot in the end as well as a sentinel
637+ size_t lo = 0, hi = r.length - 1;
638+ auto save = move(r[hi]);
639+ r[hi] = p; // Vacancy is in r[$ - 1] now
640+ // Start process
641+ for (;;)
642+ {
643+ // Loop invariant
644+ version (unittest)
645+ {
646+ import std.algorithm.searching : all;
647+ assert(r[0 .. lo].all!(x => !lt(p, x)));
648+ assert(r[hi + 1 .. r.length].all!(x => !lt(x, p)));
649+ }
650+ do ++lo; while (lt(r[lo], p));
651+ r[hi] = r[lo];
652+ // Vacancy is now in r[lo]
653+ do --hi; while (lt(p, r[hi]));
654+ if (lo >= hi) break;
655+ r[lo] = r[hi];
656+ // Vacancy is not in r[hi]
657+ }
658+ // Fixup
659+ assert(lo - hi <= 2);
660+ assert(!lt(p, r[hi]));
661+ if (lo == hi + 2)
662+ {
663+ assert(!lt(r[hi + 1], p));
664+ r[lo] = r[hi + 1];
665+ --lo;
666+ }
667+ r[lo] = save;
668+ if (lt(p, save)) --lo;
669+ assert(!lt(p, r[lo]));
670+ }
671+ else
672+ {
673+ size_t lo = 1, hi = r.length - 1;
674+ loop: for (;; lo++, hi--)
675+ {
676+ for (;; ++lo)
677+ {
678+ if (lo > hi) break loop;
679+ if (!lt(r[lo], r[0])) break;
680+ }
681+ // found the left bound: r[lo] >= r[0]
682+ assert(lo <= hi);
683+ for (;; --hi)
684+ {
685+ if (lo >= hi) break loop;
686+ if (!lt(r[0], r[hi])) break;
687+ }
688+ // found the right bound: r[hi] <= r[0], swap & make progress
689+ assert(!lt(r[lo], r[hi]));
690+ r.swapAt(lo, hi);
691+ }
692+ --lo;
693+ }
694+ r.swapAt(lo, 0);
695+ return lo;
696+}
697+
698+///
699+@safe nothrow unittest
700+{
701+ int[] a = [5, 3, 2, 6, 4, 1, 3, 7];
702+ size_t pivot = pivotPartition(a, a.length / 2);
703+ import std.algorithm.searching : all;
704+ assert(a[0 .. pivot].all!(x => x <= a[pivot]));
705+ assert(a[pivot .. $].all!(x => x >= a[pivot]));
706+}
707+
708+@safe unittest
709+{
710+ void test(alias less)()
711+ {
712+ int[] a;
713+ size_t pivot;
714+
715+ a = [-9, -4, -2, -2, 9];
716+ pivot = pivotPartition!less(a, a.length / 2);
717+ import std.algorithm.searching : all;
718+ assert(a[0 .. pivot].all!(x => x <= a[pivot]));
719+ assert(a[pivot .. $].all!(x => x >= a[pivot]));
720+
721+ a = [9, 2, 8, -5, 5, 4, -8, -4, 9];
722+ pivot = pivotPartition!less(a, a.length / 2);
723+ assert(a[0 .. pivot].all!(x => x <= a[pivot]));
724+ assert(a[pivot .. $].all!(x => x >= a[pivot]));
725+
726+ a = [ 42 ];
727+ pivot = pivotPartition!less(a, a.length / 2);
728+ assert(pivot == 0);
729+ assert(a == [ 42 ]);
730+
731+ a = [ 43, 42 ];
732+ pivot = pivotPartition!less(a, 0);
733+ assert(pivot == 1);
734+ assert(a == [ 42, 43 ]);
735+
736+ a = [ 43, 42 ];
737+ pivot = pivotPartition!less(a, 1);
738+ assert(pivot == 0);
739+ assert(a == [ 42, 43 ]);
740+
741+ a = [ 42, 42 ];
742+ pivot = pivotPartition!less(a, 0);
743+ assert(pivot == 0 || pivot == 1);
744+ assert(a == [ 42, 42 ]);
745+ pivot = pivotPartition!less(a, 1);
746+ assert(pivot == 0 || pivot == 1);
747+ assert(a == [ 42, 42 ]);
748+
749+ import std.algorithm.iteration : map;
750+ import std.random;
751+ import std.stdio;
752+ auto s = unpredictableSeed;
753+ auto g = Random(s);
754+ a = iota(0, uniform(1, 1000, g))
755+ .map!(_ => uniform(-1000, 1000, g))
756+ .array;
757+ scope(failure) writeln("RNG seed was ", s);
758+ pivot = pivotPartition!less(a, a.length / 2);
759+ assert(a[0 .. pivot].all!(x => x <= a[pivot]));
760+ assert(a[pivot .. $].all!(x => x >= a[pivot]));
761+ }
762+ test!"a < b";
763+ static bool myLess(int a, int b)
764+ {
765+ static bool bogus;
766+ if (bogus) throw new Exception(""); // just to make it no-nothrow
767+ return a < b;
768+ }
769+ test!myLess;
770+}
771+
772+/**
773+Params:
774+ pred = The predicate that the range should be partitioned by.
775+ r = The range to check.
776+Returns: $(D true) if $(D r) is partitioned according to predicate $(D pred).
777+ */
778+bool isPartitioned(alias pred, Range)(Range r)
779+if (isForwardRange!(Range))
780+{
781+ for (; !r.empty; r.popFront())
782+ {
783+ if (unaryFun!(pred)(r.front)) continue;
784+ for (r.popFront(); !r.empty; r.popFront())
785+ {
786+ if (unaryFun!(pred)(r.front)) return false;
787+ }
788+ break;
789+ }
790+ return true;
791+}
792+
793+///
794+@safe unittest
795+{
796+ int[] r = [ 1, 3, 5, 7, 8, 2, 4, ];
797+ assert(isPartitioned!"a & 1"(r));
798+}
799+
800+// partition3
801+/**
802+Rearranges elements in $(D r) in three adjacent ranges and returns
803+them. The first and leftmost range only contains elements in $(D r)
804+less than $(D pivot). The second and middle range only contains
805+elements in $(D r) that are equal to $(D pivot). Finally, the third
806+and rightmost range only contains elements in $(D r) that are greater
807+than $(D pivot). The less-than test is defined by the binary function
808+$(D less).
809+
810+Params:
811+ less = The predicate to use for the rearrangement.
812+ ss = The swapping strategy to use.
813+ r = The random-access range to rearrange.
814+ pivot = The pivot element.
815+
816+Returns:
817+ A $(REF Tuple, std,typecons) of the three resulting ranges. These ranges are
818+ slices of the original range.
819+
820+BUGS: stable $(D partition3) has not been implemented yet.
821+ */
822+auto partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E)
823+(Range r, E pivot)
824+if (ss == SwapStrategy.unstable && isRandomAccessRange!Range
825+ && hasSwappableElements!Range && hasLength!Range && hasSlicing!Range
826+ && is(typeof(binaryFun!less(r.front, pivot)) == bool)
827+ && is(typeof(binaryFun!less(pivot, r.front)) == bool)
828+ && is(typeof(binaryFun!less(r.front, r.front)) == bool))
829+{
830+ // The algorithm is described in "Engineering a sort function" by
831+ // Jon Bentley et al, pp 1257.
832+
833+ import std.algorithm.comparison : min;
834+ import std.algorithm.mutation : swap, swapAt, swapRanges;
835+ import std.typecons : tuple;
836+
837+ alias lessFun = binaryFun!less;
838+ size_t i, j, k = r.length, l = k;
839+
840+ bigloop:
841+ for (;;)
842+ {
843+ for (;; ++j)
844+ {
845+ if (j == k) break bigloop;
846+ assert(j < r.length);
847+ if (lessFun(r[j], pivot)) continue;
848+ if (lessFun(pivot, r[j])) break;
849+ r.swapAt(i++, j);
850+ }
851+ assert(j < k);
852+ for (;;)
853+ {
854+ assert(k > 0);
855+ if (!lessFun(pivot, r[--k]))
856+ {
857+ if (lessFun(r[k], pivot)) break;
858+ r.swapAt(k, --l);
859+ }
860+ if (j == k) break bigloop;
861+ }
862+ // Here we know r[j] > pivot && r[k] < pivot
863+ r.swapAt(j++, k);
864+ }
865+
866+ // Swap the equal ranges from the extremes into the middle
867+ auto strictlyLess = j - i, strictlyGreater = l - k;
868+ auto swapLen = min(i, strictlyLess);
869+ swapRanges(r[0 .. swapLen], r[j - swapLen .. j]);
870+ swapLen = min(r.length - l, strictlyGreater);
871+ swapRanges(r[k .. k + swapLen], r[r.length - swapLen .. r.length]);
872+ return tuple(r[0 .. strictlyLess],
873+ r[strictlyLess .. r.length - strictlyGreater],
874+ r[r.length - strictlyGreater .. r.length]);
875+}
876+
877+///
878+@safe unittest
879+{
880+ auto a = [ 8, 3, 4, 1, 4, 7, 4 ];
881+ auto pieces = partition3(a, 4);
882+ assert(pieces[0] == [ 1, 3 ]);
883+ assert(pieces[1] == [ 4, 4, 4 ]);
884+ assert(pieces[2] == [ 8, 7 ]);
885+}
886+
887+@safe unittest
888+{
889+ import std.random : Random, uniform, unpredictableSeed;
890+
891+ immutable uint[] seeds = [3923355730, 1927035882, unpredictableSeed];
892+ foreach (s; seeds)
893+ {
894+ auto r = Random(s);
895+ auto a = new int[](uniform(0, 100, r));
896+ foreach (ref e; a)
897+ {
898+ e = uniform(0, 50, r);
899+ }
900+ auto pieces = partition3(a, 25);
901+ assert(pieces[0].length + pieces[1].length + pieces[2].length == a.length);
902+ foreach (e; pieces[0])
903+ {
904+ assert(e < 25);
905+ }
906+ foreach (e; pieces[1])
907+ {
908+ assert(e == 25);
909+ }
910+ foreach (e; pieces[2])
911+ {
912+ assert(e > 25);
913+ }
914+ }
915+}
916+
917+// makeIndex
918+/**
919+Computes an index for $(D r) based on the comparison $(D less). The
920+index is a sorted array of pointers or indices into the original
921+range. This technique is similar to sorting, but it is more flexible
922+because (1) it allows "sorting" of immutable collections, (2) allows
923+binary search even if the original collection does not offer random
924+access, (3) allows multiple indexes, each on a different predicate,
925+and (4) may be faster when dealing with large objects. However, using
926+an index may also be slower under certain circumstances due to the
927+extra indirection, and is always larger than a sorting-based solution
928+because it needs space for the index in addition to the original
929+collection. The complexity is the same as $(D sort)'s.
930+
931+The first overload of $(D makeIndex) writes to a range containing
932+pointers, and the second writes to a range containing offsets. The
933+first overload requires $(D Range) to be a
934+$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives), and the
935+latter requires it to be a random-access range.
936+
937+$(D makeIndex) overwrites its second argument with the result, but
938+never reallocates it.
939+
940+Params:
941+ less = The comparison to use.
942+ ss = The swapping strategy.
943+ r = The range to index.
944+ index = The resulting index.
945+
946+Returns: The pointer-based version returns a $(D SortedRange) wrapper
947+over index, of type $(D SortedRange!(RangeIndex, (a, b) =>
948+binaryFun!less(*a, *b))) thus reflecting the ordering of the
949+index. The index-based version returns $(D void) because the ordering
950+relation involves not only $(D index) but also $(D r).
951+
952+Throws: If the second argument's length is less than that of the range
953+indexed, an exception is thrown.
954+*/
955+SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))
956+makeIndex(
957+ alias less = "a < b",
958+ SwapStrategy ss = SwapStrategy.unstable,
959+ Range,
960+ RangeIndex)
961+(Range r, RangeIndex index)
962+if (isForwardRange!(Range) && isRandomAccessRange!(RangeIndex)
963+ && is(ElementType!(RangeIndex) : ElementType!(Range)*))
964+{
965+ import std.algorithm.internal : addressOf;
966+ import std.exception : enforce;
967+
968+ // assume collection already ordered
969+ size_t i;
970+ for (; !r.empty; r.popFront(), ++i)
971+ index[i] = addressOf(r.front);
972+ enforce(index.length == i);
973+ // sort the index
974+ sort!((a, b) => binaryFun!less(*a, *b), ss)(index);
975+ return typeof(return)(index);
976+}
977+
978+/// Ditto
979+void makeIndex(
980+ alias less = "a < b",
981+ SwapStrategy ss = SwapStrategy.unstable,
982+ Range,
983+ RangeIndex)
984+(Range r, RangeIndex index)
985+if (isRandomAccessRange!Range && !isInfinite!Range &&
986+ isRandomAccessRange!RangeIndex && !isInfinite!RangeIndex &&
987+ isIntegral!(ElementType!RangeIndex))
988+{
989+ import std.conv : to;
990+ import std.exception : enforce;
991+
992+ alias IndexType = Unqual!(ElementType!RangeIndex);
993+ enforce(r.length == index.length,
994+ "r and index must be same length for makeIndex.");
995+ static if (IndexType.sizeof < size_t.sizeof)
996+ {
997+ enforce(r.length <= size_t(1) + IndexType.max, "Cannot create an index with " ~
998+ "element type " ~ IndexType.stringof ~ " with length " ~
999+ to!string(r.length) ~ ".");
1000+ }
1001+
1002+ // Use size_t as loop index to avoid overflow on ++i,
1003+ // e.g. when squeezing 256 elements into a ubyte index.
1004+ foreach (size_t i; 0 .. r.length)
1005+ index[i] = cast(IndexType) i;
1006+
1007+ // sort the index
1008+ sort!((a, b) => binaryFun!less(r[cast(size_t) a], r[cast(size_t) b]), ss)
1009+ (index);
1010+}
1011+
1012+///
1013+@system unittest
1014+{
1015+ immutable(int[]) arr = [ 2, 3, 1, 5, 0 ];
1016+ // index using pointers
1017+ auto index1 = new immutable(int)*[arr.length];
1018+ makeIndex!("a < b")(arr, index1);
1019+ assert(isSorted!("*a < *b")(index1));
1020+ // index using offsets
1021+ auto index2 = new size_t[arr.length];
1022+ makeIndex!("a < b")(arr, index2);
1023+ assert(isSorted!
1024+ ((size_t a, size_t b){ return arr[a] < arr[b];})
1025+ (index2));
1026+}
1027+
1028+@system unittest
1029+{
1030+ immutable(int)[] arr = [ 2, 3, 1, 5, 0 ];
1031+ // index using pointers
1032+ auto index1 = new immutable(int)*[arr.length];
1033+ alias ImmRange = typeof(arr);
1034+ alias ImmIndex = typeof(index1);
1035+ static assert(isForwardRange!(ImmRange));
1036+ static assert(isRandomAccessRange!(ImmIndex));
1037+ static assert(!isIntegral!(ElementType!(ImmIndex)));
1038+ static assert(is(ElementType!(ImmIndex) : ElementType!(ImmRange)*));
1039+ makeIndex!("a < b")(arr, index1);
1040+ assert(isSorted!("*a < *b")(index1));
1041+
1042+ // index using offsets
1043+ auto index2 = new long[arr.length];
1044+ makeIndex(arr, index2);
1045+ assert(isSorted!
1046+ ((long a, long b){
1047+ return arr[cast(size_t) a] < arr[cast(size_t) b];
1048+ })(index2));
1049+
1050+ // index strings using offsets
1051+ string[] arr1 = ["I", "have", "no", "chocolate"];
1052+ auto index3 = new byte[arr1.length];
1053+ makeIndex(arr1, index3);
1054+ assert(isSorted!
1055+ ((byte a, byte b){ return arr1[a] < arr1[b];})
1056+ (index3));
1057+}
1058+
1059+@safe unittest
1060+{
1061+ import std.algorithm.comparison : equal;
1062+
1063+ ubyte[256] index = void;
1064+ iota(256).makeIndex(index[]);
1065+ assert(index[].equal(iota(256)));
1066+ byte[128] sindex = void;
1067+ iota(128).makeIndex(sindex[]);
1068+ assert(sindex[].equal(iota(128)));
1069+
1070+ auto index2 = new uint[10];
1071+ 10.iota.makeIndex(index2);
1072+ assert(index2.equal(10.iota));
1073+}
1074+
1075+struct Merge(alias less = "a < b", Rs...)
1076+if (Rs.length >= 2 &&
1077+ allSatisfy!(isInputRange, Rs) &&
1078+ !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1079+{
1080+ public Rs source;
1081+ private size_t _lastFrontIndex = size_t.max;
1082+ static if (isBidirectional)
1083+ {
1084+ private size_t _lastBackIndex = size_t.max; // `size_t.max` means uninitialized,
1085+ }
1086+
1087+ import std.functional : binaryFun;
1088+ import std.traits : isCopyable;
1089+ import std.typetuple : anySatisfy;
1090+
1091+ private alias comp = binaryFun!less;
1092+ private alias ElementType = CommonType!(staticMap!(.ElementType, Rs));
1093+ private enum isBidirectional = allSatisfy!(isBidirectionalRange, staticMap!(Unqual, Rs));
1094+
1095+ debug private enum canCheckSortedness = isCopyable!ElementType && !hasAliasing!ElementType;
1096+
1097+ this(Rs source)
1098+ {
1099+ this.source = source;
1100+ this._lastFrontIndex = frontIndex;
1101+ }
1102+
1103+ static if (anySatisfy!(isInfinite, Rs))
1104+ {
1105+ enum bool empty = false; // propagate infiniteness
1106+ }
1107+ else
1108+ {
1109+ @property bool empty()
1110+ {
1111+ return _lastFrontIndex == size_t.max;
1112+ }
1113+ }
1114+
1115+ @property auto ref front()
1116+ {
1117+ final switch (_lastFrontIndex)
1118+ {
1119+ foreach (i, _; Rs)
1120+ {
1121+ case i:
1122+ assert(!source[i].empty);
1123+ return source[i].front;
1124+ }
1125+ }
1126+ }
1127+
1128+ private size_t frontIndex()
1129+ {
1130+ size_t bestIndex = size_t.max; // indicate undefined
1131+ Unqual!ElementType bestElement;
1132+ foreach (i, _; Rs)
1133+ {
1134+ if (source[i].empty) continue;
1135+ if (bestIndex == size_t.max || // either this is the first or
1136+ comp(source[i].front, bestElement))
1137+ {
1138+ bestIndex = i;
1139+ bestElement = source[i].front;
1140+ }
1141+ }
1142+ return bestIndex;
1143+ }
1144+
1145+ void popFront()
1146+ {
1147+ sw: final switch (_lastFrontIndex)
1148+ {
1149+ foreach (i, R; Rs)
1150+ {
1151+ case i:
1152+ debug static if (canCheckSortedness)
1153+ {
1154+ ElementType previousFront = source[i].front();
1155+ }
1156+ source[i].popFront();
1157+ debug static if (canCheckSortedness)
1158+ {
1159+ if (!source[i].empty)
1160+ {
1161+ assert(previousFront == source[i].front ||
1162+ comp(previousFront, source[i].front),
1163+ "Input " ~ i.stringof ~ " is unsorted"); // @nogc
1164+ }
1165+ }
1166+ break sw;
1167+ }
1168+ }
1169+ _lastFrontIndex = frontIndex;
1170+ }
1171+
1172+ static if (isBidirectional)
1173+ {
1174+ @property auto ref back()
1175+ {
1176+ if (_lastBackIndex == size_t.max)
1177+ {
1178+ this._lastBackIndex = backIndex; // lazy initialization
1179+ }
1180+ final switch (_lastBackIndex)
1181+ {
1182+ foreach (i, _; Rs)
1183+ {
1184+ case i:
1185+ assert(!source[i].empty);
1186+ return source[i].back;
1187+ }
1188+ }
1189+ }
1190+
1191+ private size_t backIndex()
1192+ {
1193+ size_t bestIndex = size_t.max; // indicate undefined
1194+ Unqual!ElementType bestElement;
1195+ foreach (i, _; Rs)
1196+ {
1197+ if (source[i].empty) continue;
1198+ if (bestIndex == size_t.max || // either this is the first or
1199+ comp(bestElement, source[i].back))
1200+ {
1201+ bestIndex = i;
1202+ bestElement = source[i].back;
1203+ }
1204+ }
1205+ return bestIndex;
1206+ }
1207+
1208+ void popBack()
1209+ {
1210+ if (_lastBackIndex == size_t.max)
1211+ {
1212+ this._lastBackIndex = backIndex; // lazy initialization
1213+ }
1214+ sw: final switch (_lastBackIndex)
1215+ {
1216+ foreach (i, R; Rs)
1217+ {
1218+ case i:
1219+ debug static if (canCheckSortedness)
1220+ {
1221+ ElementType previousBack = source[i].back();
1222+ }
1223+ source[i].popBack();
1224+ debug static if (canCheckSortedness)
1225+ {
1226+ if (!source[i].empty)
1227+ {
1228+ assert(previousBack == source[i].back ||
1229+ comp(source[i].back, previousBack),
1230+ "Input " ~ i.stringof ~ " is unsorted"); // @nogc
1231+ }
1232+ }
1233+ break sw;
1234+ }
1235+ }
1236+ _lastBackIndex = backIndex;
1237+ if (_lastBackIndex == size_t.max) // if emptied
1238+ {
1239+ _lastFrontIndex = size_t.max;
1240+ }
1241+ }
1242+ }
1243+
1244+ static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
1245+ {
1246+ @property auto save()
1247+ {
1248+ auto result = this;
1249+ foreach (i, _; Rs)
1250+ {
1251+ result.source[i] = result.source[i].save;
1252+ }
1253+ return result;
1254+ }
1255+ }
1256+
1257+ static if (allSatisfy!(hasLength, Rs))
1258+ {
1259+ @property size_t length()
1260+ {
1261+ size_t result;
1262+ foreach (i, _; Rs)
1263+ {
1264+ result += source[i].length;
1265+ }
1266+ return result;
1267+ }
1268+
1269+ alias opDollar = length;
1270+ }
1271+}
1272+
1273+/**
1274+ Merge multiple sorted ranges `rs` with less-than predicate function `pred`
1275+ into one single sorted output range containing the sorted union of the
1276+ elements of inputs. Duplicates are not eliminated, meaning that the total
1277+ number of elements in the output is the sum of all elements in the ranges
1278+ passed to it; the `length` member is offered if all inputs also have
1279+ `length`. The element types of all the inputs must have a common type
1280+ `CommonType`.
1281+
1282+Params:
1283+ less = Predicate the given ranges are sorted by.
1284+ rs = The ranges to compute the union for.
1285+
1286+Returns:
1287+ A range containing the union of the given ranges.
1288+
1289+Details:
1290+
1291+All of its inputs are assumed to be sorted. This can mean that inputs are
1292+ instances of $(REF SortedRange, std,range). Use the result of $(REF sort,
1293+ std,algorithm,sorting), or $(REF assumeSorted, std,range) to merge ranges
1294+ known to be sorted (show in the example below). Note that there is currently
1295+ no way of ensuring that two or more instances of $(REF SortedRange,
1296+ std,range) are sorted using a specific comparison function `pred`. Therefore
1297+ no checking is done here to assure that all inputs `rs` are instances of
1298+ $(REF SortedRange, std,range).
1299+
1300+ This algorithm is lazy, doing work progressively as elements are pulled off
1301+ the result.
1302+
1303+ Time complexity is proportional to the sum of element counts over all inputs.
1304+
1305+ If all inputs have the same element type and offer it by `ref`, output
1306+ becomes a range with mutable `front` (and `back` where appropriate) that
1307+ reflects in the original inputs.
1308+
1309+ If any of the inputs `rs` is infinite so is the result (`empty` being always
1310+ `false`).
1311+*/
1312+Merge!(less, Rs) merge(alias less = "a < b", Rs...)(Rs rs)
1313+if (Rs.length >= 2 &&
1314+ allSatisfy!(isInputRange, Rs) &&
1315+ !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1316+{
1317+ return typeof(return)(rs);
1318+}
1319+
1320+///
1321+@safe pure nothrow unittest
1322+{
1323+ import std.algorithm.comparison : equal;
1324+ import std.range : retro;
1325+
1326+ int[] a = [1, 3, 5];
1327+ int[] b = [2, 3, 4];
1328+
1329+ assert(a.merge(b).equal([1, 2, 3, 3, 4, 5]));
1330+ assert(a.merge(b).retro.equal([5, 4, 3, 3, 2, 1]));
1331+}
1332+
1333+@safe pure nothrow unittest
1334+{
1335+ import std.algorithm.comparison : equal;
1336+
1337+ int[] a = [ 1, 2, 4, 5, 7, 9 ];
1338+ int[] b = [ 0, 1, 2, 4, 7, 8 ];
1339+ double[] c = [ 10.5 ];
1340+
1341+ assert(merge(a, b).length == a.length + b.length);
1342+ assert(equal(merge(a, b), [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][]));
1343+ assert(equal(merge(a, c, b),
1344+ [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9, 10.5][]));
1345+ auto u = merge(a, b);
1346+ u.front--;
1347+ assert(equal(u, [-1, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][]));
1348+}
1349+
1350+@safe pure nothrow unittest
1351+{
1352+ // save
1353+ import std.range : dropOne;
1354+ int[] a = [1, 2];
1355+ int[] b = [0, 3];
1356+ auto arr = a.merge(b);
1357+ assert(arr.front == 0);
1358+ assert(arr.save.dropOne.front == 1);
1359+ assert(arr.front == 0);
1360+}
1361+
1362+@safe pure nothrow unittest
1363+{
1364+ import std.algorithm.comparison : equal;
1365+ import std.internal.test.dummyrange;
1366+
1367+ auto dummyResult1 = [1, 1, 1.5, 2, 3, 4, 5, 5.5, 6, 7, 8, 9, 10];
1368+ auto dummyResult2 = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
1369+ 6, 6, 7, 7, 8, 8, 9, 9, 10, 10];
1370+ foreach (DummyType; AllDummyRanges)
1371+ {
1372+ DummyType d;
1373+ assert(d.merge([1, 1.5, 5.5]).equal(dummyResult1));
1374+ assert(d.merge(d).equal(dummyResult2));
1375+ }
1376+}
1377+
1378+@nogc @safe pure nothrow unittest
1379+{
1380+ import std.algorithm.comparison : equal;
1381+
1382+ static immutable a = [1, 3, 5];
1383+ static immutable b = [2, 3, 4];
1384+ static immutable r = [1, 2, 3, 3, 4, 5];
1385+ assert(a.merge(b).equal(r));
1386+}
1387+
1388+/// test bi-directional access and common type
1389+@safe pure nothrow unittest
1390+{
1391+ import std.algorithm.comparison : equal;
1392+ import std.range : retro;
1393+ import std.traits : CommonType;
1394+
1395+ alias S = short;
1396+ alias I = int;
1397+ alias D = double;
1398+
1399+ S[] a = [1, 2, 3];
1400+ I[] b = [50, 60];
1401+ D[] c = [10, 20, 30, 40];
1402+
1403+ auto m = merge(a, b, c);
1404+
1405+ static assert(is(typeof(m.front) == CommonType!(S, I, D)));
1406+
1407+ assert(equal(m, [1, 2, 3, 10, 20, 30, 40, 50, 60]));
1408+ assert(equal(m.retro, [60, 50, 40, 30, 20, 10, 3, 2, 1]));
1409+
1410+ m.popFront();
1411+ assert(equal(m, [2, 3, 10, 20, 30, 40, 50, 60]));
1412+ m.popBack();
1413+ assert(equal(m, [2, 3, 10, 20, 30, 40, 50]));
1414+ m.popFront();
1415+ assert(equal(m, [3, 10, 20, 30, 40, 50]));
1416+ m.popBack();
1417+ assert(equal(m, [3, 10, 20, 30, 40]));
1418+ m.popFront();
1419+ assert(equal(m, [10, 20, 30, 40]));
1420+ m.popBack();
1421+ assert(equal(m, [10, 20, 30]));
1422+ m.popFront();
1423+ assert(equal(m, [20, 30]));
1424+ m.popBack();
1425+ assert(equal(m, [20]));
1426+ m.popFront();
1427+ assert(m.empty);
1428+}
1429+
1430+private template validPredicates(E, less...)
1431+{
1432+ static if (less.length == 0)
1433+ enum validPredicates = true;
1434+ else static if (less.length == 1 && is(typeof(less[0]) == SwapStrategy))
1435+ enum validPredicates = true;
1436+ else
1437+ enum validPredicates =
1438+ is(typeof((E a, E b){ bool r = binaryFun!(less[0])(a, b); }))
1439+ && validPredicates!(E, less[1 .. $]);
1440+}
1441+
1442+/**
1443+$(D auto multiSort(Range)(Range r)
1444+ if (validPredicates!(ElementType!Range, less));)
1445+
1446+Sorts a range by multiple keys. The call $(D multiSort!("a.id < b.id",
1447+"a.date > b.date")(r)) sorts the range $(D r) by $(D id) ascending,
1448+and sorts elements that have the same $(D id) by $(D date)
1449+descending. Such a call is equivalent to $(D sort!"a.id != b.id ? a.id
1450+< b.id : a.date > b.date"(r)), but $(D multiSort) is faster because it
1451+does fewer comparisons (in addition to being more convenient).
1452+
1453+Returns:
1454+ The initial range wrapped as a $(D SortedRange) with its predicates
1455+ converted to an equivalent single predicate.
1456+ */
1457+template multiSort(less...) //if (less.length > 1)
1458+{
1459+ auto multiSort(Range)(Range r)
1460+ if (validPredicates!(ElementType!Range, less))
1461+ {
1462+ import std.meta : AliasSeq;
1463+ import std.range : assumeSorted;
1464+ static if (is(typeof(less[$ - 1]) == SwapStrategy))
1465+ {
1466+ enum ss = less[$ - 1];
1467+ alias funs = less[0 .. $ - 1];
1468+ }
1469+ else
1470+ {
1471+ enum ss = SwapStrategy.unstable;
1472+ alias funs = less;
1473+ }
1474+
1475+ static if (funs.length == 0)
1476+ static assert(false, "No sorting predicate provided for multiSort");
1477+ else
1478+ static if (funs.length == 1)
1479+ return sort!(funs[0], ss, Range)(r);
1480+ else
1481+ {
1482+ multiSortImpl!(Range, ss, funs)(r);
1483+ return assumeSorted!(multiSortPredFun!(Range, funs))(r);
1484+ }
1485+ }
1486+}
1487+
1488+private bool multiSortPredFun(Range, funs...)(ElementType!Range a, ElementType!Range b)
1489+{
1490+ foreach (f; funs)
1491+ {
1492+ alias lessFun = binaryFun!(f);
1493+ if (lessFun(a, b)) return true;
1494+ if (lessFun(b, a)) return false;
1495+ }
1496+ return false;
1497+}
1498+
1499+private void multiSortImpl(Range, SwapStrategy ss, funs...)(Range r)
1500+{
1501+ alias lessFun = binaryFun!(funs[0]);
1502+
1503+ static if (funs.length > 1)
1504+ {
1505+ while (r.length > 1)
1506+ {
1507+ auto p = getPivot!lessFun(r);
1508+ auto t = partition3!(funs[0], ss)(r, r[p]);
1509+ if (t[0].length <= t[2].length)
1510+ {
1511+ multiSortImpl!(Range, ss, funs)(t[0]);
1512+ multiSortImpl!(Range, ss, funs[1 .. $])(t[1]);
1513+ r = t[2];
1514+ }
1515+ else
1516+ {
1517+ multiSortImpl!(Range, ss, funs[1 .. $])(t[1]);
1518+ multiSortImpl!(Range, ss, funs)(t[2]);
1519+ r = t[0];
1520+ }
1521+ }
1522+ }
1523+ else
1524+ {
1525+ sort!(lessFun, ss)(r);
1526+ }
1527+}
1528+
1529+///
1530+@safe unittest
1531+{
1532+ import std.algorithm.mutation : SwapStrategy;
1533+ static struct Point { int x, y; }
1534+ auto pts1 = [ Point(0, 0), Point(5, 5), Point(0, 1), Point(0, 2) ];
1535+ auto pts2 = [ Point(0, 0), Point(0, 1), Point(0, 2), Point(5, 5) ];
1536+ multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1);
1537+ assert(pts1 == pts2);
1538+}
1539+
1540+@safe unittest
1541+{
1542+ import std.algorithm.comparison : equal;
1543+ import std.range;
1544+
1545+ static struct Point { int x, y; }
1546+ auto pts1 = [ Point(5, 6), Point(1, 0), Point(5, 7), Point(1, 1), Point(1, 2), Point(0, 1) ];
1547+ auto pts2 = [ Point(0, 1), Point(1, 0), Point(1, 1), Point(1, 2), Point(5, 6), Point(5, 7) ];
1548+ static assert(validPredicates!(Point, "a.x < b.x", "a.y < b.y"));
1549+ multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1);
1550+ assert(pts1 == pts2);
1551+
1552+ auto pts3 = indexed(pts1, iota(pts1.length));
1553+ assert(pts3.multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable).release.equal(pts2));
1554+
1555+ auto pts4 = iota(10).array;
1556+ assert(pts4.multiSort!("a > b").release.equal(iota(10).retro));
1557+}
1558+
1559+@safe unittest //issue 9160 (L-value only comparators)
1560+{
1561+ static struct A
1562+ {
1563+ int x;
1564+ int y;
1565+ }
1566+
1567+ static bool byX(const ref A lhs, const ref A rhs)
1568+ {
1569+ return lhs.x < rhs.x;
1570+ }
1571+
1572+ static bool byY(const ref A lhs, const ref A rhs)
1573+ {
1574+ return lhs.y < rhs.y;
1575+ }
1576+
1577+ auto points = [ A(4, 1), A(2, 4)];
1578+ multiSort!(byX, byY)(points);
1579+ assert(points[0] == A(2, 4));
1580+ assert(points[1] == A(4, 1));
1581+}
1582+
1583+@safe unittest // issue 16179 (cannot access frame of function)
1584+{
1585+ auto arr = [[1, 2], [2, 0], [1, 0], [1, 1]];
1586+ int c = 3;
1587+
1588+ arr.multiSort!(
1589+ (a, b) => a[0] < b[0],
1590+ (a, b) => c*a[1] < c*b[1]
1591+ );
1592+ assert(arr == [[1, 0], [1, 1], [1, 2], [2, 0]]);
1593+}
1594+
1595+@safe unittest //Issue 16413 - @system comparison function
1596+{
1597+ bool lt(int a, int b) { return a < b; } static @system
1598+ auto a = [2, 1];
1599+ a.multiSort!(lt, lt);
1600+ assert(a == [1, 2]);
1601+}
1602+
1603+private size_t getPivot(alias less, Range)(Range r)
1604+{
1605+ auto mid = r.length / 2;
1606+ if (r.length < 512)
1607+ {
1608+ if (r.length >= 32)
1609+ medianOf!less(r, size_t(0), mid, r.length - 1);
1610+ return mid;
1611+ }
1612+
1613+ // The plan here is to take the median of five by taking five elements in
1614+ // the array, segregate around their median, and return the position of the
1615+ // third. We choose first, mid, last, and two more in between those.
1616+
1617+ auto quarter = r.length / 4;
1618+ medianOf!less(r,
1619+ size_t(0), mid - quarter, mid, mid + quarter, r.length - 1);
1620+ return mid;
1621+}
1622+
1623+/*
1624+Sorting routine that is optimized for short ranges. Note: uses insertion sort
1625+going downward. Benchmarked a similar routine that goes upward, for some reason
1626+it's slower.
1627+*/
1628+private void shortSort(alias less, Range)(Range r)
1629+{
1630+ import std.algorithm.mutation : swapAt;
1631+ alias pred = binaryFun!(less);
1632+
1633+ switch (r.length)
1634+ {
1635+ case 0: case 1:
1636+ return;
1637+ case 2:
1638+ if (pred(r[1], r[0])) r.swapAt(0, 1);
1639+ return;
1640+ case 3:
1641+ if (pred(r[2], r[0]))
1642+ {
1643+ if (pred(r[0], r[1]))
1644+ {
1645+ r.swapAt(0, 1);
1646+ r.swapAt(0, 2);
1647+ }
1648+ else
1649+ {
1650+ r.swapAt(0, 2);
1651+ if (pred(r[1], r[0])) r.swapAt(0, 1);
1652+ }
1653+ }
1654+ else
1655+ {
1656+ if (pred(r[1], r[0]))
1657+ {
1658+ r.swapAt(0, 1);
1659+ }
1660+ else
1661+ {
1662+ if (pred(r[2], r[1])) r.swapAt(1, 2);
1663+ }
1664+ }
1665+ return;
1666+ case 4:
1667+ if (pred(r[1], r[0])) r.swapAt(0, 1);
1668+ if (pred(r[3], r[2])) r.swapAt(2, 3);
1669+ if (pred(r[2], r[0])) r.swapAt(0, 2);
1670+ if (pred(r[3], r[1])) r.swapAt(1, 3);
1671+ if (pred(r[2], r[1])) r.swapAt(1, 2);
1672+ return;
1673+ default:
1674+ sort5!pred(r[r.length - 5 .. r.length]);
1675+ if (r.length == 5) return;
1676+ break;
1677+ }
1678+
1679+ assert(r.length >= 6);
1680+ /* The last 5 elements of the range are sorted. Proceed with expanding the
1681+ sorted portion downward. */
1682+ immutable maxJ = r.length - 2;
1683+ for (size_t i = r.length - 6; ; --i)
1684+ {
1685+ static if (is(typeof(() nothrow
1686+ {
1687+ auto t = r[0]; if (pred(t, r[0])) r[0] = r[0];
1688+ }))) // Can we afford to temporarily invalidate the array?
1689+ {
1690+ size_t j = i + 1;
1691+ auto temp = r[i];
1692+ if (pred(r[j], temp))
1693+ {
1694+ do
1695+ {
1696+ r[j - 1] = r[j];
1697+ ++j;
1698+ }
1699+ while (j < r.length && pred(r[j], temp));
1700+ r[j - 1] = temp;
1701+ }
1702+ }
1703+ else
1704+ {
1705+ size_t j = i;
1706+ while (pred(r[j + 1], r[j]))
1707+ {
1708+ r.swapAt(j, j + 1);
1709+ if (j == maxJ) break;
1710+ ++j;
1711+ }
1712+ }
1713+ if (i == 0) break;
1714+ }
1715+}
1716+
1717+@safe unittest
1718+{
1719+ import std.random : Random, uniform;
1720+
1721+ auto rnd = Random(1);
1722+ auto a = new int[uniform(100, 200, rnd)];
1723+ foreach (ref e; a)
1724+ {
1725+ e = uniform(-100, 100, rnd);
1726+ }
1727+
1728+ shortSort!(binaryFun!("a < b"), int[])(a);
1729+ assert(isSorted(a));
1730+}
1731+
1732+/*
1733+Sorts the first 5 elements exactly of range r.
1734+*/
1735+private void sort5(alias lt, Range)(Range r)
1736+{
1737+ assert(r.length >= 5);
1738+
1739+ import std.algorithm.mutation : swapAt;
1740+
1741+ // 1. Sort first two pairs
1742+ if (lt(r[1], r[0])) r.swapAt(0, 1);
1743+ if (lt(r[3], r[2])) r.swapAt(2, 3);
1744+
1745+ // 2. Arrange first two pairs by the largest element
1746+ if (lt(r[3], r[1]))
1747+ {
1748+ r.swapAt(0, 2);
1749+ r.swapAt(1, 3);
1750+ }
1751+ assert(!lt(r[1], r[0]) && !lt(r[3], r[1]) && !lt(r[3], r[2]));
1752+
1753+ // 3. Insert 4 into [0, 1, 3]
1754+ if (lt(r[4], r[1]))
1755+ {
1756+ r.swapAt(3, 4);
1757+ r.swapAt(1, 3);
1758+ if (lt(r[1], r[0]))
1759+ {
1760+ r.swapAt(0, 1);
1761+ }
1762+ }
1763+ else if (lt(r[4], r[3]))
1764+ {
1765+ r.swapAt(3, 4);
1766+ }
1767+ assert(!lt(r[1], r[0]) && !lt(r[3], r[1]) && !lt(r[4], r[3]));
1768+
1769+ // 4. Insert 2 into [0, 1, 3, 4] (note: we already know the last is greater)
1770+ assert(!lt(r[4], r[2]));
1771+ if (lt(r[2], r[1]))
1772+ {
1773+ r.swapAt(1, 2);
1774+ if (lt(r[1], r[0]))
1775+ {
1776+ r.swapAt(0, 1);
1777+ }
1778+ }
1779+ else if (lt(r[3], r[2]))
1780+ {
1781+ r.swapAt(2, 3);
1782+ }
1783+ // 7 comparisons, 0-9 swaps
1784+}
1785+
1786+@safe unittest
1787+{
1788+ import std.algorithm.iteration : permutations;
1789+ import std.algorithm.mutation : copy;
1790+
1791+ int[5] buf;
1792+ foreach (per; iota(5).permutations)
1793+ {
1794+ per.copy(buf[]);
1795+ sort5!((a, b) => a < b)(buf[]);
1796+ assert(buf[].isSorted);
1797+ }
1798+}
1799+
1800+// sort
1801+/**
1802+Sorts a random-access range according to the predicate $(D less). Performs
1803+$(BIGOH r.length * log(r.length)) evaluations of $(D less). If `less` involves
1804+expensive computations on the _sort key, it may be worthwhile to use
1805+$(LREF schwartzSort) instead.
1806+
1807+Stable sorting requires $(D hasAssignableElements!Range) to be true.
1808+
1809+$(D sort) returns a $(REF SortedRange, std,range) over the original range,
1810+allowing functions that can take advantage of sorted data to know that the
1811+range is sorted and adjust accordingly. The $(REF SortedRange, std,range) is a
1812+wrapper around the original range, so both it and the original range are sorted.
1813+Other functions can't know that the original range has been sorted, but
1814+they $(I can) know that $(REF SortedRange, std,range) has been sorted.
1815+
1816+Preconditions:
1817+
1818+The predicate is expected to satisfy certain rules in order for $(D sort) to
1819+behave as expected - otherwise, the program may fail on certain inputs (but not
1820+others) when not compiled in release mode, due to the cursory $(D assumeSorted)
1821+check. Specifically, $(D sort) expects $(D less(a,b) && less(b,c)) to imply
1822+$(D less(a,c)) (transitivity), and, conversely, $(D !less(a,b) && !less(b,c)) to
1823+imply $(D !less(a,c)). Note that the default predicate ($(D "a < b")) does not
1824+always satisfy these conditions for floating point types, because the expression
1825+will always be $(D false) when either $(D a) or $(D b) is NaN.
1826+Use $(REF cmp, std,math) instead.
1827+
1828+Params:
1829+ less = The predicate to sort by.
1830+ ss = The swapping strategy to use.
1831+ r = The range to sort.
1832+
1833+Returns: The initial range wrapped as a $(D SortedRange) with the predicate
1834+$(D binaryFun!less).
1835+
1836+Algorithms: $(HTTP en.wikipedia.org/wiki/Introsort, Introsort) is used for unstable sorting and
1837+$(HTTP en.wikipedia.org/wiki/Timsort, Timsort) is used for stable sorting.
1838+Each algorithm has benefits beyond stability. Introsort is generally faster but
1839+Timsort may achieve greater speeds on data with low entropy or if predicate calls
1840+are expensive. Introsort performs no allocations whereas Timsort will perform one
1841+or more allocations per call. Both algorithms have $(BIGOH n log n) worst-case
1842+time complexity.
1843+
1844+See_Also:
1845+ $(REF assumeSorted, std,range)$(BR)
1846+ $(REF SortedRange, std,range)$(BR)
1847+ $(REF SwapStrategy, std,algorithm,mutation)$(BR)
1848+ $(REF binaryFun, std,functional)
1849+*/
1850+SortedRange!(Range, less)
1851+sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
1852+ Range)(Range r)
1853+if (((ss == SwapStrategy.unstable && (hasSwappableElements!Range ||
1854+ hasAssignableElements!Range)) ||
1855+ (ss != SwapStrategy.unstable && hasAssignableElements!Range)) &&
1856+ isRandomAccessRange!Range &&
1857+ hasSlicing!Range &&
1858+ hasLength!Range)
1859+ /+ Unstable sorting uses the quicksort algorithm, which uses swapAt,
1860+ which either uses swap(...), requiring swappable elements, or just
1861+ swaps using assignment.
1862+ Stable sorting uses TimSort, which needs to copy elements into a buffer,
1863+ requiring assignable elements. +/
1864+{
1865+ import std.range : assumeSorted;
1866+ alias lessFun = binaryFun!(less);
1867+ alias LessRet = typeof(lessFun(r.front, r.front)); // instantiate lessFun
1868+ static if (is(LessRet == bool))
1869+ {
1870+ static if (ss == SwapStrategy.unstable)
1871+ quickSortImpl!(lessFun)(r, r.length);
1872+ else //use Tim Sort for semistable & stable
1873+ TimSortImpl!(lessFun, Range).sort(r, null);
1874+
1875+ assert(isSorted!lessFun(r), "Failed to sort range of type " ~ Range.stringof);
1876+ }
1877+ else
1878+ {
1879+ static assert(false, "Invalid predicate passed to sort: " ~ less.stringof);
1880+ }
1881+ return assumeSorted!less(r);
1882+}
1883+
1884+///
1885+@safe pure nothrow unittest
1886+{
1887+ int[] array = [ 1, 2, 3, 4 ];
1888+
1889+ // sort in descending order
1890+ array.sort!("a > b");
1891+ assert(array == [ 4, 3, 2, 1 ]);
1892+
1893+ // sort in ascending order
1894+ array.sort();
1895+ assert(array == [ 1, 2, 3, 4 ]);
1896+
1897+ // sort with reusable comparator and chain
1898+ alias myComp = (x, y) => x > y;
1899+ assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]);
1900+}
1901+
1902+///
1903+@safe unittest
1904+{
1905+ // Showcase stable sorting
1906+ import std.algorithm.mutation : SwapStrategy;
1907+ string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
1908+ sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words);
1909+ assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
1910+}
1911+
1912+///
1913+@safe unittest
1914+{
1915+ // Sorting floating-point numbers in presence of NaN
1916+ double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan];
1917+
1918+ import std.algorithm.comparison : equal;
1919+ import std.math : cmp, isIdentical;
1920+
1921+ sort!((a, b) => cmp(a, b) < 0)(numbers);
1922+
1923+ double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan];
1924+ assert(numbers.equal!isIdentical(sorted));
1925+}
1926+
1927+@safe unittest
1928+{
1929+ // Simple regression benchmark
1930+ import std.algorithm.iteration, std.algorithm.mutation, std.random;
1931+ Random rng;
1932+ int[] a = iota(20148).map!(_ => uniform(-1000, 1000, rng)).array;
1933+ static uint comps;
1934+ static bool less(int a, int b) { ++comps; return a < b; }
1935+ sort!less(a); // random numbers
1936+ sort!less(a); // sorted ascending
1937+ a.reverse();
1938+ sort!less(a); // sorted descending
1939+ a[] = 0;
1940+ sort!less(a); // all equal
1941+
1942+ // This should get smaller with time. On occasion it may go larger, but only
1943+ // if there's thorough justification.
1944+ debug enum uint watermark = 1676280;
1945+ else enum uint watermark = 1676220;
1946+
1947+ import std.conv;
1948+ assert(comps <= watermark, text("You seem to have pessimized sort! ",
1949+ watermark, " < ", comps));
1950+ assert(comps >= watermark, text("You seem to have improved sort!",
1951+ " Please update watermark from ", watermark, " to ", comps));
1952+}
1953+
1954+@safe unittest
1955+{
1956+ import std.algorithm.internal : rndstuff;
1957+ import std.algorithm.mutation : swapRanges;
1958+ import std.random : Random, unpredictableSeed, uniform;
1959+ import std.uni : toUpper;
1960+
1961+ // sort using delegate
1962+ auto a = new int[100];
1963+ auto rnd = Random(unpredictableSeed);
1964+ foreach (ref e; a)
1965+ {
1966+ e = uniform(-100, 100, rnd);
1967+ }
1968+
1969+ int i = 0;
1970+ bool greater2(int a, int b) @safe { return a + i > b + i; }
1971+ auto greater = &greater2;
1972+ sort!(greater)(a);
1973+ assert(isSorted!(greater)(a));
1974+
1975+ // sort using string
1976+ sort!("a < b")(a);
1977+ assert(isSorted!("a < b")(a));
1978+
1979+ // sort using function; all elements equal
1980+ foreach (ref e; a)
1981+ {
1982+ e = 5;
1983+ }
1984+ static bool less(int a, int b) { return a < b; }
1985+ sort!(less)(a);
1986+ assert(isSorted!(less)(a));
1987+
1988+ string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
1989+ bool lessi(string a, string b) { return toUpper(a) < toUpper(b); }
1990+ sort!(lessi, SwapStrategy.stable)(words);
1991+ assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
1992+
1993+ // sort using ternary predicate
1994+ //sort!("b - a")(a);
1995+ //assert(isSorted!(less)(a));
1996+
1997+ a = rndstuff!(int)();
1998+ sort(a);
1999+ assert(isSorted(a));
2000+ auto b = rndstuff!(string)();
2001+ sort!("toLower(a) < toLower(b)")(b);
2002+ assert(isSorted!("toUpper(a) < toUpper(b)")(b));
2003+
2004+ {
2005+ // Issue 10317
2006+ enum E_10317 { a, b }
2007+ auto a_10317 = new E_10317[10];
2008+ sort(a_10317);
2009+ }
2010+
2011+ {
2012+ // Issue 7767
2013+ // Unstable sort should complete without an excessive number of predicate calls
2014+ // This would suggest it's running in quadratic time
2015+
2016+ // Compilation error if predicate is not static, i.e. a nested function
2017+ static uint comp;
2018+ static bool pred(size_t a, size_t b)
2019+ {
2020+ ++comp;
2021+ return a < b;
2022+ }
2023+
2024+ size_t[] arr;
2025+ arr.length = 1024;
2026+
2027+ foreach (k; 0 .. arr.length) arr[k] = k;
2028+ swapRanges(arr[0..$/2], arr[$/2..$]);
2029+
2030+ sort!(pred, SwapStrategy.unstable)(arr);
2031+ assert(comp < 25_000);
2032+ }
2033+
2034+ {
2035+ import std.algorithm.mutation : swap;
2036+
2037+ bool proxySwapCalled;
2038+ struct S
2039+ {
2040+ int i;
2041+ alias i this;
2042+ void proxySwap(ref S other) { swap(i, other.i); proxySwapCalled = true; }
2043+ @disable void opAssign(S value);
2044+ }
2045+
2046+ alias R = S[];
2047+ R r = [S(3), S(2), S(1)];
2048+ static assert(hasSwappableElements!R);
2049+ static assert(!hasAssignableElements!R);
2050+ r.sort();
2051+ assert(proxySwapCalled);
2052+ }
2053+}
2054+
2055+private void quickSortImpl(alias less, Range)(Range r, size_t depth)
2056+{
2057+ import std.algorithm.comparison : min, max;
2058+ import std.algorithm.mutation : swap, swapAt;
2059+
2060+ alias Elem = ElementType!(Range);
2061+ enum size_t shortSortGetsBetter = max(32, 1024 / Elem.sizeof);
2062+ static assert(shortSortGetsBetter >= 1);
2063+
2064+ // partition
2065+ while (r.length > shortSortGetsBetter)
2066+ {
2067+ if (depth == 0)
2068+ {
2069+ HeapOps!(less, Range).heapSort(r);
2070+ return;
2071+ }
2072+ depth = depth >= depth.max / 2 ? (depth / 3) * 2 : (depth * 2) / 3;
2073+
2074+ const pivotIdx = getPivot!(less)(r);
2075+ auto pivot = r[pivotIdx];
2076+
2077+ // partition
2078+ r.swapAt(pivotIdx, r.length - 1);
2079+ size_t lessI = size_t.max, greaterI = r.length - 1;
2080+
2081+ outer: for (;;)
2082+ {
2083+ alias pred = binaryFun!less;
2084+ while (pred(r[++lessI], pivot)) {}
2085+ assert(lessI <= greaterI, "sort: invalid comparison function.");
2086+ for (;;)
2087+ {
2088+ if (greaterI == lessI) break outer;
2089+ if (!pred(pivot, r[--greaterI])) break;
2090+ }
2091+ assert(lessI <= greaterI, "sort: invalid comparison function.");
2092+ if (lessI == greaterI) break;
2093+ r.swapAt(lessI, greaterI);
2094+ }
2095+
2096+ r.swapAt(r.length - 1, lessI);
2097+ auto left = r[0 .. lessI], right = r[lessI + 1 .. r.length];
2098+ if (right.length > left.length)
2099+ {
2100+ swap(left, right);
2101+ }
2102+ .quickSortImpl!(less, Range)(right, depth);
2103+ r = left;
2104+ }
2105+ // residual sort
2106+ static if (shortSortGetsBetter > 1)
2107+ {
2108+ shortSort!(less, Range)(r);
2109+ }
2110+}
2111+
2112+// Heap operations for random-access ranges
2113+package(std) template HeapOps(alias less, Range)
2114+{
2115+ import std.algorithm.mutation : swapAt;
2116+
2117+ static assert(isRandomAccessRange!Range);
2118+ static assert(hasLength!Range);
2119+ static assert(hasSwappableElements!Range || hasAssignableElements!Range);
2120+
2121+ alias lessFun = binaryFun!less;
2122+
2123+ //template because of @@@12410@@@
2124+ void heapSort()(Range r)
2125+ {
2126+ // If true, there is nothing to do
2127+ if (r.length < 2) return;
2128+ // Build Heap
2129+ buildHeap(r);
2130+ // Sort
2131+ for (size_t i = r.length - 1; i > 0; --i)
2132+ {
2133+ r.swapAt(0, i);
2134+ percolate(r, 0, i);
2135+ }
2136+ }
2137+
2138+ //template because of @@@12410@@@
2139+ void buildHeap()(Range r)
2140+ {
2141+ immutable n = r.length;
2142+ for (size_t i = n / 2; i-- > 0; )
2143+ {
2144+ siftDown(r, i, n);
2145+ }
2146+ assert(isHeap(r));
2147+ }
2148+
2149+ bool isHeap()(Range r)
2150+ {
2151+ size_t parent = 0;
2152+ foreach (child; 1 .. r.length)
2153+ {
2154+ if (lessFun(r[parent], r[child])) return false;
2155+ // Increment parent every other pass
2156+ parent += !(child & 1);
2157+ }
2158+ return true;
2159+ }
2160+
2161+ // Sifts down r[parent] (which is initially assumed to be messed up) so the
2162+ // heap property is restored for r[parent .. end].
2163+ // template because of @@@12410@@@
2164+ void siftDown()(Range r, size_t parent, immutable size_t end)
2165+ {
2166+ for (;;)
2167+ {
2168+ auto child = (parent + 1) * 2;
2169+ if (child >= end)
2170+ {
2171+ // Leftover left child?
2172+ if (child == end && lessFun(r[parent], r[--child]))
2173+ r.swapAt(parent, child);
2174+ break;
2175+ }
2176+ auto leftChild = child - 1;
2177+ if (lessFun(r[child], r[leftChild])) child = leftChild;
2178+ if (!lessFun(r[parent], r[child])) break;
2179+ r.swapAt(parent, child);
2180+ parent = child;
2181+ }
2182+ }
2183+
2184+ // Alternate version of siftDown that performs fewer comparisons, see
2185+ // https://en.wikipedia.org/wiki/Heapsort#Bottom-up_heapsort. The percolate
2186+ // process first sifts the parent all the way down (without comparing it
2187+ // against the leaves), and then a bit up until the heap property is
2188+ // restored. So there are more swaps but fewer comparisons. Gains are made
2189+ // when the final position is likely to end toward the bottom of the heap,
2190+ // so not a lot of sifts back are performed.
2191+ //template because of @@@12410@@@
2192+ void percolate()(Range r, size_t parent, immutable size_t end)
2193+ {
2194+ immutable root = parent;
2195+
2196+ // Sift down
2197+ for (;;)
2198+ {
2199+ auto child = (parent + 1) * 2;
2200+
2201+ if (child >= end)
2202+ {
2203+ if (child == end)
2204+ {
2205+ // Leftover left node.
2206+ --child;
2207+ r.swapAt(parent, child);
2208+ parent = child;
2209+ }
2210+ break;
2211+ }
2212+
2213+ auto leftChild = child - 1;
2214+ if (lessFun(r[child], r[leftChild])) child = leftChild;
2215+ r.swapAt(parent, child);
2216+ parent = child;
2217+ }
2218+
2219+ // Sift up
2220+ for (auto child = parent; child > root; child = parent)
2221+ {
2222+ parent = (child - 1) / 2;
2223+ if (!lessFun(r[parent], r[child])) break;
2224+ r.swapAt(parent, child);
2225+ }
2226+ }
2227+}
2228+
2229+// Tim Sort implementation
2230+private template TimSortImpl(alias pred, R)
2231+{
2232+ import core.bitop : bsr;
2233+ import std.array : uninitializedArray;
2234+
2235+ static assert(isRandomAccessRange!R);
2236+ static assert(hasLength!R);
2237+ static assert(hasSlicing!R);
2238+ static assert(hasAssignableElements!R);
2239+
2240+ alias T = ElementType!R;
2241+
2242+ alias less = binaryFun!pred;
2243+ alias greater = (a, b) => less(b, a);
2244+ alias greaterEqual = (a, b) => !less(a, b);
2245+ alias lessEqual = (a, b) => !less(b, a);
2246+
2247+ enum minimalMerge = 128;
2248+ enum minimalGallop = 7;
2249+ enum minimalStorage = 256;
2250+ enum stackSize = 40;
2251+
2252+ struct Slice{ size_t base, length; }
2253+
2254+ // Entry point for tim sort
2255+ void sort()(R range, T[] temp)
2256+ {
2257+ import std.algorithm.comparison : min;
2258+
2259+ // Do insertion sort on small range
2260+ if (range.length <= minimalMerge)
2261+ {
2262+ binaryInsertionSort(range);
2263+ return;
2264+ }
2265+
2266+ immutable minRun = minRunLength(range.length);
2267+ immutable minTemp = min(range.length / 2, minimalStorage);
2268+ size_t minGallop = minimalGallop;
2269+ Slice[stackSize] stack = void;
2270+ size_t stackLen = 0;
2271+
2272+ // Allocate temporary memory if not provided by user
2273+ if (temp.length < minTemp) temp = () @trusted { return uninitializedArray!(T[])(minTemp); }();
2274+
2275+ for (size_t i = 0; i < range.length; )
2276+ {
2277+ // Find length of first run in list
2278+ size_t runLen = firstRun(range[i .. range.length]);
2279+
2280+ // If run has less than minRun elements, extend using insertion sort
2281+ if (runLen < minRun)
2282+ {
2283+ // Do not run farther than the length of the range
2284+ immutable force = range.length - i > minRun ? minRun : range.length - i;
2285+ binaryInsertionSort(range[i .. i + force], runLen);
2286+ runLen = force;
2287+ }
2288+
2289+ // Push run onto stack
2290+ stack[stackLen++] = Slice(i, runLen);
2291+ i += runLen;
2292+
2293+ // Collapse stack so that (e1 > e2 + e3 && e2 > e3)
2294+ // STACK is | ... e1 e2 e3 >
2295+ while (stackLen > 1)
2296+ {
2297+ immutable run4 = stackLen - 1;
2298+ immutable run3 = stackLen - 2;
2299+ immutable run2 = stackLen - 3;
2300+ immutable run1 = stackLen - 4;
2301+
2302+ if ( (stackLen > 2 && stack[run2].length <= stack[run3].length + stack[run4].length) ||
2303+ (stackLen > 3 && stack[run1].length <= stack[run3].length + stack[run2].length) )
2304+ {
2305+ immutable at = stack[run2].length < stack[run4].length ? run2 : run3;
2306+ mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
2307+ }
2308+ else if (stack[run3].length > stack[run4].length) break;
2309+ else mergeAt(range, stack[0 .. stackLen], run3, minGallop, temp);
2310+
2311+ stackLen -= 1;
2312+ }
2313+
2314+ // Assert that the code above established the invariant correctly
2315+ version (assert)
2316+ {
2317+ if (stackLen == 2) assert(stack[0].length > stack[1].length);
2318+ else if (stackLen > 2)
2319+ {
2320+ foreach (k; 2 .. stackLen)
2321+ {
2322+ assert(stack[k - 2].length > stack[k - 1].length + stack[k].length);
2323+ assert(stack[k - 1].length > stack[k].length);
2324+ }
2325+ }
2326+ }
2327+ }
2328+
2329+ // Force collapse stack until there is only one run left
2330+ while (stackLen > 1)
2331+ {
2332+ immutable run3 = stackLen - 1;
2333+ immutable run2 = stackLen - 2;
2334+ immutable run1 = stackLen - 3;
2335+ immutable at = stackLen >= 3 && stack[run1].length <= stack[run3].length
2336+ ? run1 : run2;
2337+ mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
2338+ --stackLen;
2339+ }
2340+ }
2341+
2342+ // Calculates optimal value for minRun:
2343+ // take first 6 bits of n and add 1 if any lower bits are set
2344+ size_t minRunLength()(size_t n)
2345+ {
2346+ immutable shift = bsr(n)-5;
2347+ auto result = (n >> shift) + !!(n & ~((1 << shift)-1));
2348+ return result;
2349+ }
2350+
2351+ // Returns length of first run in range
2352+ size_t firstRun()(R range)
2353+ out(ret)
2354+ {
2355+ assert(ret <= range.length);
2356+ }
2357+ body
2358+ {
2359+ import std.algorithm.mutation : reverse;
2360+
2361+ if (range.length < 2) return range.length;
2362+
2363+ size_t i = 2;
2364+ if (lessEqual(range[0], range[1]))
2365+ {
2366+ while (i < range.length && lessEqual(range[i-1], range[i])) ++i;
2367+ }
2368+ else
2369+ {
2370+ while (i < range.length && greater(range[i-1], range[i])) ++i;
2371+ reverse(range[0 .. i]);
2372+ }
2373+ return i;
2374+ }
2375+
2376+ // A binary insertion sort for building runs up to minRun length
2377+ void binaryInsertionSort()(R range, size_t sortedLen = 1)
2378+ out
2379+ {
2380+ if (!__ctfe) assert(isSorted!pred(range));
2381+ }
2382+ body
2383+ {
2384+ import std.algorithm.mutation : move;
2385+
2386+ for (; sortedLen < range.length; ++sortedLen)
2387+ {
2388+ T item = range.moveAt(sortedLen);
2389+ size_t lower = 0;
2390+ size_t upper = sortedLen;
2391+ while (upper != lower)
2392+ {
2393+ size_t center = (lower + upper) / 2;
2394+ if (less(item, range[center])) upper = center;
2395+ else lower = center + 1;
2396+ }
2397+ //Currently (DMD 2.061) moveAll+retro is slightly less
2398+ //efficient then stright 'for' loop
2399+ //11 instructions vs 7 in the innermost loop [checked on Win32]
2400+ //moveAll(retro(range[lower .. sortedLen]),
2401+ // retro(range[lower+1 .. sortedLen+1]));
2402+ for (upper=sortedLen; upper > lower; upper--)
2403+ range[upper] = range.moveAt(upper - 1);
2404+ range[lower] = move(item);
2405+ }
2406+ }
2407+
2408+ // Merge two runs in stack (at, at + 1)
2409+ void mergeAt()(R range, Slice[] stack, immutable size_t at, ref size_t minGallop, ref T[] temp)
2410+ in
2411+ {
2412+ assert(stack.length >= 2);
2413+ assert(stack.length - at == 2 || stack.length - at == 3);
2414+ }
2415+ body
2416+ {
2417+ immutable base = stack[at].base;
2418+ immutable mid = stack[at].length;
2419+ immutable len = stack[at + 1].length + mid;
2420+
2421+ // Pop run from stack
2422+ stack[at] = Slice(base, len);
2423+ if (stack.length - at == 3) stack[$ - 2] = stack[$ - 1];
2424+
2425+ // Merge runs (at, at + 1)
2426+ return merge(range[base .. base + len], mid, minGallop, temp);
2427+ }
2428+
2429+ // Merge two runs in a range. Mid is the starting index of the second run.
2430+ // minGallop and temp are references; The calling function must receive the updated values.
2431+ void merge()(R range, size_t mid, ref size_t minGallop, ref T[] temp)
2432+ in
2433+ {
2434+ if (!__ctfe)
2435+ {
2436+ assert(isSorted!pred(range[0 .. mid]));
2437+ assert(isSorted!pred(range[mid .. range.length]));
2438+ }
2439+ }
2440+ body
2441+ {
2442+ assert(mid < range.length);
2443+
2444+ // Reduce range of elements
2445+ immutable firstElement = gallopForwardUpper(range[0 .. mid], range[mid]);
2446+ immutable lastElement = gallopReverseLower(range[mid .. range.length], range[mid - 1]) + mid;
2447+ range = range[firstElement .. lastElement];
2448+ mid -= firstElement;
2449+
2450+ if (mid == 0 || mid == range.length) return;
2451+
2452+ // Call function which will copy smaller run into temporary memory
2453+ if (mid <= range.length / 2)
2454+ {
2455+ temp = ensureCapacity(mid, temp);
2456+ minGallop = mergeLo(range, mid, minGallop, temp);
2457+ }
2458+ else
2459+ {
2460+ temp = ensureCapacity(range.length - mid, temp);
2461+ minGallop = mergeHi(range, mid, minGallop, temp);
2462+ }
2463+ }
2464+
2465+ // Enlarge size of temporary memory if needed
2466+ T[] ensureCapacity()(size_t minCapacity, T[] temp)
2467+ out(ret)
2468+ {
2469+ assert(ret.length >= minCapacity);
2470+ }
2471+ body
2472+ {
2473+ if (temp.length < minCapacity)
2474+ {
2475+ size_t newSize = 1<<(bsr(minCapacity)+1);
2476+ //Test for overflow
2477+ if (newSize < minCapacity) newSize = minCapacity;
2478+
2479+ if (__ctfe) temp.length = newSize;
2480+ else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
2481+ }
2482+ return temp;
2483+ }
2484+
2485+ // Merge front to back. Returns new value of minGallop.
2486+ // temp must be large enough to store range[0 .. mid]
2487+ size_t mergeLo()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2488+ out
2489+ {
2490+ if (!__ctfe) assert(isSorted!pred(range));
2491+ }
2492+ body
2493+ {
2494+ import std.algorithm.mutation : copy;
2495+
2496+ assert(mid <= range.length);
2497+ assert(temp.length >= mid);
2498+
2499+ // Copy run into temporary memory
2500+ temp = temp[0 .. mid];
2501+ copy(range[0 .. mid], temp);
2502+
2503+ // Move first element into place
2504+ range[0] = range[mid];
2505+
2506+ size_t i = 1, lef = 0, rig = mid + 1;
2507+ size_t count_lef, count_rig;
2508+ immutable lef_end = temp.length - 1;
2509+
2510+ if (lef < lef_end && rig < range.length)
2511+ outer: while (true)
2512+ {
2513+ count_lef = 0;
2514+ count_rig = 0;
2515+
2516+ // Linear merge
2517+ while ((count_lef | count_rig) < minGallop)
2518+ {
2519+ if (lessEqual(temp[lef], range[rig]))
2520+ {
2521+ range[i++] = temp[lef++];
2522+ if (lef >= lef_end) break outer;
2523+ ++count_lef;
2524+ count_rig = 0;
2525+ }
2526+ else
2527+ {
2528+ range[i++] = range[rig++];
2529+ if (rig >= range.length) break outer;
2530+ count_lef = 0;
2531+ ++count_rig;
2532+ }
2533+ }
2534+
2535+ // Gallop merge
2536+ do
2537+ {
2538+ count_lef = gallopForwardUpper(temp[lef .. $], range[rig]);
2539+ foreach (j; 0 .. count_lef) range[i++] = temp[lef++];
2540+ if (lef >= temp.length) break outer;
2541+
2542+ count_rig = gallopForwardLower(range[rig .. range.length], temp[lef]);
2543+ foreach (j; 0 .. count_rig) range[i++] = range[rig++];
2544+ if (rig >= range.length) while (true)
2545+ {
2546+ range[i++] = temp[lef++];
2547+ if (lef >= temp.length) break outer;
2548+ }
2549+
2550+ if (minGallop > 0) --minGallop;
2551+ }
2552+ while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2553+
2554+ minGallop += 2;
2555+ }
2556+
2557+ // Move remaining elements from right
2558+ while (rig < range.length)
2559+ range[i++] = range[rig++];
2560+
2561+ // Move remaining elements from left
2562+ while (lef < temp.length)
2563+ range[i++] = temp[lef++];
2564+
2565+ return minGallop > 0 ? minGallop : 1;
2566+ }
2567+
2568+ // Merge back to front. Returns new value of minGallop.
2569+ // temp must be large enough to store range[mid .. range.length]
2570+ size_t mergeHi()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2571+ out
2572+ {
2573+ if (!__ctfe) assert(isSorted!pred(range));
2574+ }
2575+ body
2576+ {
2577+ import std.algorithm.mutation : copy;
2578+
2579+ assert(mid <= range.length);
2580+ assert(temp.length >= range.length - mid);
2581+
2582+ // Copy run into temporary memory
2583+ temp = temp[0 .. range.length - mid];
2584+ copy(range[mid .. range.length], temp);
2585+
2586+ // Move first element into place
2587+ range[range.length - 1] = range[mid - 1];
2588+
2589+ size_t i = range.length - 2, lef = mid - 2, rig = temp.length - 1;
2590+ size_t count_lef, count_rig;
2591+
2592+ outer:
2593+ while (true)
2594+ {
2595+ count_lef = 0;
2596+ count_rig = 0;
2597+
2598+ // Linear merge
2599+ while ((count_lef | count_rig) < minGallop)
2600+ {
2601+ if (greaterEqual(temp[rig], range[lef]))
2602+ {
2603+ range[i--] = temp[rig];
2604+ if (rig == 1)
2605+ {
2606+ // Move remaining elements from left
2607+ while (true)
2608+ {
2609+ range[i--] = range[lef];
2610+ if (lef == 0) break;
2611+ --lef;
2612+ }
2613+
2614+ // Move last element into place
2615+ range[i] = temp[0];
2616+
2617+ break outer;
2618+ }
2619+ --rig;
2620+ count_lef = 0;
2621+ ++count_rig;
2622+ }
2623+ else
2624+ {
2625+ range[i--] = range[lef];
2626+ if (lef == 0) while (true)
2627+ {
2628+ range[i--] = temp[rig];
2629+ if (rig == 0) break outer;
2630+ --rig;
2631+ }
2632+ --lef;
2633+ ++count_lef;
2634+ count_rig = 0;
2635+ }
2636+ }
2637+
2638+ // Gallop merge
2639+ do
2640+ {
2641+ count_rig = rig - gallopReverseLower(temp[0 .. rig], range[lef]);
2642+ foreach (j; 0 .. count_rig)
2643+ {
2644+ range[i--] = temp[rig];
2645+ if (rig == 0) break outer;
2646+ --rig;
2647+ }
2648+
2649+ count_lef = lef - gallopReverseUpper(range[0 .. lef], temp[rig]);
2650+ foreach (j; 0 .. count_lef)
2651+ {
2652+ range[i--] = range[lef];
2653+ if (lef == 0) while (true)
2654+ {
2655+ range[i--] = temp[rig];
2656+ if (rig == 0) break outer;
2657+ --rig;
2658+ }
2659+ --lef;
2660+ }
2661+
2662+ if (minGallop > 0) --minGallop;
2663+ }
2664+ while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2665+
2666+ minGallop += 2;
2667+ }
2668+
2669+ return minGallop > 0 ? minGallop : 1;
2670+ }
2671+
2672+ // false = forward / lower, true = reverse / upper
2673+ template gallopSearch(bool forwardReverse, bool lowerUpper)
2674+ {
2675+ // Gallop search on range according to attributes forwardReverse and lowerUpper
2676+ size_t gallopSearch(R)(R range, T value)
2677+ out(ret)
2678+ {
2679+ assert(ret <= range.length);
2680+ }
2681+ body
2682+ {
2683+ size_t lower = 0, center = 1, upper = range.length;
2684+ alias gap = center;
2685+
2686+ static if (forwardReverse)
2687+ {
2688+ static if (!lowerUpper) alias comp = lessEqual; // reverse lower
2689+ static if (lowerUpper) alias comp = less; // reverse upper
2690+
2691+ // Gallop Search Reverse
2692+ while (gap <= upper)
2693+ {
2694+ if (comp(value, range[upper - gap]))
2695+ {
2696+ upper -= gap;
2697+ gap *= 2;
2698+ }
2699+ else
2700+ {
2701+ lower = upper - gap;
2702+ break;
2703+ }
2704+ }
2705+
2706+ // Binary Search Reverse
2707+ while (upper != lower)
2708+ {
2709+ center = lower + (upper - lower) / 2;
2710+ if (comp(value, range[center])) upper = center;
2711+ else lower = center + 1;
2712+ }
2713+ }
2714+ else
2715+ {
2716+ static if (!lowerUpper) alias comp = greater; // forward lower
2717+ static if (lowerUpper) alias comp = greaterEqual; // forward upper
2718+
2719+ // Gallop Search Forward
2720+ while (lower + gap < upper)
2721+ {
2722+ if (comp(value, range[lower + gap]))
2723+ {
2724+ lower += gap;
2725+ gap *= 2;
2726+ }
2727+ else
2728+ {
2729+ upper = lower + gap;
2730+ break;
2731+ }
2732+ }
2733+
2734+ // Binary Search Forward
2735+ while (lower != upper)
2736+ {
2737+ center = lower + (upper - lower) / 2;
2738+ if (comp(value, range[center])) lower = center + 1;
2739+ else upper = center;
2740+ }
2741+ }
2742+
2743+ return lower;
2744+ }
2745+ }
2746+
2747+ alias gallopForwardLower = gallopSearch!(false, false);
2748+ alias gallopForwardUpper = gallopSearch!(false, true);
2749+ alias gallopReverseLower = gallopSearch!( true, false);
2750+ alias gallopReverseUpper = gallopSearch!( true, true);
2751+}
2752+
2753+@safe unittest
2754+{
2755+ import std.random : Random, uniform, randomShuffle;
2756+
2757+ // Element type with two fields
2758+ static struct E
2759+ {
2760+ size_t value, index;
2761+ }
2762+
2763+ // Generates data especially for testing sorting with Timsort
2764+ static E[] genSampleData(uint seed) @safe
2765+ {
2766+ import std.algorithm.mutation : swap, swapRanges;
2767+
2768+ auto rnd = Random(seed);
2769+
2770+ E[] arr;
2771+ arr.length = 64 * 64;
2772+
2773+ // We want duplicate values for testing stability
2774+ foreach (i, ref v; arr) v.value = i / 64;
2775+
2776+ // Swap ranges at random middle point (test large merge operation)
2777+ immutable mid = uniform(arr.length / 4, arr.length / 4 * 3, rnd);
2778+ swapRanges(arr[0 .. mid], arr[mid .. $]);
2779+
2780+ // Shuffle last 1/8 of the array (test insertion sort and linear merge)
2781+ randomShuffle(arr[$ / 8 * 7 .. $], rnd);
2782+
2783+ // Swap few random elements (test galloping mode)
2784+ foreach (i; 0 .. arr.length / 64)
2785+ {
2786+ immutable a = uniform(0, arr.length, rnd), b = uniform(0, arr.length, rnd);
2787+ swap(arr[a], arr[b]);
2788+ }
2789+
2790+ // Now that our test array is prepped, store original index value
2791+ // This will allow us to confirm the array was sorted stably
2792+ foreach (i, ref v; arr) v.index = i;
2793+
2794+ return arr;
2795+ }
2796+
2797+ // Tests the Timsort function for correctness and stability
2798+ static bool testSort(uint seed)
2799+ {
2800+ auto arr = genSampleData(seed);
2801+
2802+ // Now sort the array!
2803+ static bool comp(E a, E b)
2804+ {
2805+ return a.value < b.value;
2806+ }
2807+
2808+ sort!(comp, SwapStrategy.stable)(arr);
2809+
2810+ // Test that the array was sorted correctly
2811+ assert(isSorted!comp(arr));
2812+
2813+ // Test that the array was sorted stably
2814+ foreach (i; 0 .. arr.length - 1)
2815+ {
2816+ if (arr[i].value == arr[i + 1].value) assert(arr[i].index < arr[i + 1].index);
2817+ }
2818+
2819+ return true;
2820+ }
2821+
2822+ enum seed = 310614065;
2823+ testSort(seed);
2824+
2825+ enum result = testSort(seed);
2826+ assert(result == true);
2827+}
2828+
2829+@safe unittest
2830+{//bugzilla 4584
2831+ assert(isSorted!"a < b"(sort!("a < b", SwapStrategy.stable)(
2832+ [83, 42, 85, 86, 87, 22, 89, 30, 91, 46, 93, 94, 95, 6,
2833+ 97, 14, 33, 10, 101, 102, 103, 26, 105, 106, 107, 6]
2834+ )));
2835+
2836+}
2837+
2838+@safe unittest
2839+{
2840+ //test stable sort + zip
2841+ import std.range;
2842+ auto x = [10, 50, 60, 60, 20];
2843+ dchar[] y = "abcde"d.dup;
2844+
2845+ sort!("a[0] < b[0]", SwapStrategy.stable)(zip(x, y));
2846+ assert(x == [10, 20, 50, 60, 60]);
2847+ assert(y == "aebcd"d);
2848+}
2849+
2850+@safe unittest
2851+{
2852+ // Issue 14223
2853+ import std.array, std.range;
2854+ auto arr = chain(iota(0, 384), iota(0, 256), iota(0, 80), iota(0, 64), iota(0, 96)).array;
2855+ sort!("a < b", SwapStrategy.stable)(arr);
2856+}
2857+
2858+// schwartzSort
2859+/**
2860+Alternative sorting method that should be used when comparing keys involves an
2861+expensive computation. Instead of using `less(a, b)` for comparing elements,
2862+`schwartzSort` uses `less(transform(a), transform(b))`. The values of the
2863+`transform` function are precomputed in a temporary array, thus saving on
2864+repeatedly computing it. Conversely, if the cost of `transform` is small
2865+compared to the cost of allocating and filling the precomputed array, `sort`
2866+may be faster and therefore preferable.
2867+
2868+This approach to sorting is akin to the $(HTTP
2869+wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform), also known as
2870+the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the
2871+same as that of the corresponding `sort`, but `schwartzSort` evaluates
2872+`transform` only `r.length` times (less than half when compared to regular
2873+sorting). The usage can be best illustrated with an example.
2874+
2875+Example:
2876+----
2877+uint hashFun(string) { ... expensive computation ... }
2878+string[] array = ...;
2879+// Sort strings by hash, slow
2880+sort!((a, b) => hashFun(a) < hashFun(b))(array);
2881+// Sort strings by hash, fast (only computes arr.length hashes):
2882+schwartzSort!(hashFun, "a < b")(array);
2883+----
2884+
2885+The $(D schwartzSort) function might require less temporary data and
2886+be faster than the Perl idiom or the decorate-sort-undecorate idiom
2887+present in Python and Lisp. This is because sorting is done in-place
2888+and only minimal extra data (one array of transformed elements) is
2889+created.
2890+
2891+To check whether an array was sorted and benefit of the speedup of
2892+Schwartz sorting, a function $(D schwartzIsSorted) is not provided
2893+because the effect can be achieved by calling $(D
2894+isSorted!less(map!transform(r))).
2895+
2896+Params:
2897+ transform = The transformation to apply.
2898+ less = The predicate to sort by.
2899+ ss = The swapping strategy to use.
2900+ r = The range to sort.
2901+
2902+Returns: The initial range wrapped as a $(D SortedRange) with the
2903+predicate $(D (a, b) => binaryFun!less(transform(a),
2904+transform(b))).
2905+ */
2906+SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a),
2907+ unaryFun!transform(b))))
2908+schwartzSort(alias transform, alias less = "a < b",
2909+ SwapStrategy ss = SwapStrategy.unstable, R)(R r)
2910+if (isRandomAccessRange!R && hasLength!R)
2911+{
2912+ import std.conv : emplace;
2913+ import std.range : zip, SortedRange;
2914+ import std.string : representation;
2915+
2916+ alias T = typeof(unaryFun!transform(r.front));
2917+ static trustedMalloc(size_t len) @trusted
2918+ {
2919+ import core.checkedint : mulu;
2920+ import core.stdc.stdlib : malloc;
2921+ bool overflow;
2922+ const nbytes = mulu(len, T.sizeof, overflow);
2923+ if (overflow) assert(0);
2924+ return (cast(T*) malloc(nbytes))[0 .. len];
2925+ }
2926+ auto xform1 = trustedMalloc(r.length);
2927+
2928+ size_t length;
2929+ scope(exit)
2930+ {
2931+ static if (hasElaborateDestructor!T)
2932+ {
2933+ foreach (i; 0 .. length) collectException(destroy(xform1[i]));
2934+ }
2935+ static void trustedFree(T[] p) @trusted
2936+ {
2937+ import core.stdc.stdlib : free;
2938+ free(p.ptr);
2939+ }
2940+ trustedFree(xform1);
2941+ }
2942+ for (; length != r.length; ++length)
2943+ {
2944+ emplace(&xform1[length], unaryFun!transform(r[length]));
2945+ }
2946+ // Make sure we use ubyte[] and ushort[], not char[] and wchar[]
2947+ // for the intermediate array, lest zip gets confused.
2948+ static if (isNarrowString!(typeof(xform1)))
2949+ {
2950+ auto xform = xform1.representation();
2951+ }
2952+ else
2953+ {
2954+ alias xform = xform1;
2955+ }
2956+ zip(xform, r).sort!((a, b) => binaryFun!less(a[0], b[0]), ss)();
2957+ return typeof(return)(r);
2958+}
2959+
2960+///
2961+@safe unittest
2962+{
2963+ import std.algorithm.iteration : map;
2964+ import std.numeric : entropy;
2965+
2966+ auto lowEnt = [ 1.0, 0, 0 ],
2967+ midEnt = [ 0.1, 0.1, 0.8 ],
2968+ highEnt = [ 0.31, 0.29, 0.4 ];
2969+ auto arr = new double[][3];
2970+ arr[0] = midEnt;
2971+ arr[1] = lowEnt;
2972+ arr[2] = highEnt;
2973+
2974+ schwartzSort!(entropy, "a > b")(arr);
2975+
2976+ assert(arr[0] == highEnt);
2977+ assert(arr[1] == midEnt);
2978+ assert(arr[2] == lowEnt);
2979+ assert(isSorted!("a > b")(map!(entropy)(arr)));
2980+}
2981+
2982+@safe unittest
2983+{
2984+ import std.algorithm.iteration : map;
2985+ import std.numeric : entropy;
2986+
2987+ auto lowEnt = [ 1.0, 0, 0 ],
2988+ midEnt = [ 0.1, 0.1, 0.8 ],
2989+ highEnt = [ 0.31, 0.29, 0.4 ];
2990+ auto arr = new double[][3];
2991+ arr[0] = midEnt;
2992+ arr[1] = lowEnt;
2993+ arr[2] = highEnt;
2994+
2995+ schwartzSort!(entropy, "a < b")(arr);
2996+
2997+ assert(arr[0] == lowEnt);
2998+ assert(arr[1] == midEnt);
2999+ assert(arr[2] == highEnt);
3000+ assert(isSorted!("a < b")(map!(entropy)(arr)));
3001+}
3002+
3003+@safe unittest
3004+{
3005+ // issue 4909
3006+ import std.typecons : Tuple;
3007+ Tuple!(char)[] chars;
3008+ schwartzSort!"a[0]"(chars);
3009+}
3010+
3011+@safe unittest
3012+{
3013+ // issue 5924
3014+ import std.typecons : Tuple;
3015+ Tuple!(char)[] chars;
3016+ schwartzSort!((Tuple!(char) c){ return c[0]; })(chars);
3017+}
3018+
3019+// partialSort
3020+/**
3021+Reorders the random-access range $(D r) such that the range $(D r[0
3022+.. mid]) is the same as if the entire $(D r) were sorted, and leaves
3023+the range $(D r[mid .. r.length]) in no particular order. Performs
3024+$(BIGOH r.length * log(mid)) evaluations of $(D pred). The
3025+implementation simply calls $(D topN!(less, ss)(r, n)) and then $(D
3026+sort!(less, ss)(r[0 .. n])).
3027+
3028+Params:
3029+ less = The predicate to sort by.
3030+ ss = The swapping strategy to use.
3031+ r = The random-access range to reorder.
3032+ n = The length of the initial segment of `r` to sort.
3033+*/
3034+void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3035+ Range)(Range r, size_t n)
3036+if (isRandomAccessRange!(Range) && hasLength!(Range) && hasSlicing!(Range))
3037+{
3038+ partialSort!(less, ss)(r[0 .. n], r[n .. $]);
3039+}
3040+
3041+///
3042+@system unittest
3043+{
3044+ int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
3045+ partialSort(a, 5);
3046+ assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);
3047+}
3048+
3049+/**
3050+Stores the smallest elements of the two ranges in the left-hand range in sorted order.
3051+
3052+Params:
3053+ less = The predicate to sort by.
3054+ ss = The swapping strategy to use.
3055+ r1 = The first range.
3056+ r2 = The second range.
3057+ */
3058+
3059+void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3060+ Range1, Range2)(Range1 r1, Range2 r2)
3061+if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
3062+ isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
3063+ hasLvalueElements!Range1 && hasLvalueElements!Range2)
3064+{
3065+ topN!(less, ss)(r1, r2);
3066+ sort!(less, ss)(r1);
3067+}
3068+///
3069+@system unittest
3070+{
3071+ int[] a = [5, 7, 2, 6, 7];
3072+ int[] b = [2, 1, 5, 6, 7, 3, 0];
3073+
3074+ partialSort(a, b);
3075+ assert(a == [0, 1, 2, 2, 3]);
3076+}
3077+
3078+// topN
3079+/**
3080+Reorders the range $(D r) using $(D swap) such that $(D r[nth]) refers
3081+to the element that would fall there if the range were fully
3082+sorted. In addition, it also partitions $(D r) such that all elements
3083+$(D e1) from $(D r[0]) to $(D r[nth]) satisfy $(D !less(r[nth], e1)),
3084+and all elements $(D e2) from $(D r[nth]) to $(D r[r.length]) satisfy
3085+$(D !less(e2, r[nth])). Effectively, it finds the nth smallest
3086+(according to $(D less)) elements in $(D r). Performs an expected
3087+$(BIGOH r.length) (if unstable) or $(BIGOH r.length * log(r.length))
3088+(if stable) evaluations of $(D less) and $(D swap).
3089+
3090+If $(D n >= r.length), the algorithm has no effect and returns
3091+`r[0 .. r.length]`.
3092+
3093+Params:
3094+ less = The predicate to sort by.
3095+ ss = The swapping strategy to use.
3096+ r = The random-access range to reorder.
3097+ nth = The index of the element that should be in sorted position after the
3098+ function is done.
3099+
3100+See_Also:
3101+ $(LREF topNIndex),
3102+ $(HTTP sgi.com/tech/stl/nth_element.html, STL's nth_element)
3103+
3104+BUGS:
3105+
3106+Stable topN has not been implemented yet.
3107+*/
3108+auto topN(alias less = "a < b",
3109+ SwapStrategy ss = SwapStrategy.unstable,
3110+ Range)(Range r, size_t nth)
3111+if (isRandomAccessRange!(Range) && hasLength!Range && hasSlicing!Range)
3112+{
3113+ static assert(ss == SwapStrategy.unstable,
3114+ "Stable topN not yet implemented");
3115+ if (nth >= r.length) return r[0 .. r.length];
3116+ auto ret = r[0 .. nth];
3117+ if (false)
3118+ {
3119+ // Workaround for https://issues.dlang.org/show_bug.cgi?id=16528
3120+ // Safety checks: enumerate all potentially unsafe generic primitives
3121+ // then use a @trusted implementation.
3122+ binaryFun!less(r[0], r[r.length - 1]);
3123+ import std.algorithm.mutation : swapAt;
3124+ r.swapAt(size_t(0), size_t(0));
3125+ static assert(is(typeof(r.length) == size_t));
3126+ pivotPartition!less(r, 0);
3127+ }
3128+ bool useSampling = true;
3129+ topNImpl!(binaryFun!less)(r, nth, useSampling);
3130+ return ret;
3131+}
3132+
3133+private @trusted
3134+void topNImpl(alias less, R)(R r, size_t n, ref bool useSampling)
3135+{
3136+ for (;;)
3137+ {
3138+ import std.algorithm.mutation : swapAt;
3139+ assert(n < r.length);
3140+ size_t pivot = void;
3141+
3142+ // Decide strategy for partitioning
3143+ if (n == 0)
3144+ {
3145+ pivot = 0;
3146+ foreach (i; 1 .. r.length)
3147+ if (less(r[i], r[pivot])) pivot = i;
3148+ r.swapAt(n, pivot);
3149+ return;
3150+ }
3151+ if (n + 1 == r.length)
3152+ {
3153+ pivot = 0;
3154+ foreach (i; 1 .. r.length)
3155+ if (less(r[pivot], r[i])) pivot = i;
3156+ r.swapAt(n, pivot);
3157+ return;
3158+ }
3159+ if (r.length <= 12)
3160+ {
3161+ pivot = pivotPartition!less(r, r.length / 2);
3162+ }
3163+ else if (n * 16 <= (r.length - 1) * 7)
3164+ {
3165+ pivot = topNPartitionOffMedian!(less, No.leanRight)
3166+ (r, n, useSampling);
3167+ // Quality check
3168+ if (useSampling)
3169+ {
3170+ if (pivot < n)
3171+ {
3172+ if (pivot * 4 < r.length)
3173+ {
3174+ useSampling = false;
3175+ }
3176+ }
3177+ else if ((r.length - pivot) * 8 < r.length * 3)
3178+ {
3179+ useSampling = false;
3180+ }
3181+ }
3182+ }
3183+ else if (n * 16 >= (r.length - 1) * 9)
3184+ {
3185+ pivot = topNPartitionOffMedian!(less, Yes.leanRight)
3186+ (r, n, useSampling);
3187+ // Quality check
3188+ if (useSampling)
3189+ {
3190+ if (pivot < n)
3191+ {
3192+ if (pivot * 8 < r.length * 3)
3193+ {
3194+ useSampling = false;
3195+ }
3196+ }
3197+ else if ((r.length - pivot) * 4 < r.length)
3198+ {
3199+ useSampling = false;
3200+ }
3201+ }
3202+ }
3203+ else
3204+ {
3205+ pivot = topNPartition!less(r, n, useSampling);
3206+ // Quality check
3207+ if (useSampling &&
3208+ (pivot * 9 < r.length * 2 || pivot * 9 > r.length * 7))
3209+ {
3210+ // Failed - abort sampling going forward
3211+ useSampling = false;
3212+ }
3213+ }
3214+
3215+ assert(pivot != size_t.max);
3216+ // See how the pivot fares
3217+ if (pivot == n)
3218+ {
3219+ return;
3220+ }
3221+ if (pivot > n)
3222+ {
3223+ r = r[0 .. pivot];
3224+ }
3225+ else
3226+ {
3227+ n -= pivot + 1;
3228+ r = r[pivot + 1 .. r.length];
3229+ }
3230+ }
3231+}
3232+
3233+///
3234+@safe unittest
3235+{
3236+ int[] v = [ 25, 7, 9, 2, 0, 5, 21 ];
3237+ topN!"a < b"(v, 100);
3238+ assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]);
3239+ auto n = 4;
3240+ topN!"a < b"(v, n);
3241+ assert(v[n] == 9);
3242+}
3243+
3244+private size_t topNPartition(alias lp, R)(R r, size_t n, bool useSampling)
3245+{
3246+ assert(r.length >= 9 && n < r.length);
3247+ immutable ninth = r.length / 9;
3248+ auto pivot = ninth / 2;
3249+ // Position subrange r[lo .. hi] to have length equal to ninth and its upper
3250+ // median r[lo .. hi][$ / 2] in exactly the same place as the upper median
3251+ // of the entire range r[$ / 2]. This is to improve behavior for searching
3252+ // the median in already sorted ranges.
3253+ immutable lo = r.length / 2 - pivot, hi = lo + ninth;
3254+ // We have either one straggler on the left, one on the right, or none.
3255+ assert(lo - (r.length - hi) <= 1 || (r.length - hi) - lo <= 1);
3256+ assert(lo >= ninth * 4);
3257+ assert(r.length - hi >= ninth * 4);
3258+
3259+ // Partition in groups of 3, and the mid tertile again in groups of 3
3260+ if (!useSampling)
3261+ p3!lp(r, lo - ninth, hi + ninth);
3262+ p3!lp(r, lo, hi);
3263+
3264+ // Get the median of medians of medians
3265+ // Map the full interval of n to the full interval of the ninth
3266+ pivot = (n * (ninth - 1)) / (r.length - 1);
3267+ topNImpl!lp(r[lo .. hi], pivot, useSampling);
3268+ return expandPartition!lp(r, lo, pivot + lo, hi);
3269+}
3270+
3271+private void p3(alias less, Range)(Range r, size_t lo, immutable size_t hi)
3272+{
3273+ assert(lo <= hi && hi < r.length);
3274+ immutable ln = hi - lo;
3275+ for (; lo < hi; ++lo)
3276+ {
3277+ assert(lo >= ln);
3278+ assert(lo + ln < r.length);
3279+ medianOf!less(r, lo - ln, lo, lo + ln);
3280+ }
3281+}
3282+
3283+private void p4(alias less, Flag!"leanRight" f, Range)
3284+ (Range r, size_t lo, immutable size_t hi)
3285+{
3286+ assert(lo <= hi && hi < r.length);
3287+ immutable ln = hi - lo, _2ln = ln * 2;
3288+ for (; lo < hi; ++lo)
3289+ {
3290+ assert(lo >= ln);
3291+ assert(lo + ln < r.length);
3292+ static if (f == Yes.leanRight)
3293+ medianOf!(less, f)(r, lo - _2ln, lo - ln, lo, lo + ln);
3294+ else
3295+ medianOf!(less, f)(r, lo - ln, lo, lo + ln, lo + _2ln);
3296+ }
3297+}
3298+
3299+private size_t topNPartitionOffMedian(alias lp, Flag!"leanRight" f, R)
3300+ (R r, size_t n, bool useSampling)
3301+{
3302+ assert(r.length >= 12);
3303+ assert(n < r.length);
3304+ immutable _4 = r.length / 4;
3305+ static if (f == Yes.leanRight)
3306+ immutable leftLimit = 2 * _4;
3307+ else
3308+ immutable leftLimit = _4;
3309+ // Partition in groups of 4, and the left quartile again in groups of 3
3310+ if (!useSampling)
3311+ {
3312+ p4!(lp, f)(r, leftLimit, leftLimit + _4);
3313+ }
3314+ immutable _12 = _4 / 3;
3315+ immutable lo = leftLimit + _12, hi = lo + _12;
3316+ p3!lp(r, lo, hi);
3317+
3318+ // Get the median of medians of medians
3319+ // Map the full interval of n to the full interval of the ninth
3320+ immutable pivot = (n * (_12 - 1)) / (r.length - 1);
3321+ topNImpl!lp(r[lo .. hi], pivot, useSampling);
3322+ return expandPartition!lp(r, lo, pivot + lo, hi);
3323+}
3324+
3325+/*
3326+Params:
3327+less = predicate
3328+r = range to partition
3329+pivot = pivot to partition around
3330+lo = value such that r[lo .. pivot] already less than r[pivot]
3331+hi = value such that r[pivot .. hi] already greater than r[pivot]
3332+
3333+Returns: new position of pivot
3334+*/
3335+private
3336+size_t expandPartition(alias lp, R)(R r, size_t lo, size_t pivot, size_t hi)
3337+in
3338+{
3339+ import std.algorithm.searching : all;
3340+ assert(lo <= pivot);
3341+ assert(pivot < hi);
3342+ assert(hi <= r.length);
3343+ assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)));
3344+ assert(r[pivot + 1 .. hi].all!(x => !lp(x, r[pivot])));
3345+ }
3346+out
3347+{
3348+ import std.algorithm.searching : all;
3349+ assert(r[0 .. pivot + 1].all!(x => !lp(r[pivot], x)));
3350+ assert(r[pivot + 1 .. r.length].all!(x => !lp(x, r[pivot])));
3351+}
3352+body
3353+{
3354+ import std.algorithm.mutation : swapAt;
3355+ import std.algorithm.searching : all;
3356+ // We work with closed intervals!
3357+ --hi;
3358+
3359+ size_t left = 0, rite = r.length - 1;
3360+ loop: for (;; ++left, --rite)
3361+ {
3362+ for (;; ++left)
3363+ {
3364+ if (left == lo) break loop;
3365+ if (!lp(r[left], r[pivot])) break;
3366+ }
3367+ for (;; --rite)
3368+ {
3369+ if (rite == hi) break loop;
3370+ if (!lp(r[pivot], r[rite])) break;
3371+ }
3372+ r.swapAt(left, rite);
3373+ }
3374+
3375+ assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)));
3376+ assert(r[pivot + 1 .. hi + 1].all!(x => !lp(x, r[pivot])));
3377+ assert(r[0 .. left].all!(x => !lp(r[pivot], x)));
3378+ assert(r[rite + 1 .. r.length].all!(x => !lp(x, r[pivot])));
3379+
3380+ immutable oldPivot = pivot;
3381+
3382+ if (left < lo)
3383+ {
3384+ // First loop: spend r[lo .. pivot]
3385+ for (; lo < pivot; ++left)
3386+ {
3387+ if (left == lo) goto done;
3388+ if (!lp(r[oldPivot], r[left])) continue;
3389+ --pivot;
3390+ assert(!lp(r[oldPivot], r[pivot]));
3391+ r.swapAt(left, pivot);
3392+ }
3393+ // Second loop: make left and pivot meet
3394+ for (;; ++left)
3395+ {
3396+ if (left == pivot) goto done;
3397+ if (!lp(r[oldPivot], r[left])) continue;
3398+ for (;;)
3399+ {
3400+ if (left == pivot) goto done;
3401+ --pivot;
3402+ if (lp(r[pivot], r[oldPivot]))
3403+ {
3404+ r.swapAt(left, pivot);
3405+ break;
3406+ }
3407+ }
3408+ }
3409+ }
3410+
3411+ // First loop: spend r[lo .. pivot]
3412+ for (; hi != pivot; --rite)
3413+ {
3414+ if (rite == hi) goto done;
3415+ if (!lp(r[rite], r[oldPivot])) continue;
3416+ ++pivot;
3417+ assert(!lp(r[pivot], r[oldPivot]));
3418+ r.swapAt(rite, pivot);
3419+ }
3420+ // Second loop: make left and pivot meet
3421+ for (; rite > pivot; --rite)
3422+ {
3423+ if (!lp(r[rite], r[oldPivot])) continue;
3424+ while (rite > pivot)
3425+ {
3426+ ++pivot;
3427+ if (lp(r[oldPivot], r[pivot]))
3428+ {
3429+ r.swapAt(rite, pivot);
3430+ break;
3431+ }
3432+ }
3433+ }
3434+
3435+done:
3436+ r.swapAt(oldPivot, pivot);
3437+ return pivot;
3438+}
3439+
3440+@safe unittest
3441+{
3442+ auto a = [ 10, 5, 3, 4, 8, 11, 13, 3, 9, 4, 10 ];
3443+ assert(expandPartition!((a, b) => a < b)(a, 4, 5, 6) == 9);
3444+ a = randomArray;
3445+ if (a.length == 0) return;
3446+ expandPartition!((a, b) => a < b)(a, a.length / 2, a.length / 2,
3447+ a.length / 2 + 1);
3448+}
3449+
3450+version (unittest)
3451+private T[] randomArray(Flag!"exactSize" flag = No.exactSize, T = int)(
3452+ size_t maxSize = 1000,
3453+ T minValue = 0, T maxValue = 255)
3454+{
3455+ import std.algorithm.iteration : map;
3456+ import std.random : unpredictableSeed, Random, uniform;
3457+ auto size = flag == Yes.exactSize ? maxSize : uniform(1, maxSize);
3458+ return iota(0, size).map!(_ => uniform(minValue, maxValue)).array;
3459+}
3460+
3461+@safe unittest
3462+{
3463+ import std.algorithm.comparison : max, min;
3464+ import std.algorithm.iteration : reduce;
3465+
3466+ int[] v = [ 7, 6, 5, 4, 3, 2, 1, 0 ];
3467+ ptrdiff_t n = 3;
3468+ topN!("a < b")(v, n);
3469+ assert(reduce!max(v[0 .. n]) <= v[n]);
3470+ assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3471+ //
3472+ v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3473+ n = 3;
3474+ topN(v, n);
3475+ assert(reduce!max(v[0 .. n]) <= v[n]);
3476+ assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3477+ //
3478+ v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3479+ n = 1;
3480+ topN(v, n);
3481+ assert(reduce!max(v[0 .. n]) <= v[n]);
3482+ assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3483+ //
3484+ v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3485+ n = v.length - 1;
3486+ topN(v, n);
3487+ assert(v[n] == 7);
3488+ //
3489+ v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3490+ n = 0;
3491+ topN(v, n);
3492+ assert(v[n] == 1);
3493+
3494+ double[][] v1 = [[-10, -5], [-10, -3], [-10, -5], [-10, -4],
3495+ [-10, -5], [-9, -5], [-9, -3], [-9, -5],];
3496+
3497+ // double[][] v1 = [ [-10, -5], [-10, -4], [-9, -5], [-9, -5],
3498+ // [-10, -5], [-10, -3], [-10, -5], [-9, -3],];
3499+ double[]*[] idx = [ &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5], &v1[6],
3500+ &v1[7], ];
3501+
3502+ auto mid = v1.length / 2;
3503+ topN!((a, b){ return (*a)[1] < (*b)[1]; })(idx, mid);
3504+ foreach (e; idx[0 .. mid]) assert((*e)[1] <= (*idx[mid])[1]);
3505+ foreach (e; idx[mid .. $]) assert((*e)[1] >= (*idx[mid])[1]);
3506+}
3507+
3508+@safe unittest
3509+{
3510+ import std.algorithm.comparison : max, min;
3511+ import std.algorithm.iteration : reduce;
3512+ import std.random : Random, uniform, unpredictableSeed;
3513+
3514+ immutable uint[] seeds = [90027751, 2709791795, 1374631933, 995751648, 3541495258, 984840953, unpredictableSeed];
3515+ foreach (s; seeds)
3516+ {
3517+ auto r = Random(s);
3518+
3519+ int[] a = new int[uniform(1, 10000, r)];
3520+ foreach (ref e; a) e = uniform(-1000, 1000, r);
3521+
3522+ auto k = uniform(0, a.length, r);
3523+ topN(a, k);
3524+ if (k > 0)
3525+ {
3526+ auto left = reduce!max(a[0 .. k]);
3527+ assert(left <= a[k]);
3528+ }
3529+ if (k + 1 < a.length)

939 more lines aren’t shown here.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t