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/**
3This is a submodule of $(MREF std, algorithm).
4It 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
48Copyright: Andrei Alexandrescu 2008-.
49
50License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
51
52Authors: $(HTTP erdani.com, Andrei Alexandrescu)
53
54Source: $(PHOBOSSRC std/algorithm/_comparison.d)
55
56Macros:
57T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
58 */
59module std.algorithm.comparison;
60
61// FIXME
62import std.functional; // : unaryFun, binaryFun;
63import std.range.primitives;
64import std.traits;
65// FIXME
66import std.meta : allSatisfy;
67import std.typecons; // : tuple, Tuple, Flag, Yes;
68
69/**
70Find $(D value) _among $(D values), returning the 1-based index
71of the first matching value in $(D values), or $(D 0) if $(D value)
72is not _among $(D values). The predicate $(D pred) is used to
73compare values, and uses equality by default.
74
75Params:
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
80Returns:
81 0 if value was not found among the values, otherwise the index of the
82 found value plus one is returned.
83
84See_Also:
85$(REF_ALTTEXT find, find, std,algorithm,searching) and $(REF_ALTTEXT canFind, canFind, std,algorithm,searching) for finding a value in a
86range.
87*/
88uint among(alias pred = (a, b) => a == b, Value, Values...)
89 (Value value, Values values)
90if (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
101template among(values...)
102if (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/**
133Alternatively, $(D values) can be passed at compile-time, allowing for a more
134efficient 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.
179private 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/**
214Executes and returns one of a collection of handlers based on the type of the
215switch object.
216
217The first choice that $(D switchObject) can be casted to the type
218of argument it accepts will be called with $(D switchObject) casted to that
219type, and the value it'll return will be returned by $(D castSwitch).
220
221If a choice's return type is void, the choice must throw an exception, unless
222all the choices are void. In that case, castSwitch itself will return void.
223
224Throws: If none of the choice matches, a $(D SwitchError) will be thrown. $(D
225SwitchError) will also be thrown if not all the choices are void and a void
226choice was executed without throwing anything.
227
228Params:
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
235Returns:
236 The value of the selected choice.
237
238Note: $(D castSwitch) can only be used with object types.
239*/
240auto 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
520This functions is equivalent to $(D max(lower, min(upper,val))).
521
522Params:
523 val = The value to _clamp.
524 lower = The _lower bound of the _clamp.
525 upper = The _upper bound of the _clamp.
526
527Returns:
528 Returns $(D val), if it is between $(D lower) and $(D upper).
529 Otherwise returns the nearest of the two.
530
531*/
532auto clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
533in
534{
535 import std.functional : greaterThan;
536 assert(!lower.greaterThan(upper));
537}
538body
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/**********************************
583Performs three-way lexicographical comparison on two
584$(REF_ALTTEXT input ranges, isInputRange, std,range,primitives)
585according to predicate $(D pred). Iterating $(D r1) and $(D r2) in
586lockstep, $(D cmp) compares each element $(D e1) of $(D r1) with the
587corresponding element $(D e2) in $(D r2). If one of the ranges has been
588finished, $(D cmp) returns a negative value if $(D r1) has fewer
589elements than $(D r2), a positive value if $(D r1) has more elements
590than $(D r2), and $(D 0) if the ranges have the same number of
591elements.
592
593If the ranges are strings, $(D cmp) performs UTF decoding
594appropriately and compares the ranges one code point at a time.
595
596Params:
597 pred = The predicate used for comparison.
598 r1 = The first range.
599 r2 = The second range.
600
601Returns:
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*/
608int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2)
609if (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
622int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2)
623if (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/**
729Compares two ranges for equality, as defined by predicate $(D pred)
730(which is $(D ==) by default).
731*/
732template 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/++
847Tip: $(D equal) can itself be used as a predicate to other functions.
848This can be very useful when the element type of a range is itself a
849range. In particular, $(D equal) can be its own predicate, allowing
850range 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
960private template MaxType(T...)
961if (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/**
984Encodes $(HTTP realityinteractive.com/rgrzywinski/archives/000249.html,
985edit operations) necessary to transform one sequence into
986another. Given sequences $(D s) (source) and $(D t) (target), a
987sequence of $(D EditOp) encodes the steps that need to be taken to
988convert $(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:
990skip two characters, replace 't' with 'r', and insert an 's'. Working
991with edit operations is useful in applications such as spell-checkers
992(to find the closest word to a given misspelled word), approximate
993searches, diff-style programs that compute the difference between
994files, efficient encoding of patches, DNA sequence analysis, and
995plagiarism detection.
996*/
997
998enum 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
1020private 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
1063private:
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/**
1195Returns the $(HTTP wikipedia.org/wiki/Levenshtein_distance, Levenshtein
1196distance) between $(D s) and $(D t). The Levenshtein distance computes
1197the minimal amount of edit operations necessary to transform $(D s)
1198into $(D t). Performs $(BIGOH s.length * t.length) evaluations of $(D
1199equals) and occupies $(BIGOH s.length * t.length) storage.
1200
1201Params:
1202 equals = The binary predicate to compare the elements of the two ranges.
1203 s = The original range.
1204 t = The transformation target
1205
1206Returns:
1207 The minimal number of edits to transform s into t.
1208
1209Does not allocate GC memory.
1210*/
1211size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2)
1212 (Range1 s, Range2 t)
1213if (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
1282size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2)
1283 (auto ref Range1 s, auto ref Range2 t)
1284if (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/**
1308Returns the Levenshtein distance and the edit path between $(D s) and
1309$(D t).
1310
1311Params:
1312 equals = The binary predicate to compare the elements of the two ranges.
1313 s = The original range.
1314 t = The transformation target
1315
1316Returns:
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
1320Allocates GC memory for the returned EditOp[] array.
1321*/
1322Tuple!(size_t, EditOp[])
1323levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2)
1324 (Range1 s, Range2 t)
1325if (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
1352Tuple!(size_t, EditOp[])
1353levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2)
1354 (auto ref Range1 s, auto ref Range2 t)
1355if (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/**
1372Iterates the passed arguments and return the maximum value.
1373
1374Params:
1375 args = The values to select the maximum from. At least two arguments must
1376 be passed.
1377
1378Returns:
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
1382See_Also:
1383 $(REF maxElement, std,algorithm,searching)
1384*/
1385MaxType!T max(T...)(T args)
1386if (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
1456private template MinType(T...)
1457if (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/**
1489Iterates the passed arguments and returns the minimum value.
1490
1491Params: args = The values to select the minimum from. At least two arguments
1492 must be passed, and they must be comparable with `<`.
1493Returns: The minimum of the passed-in values.
1494See_Also:
1495 $(REF minElement, std,algorithm,searching)
1496*/
1497MinType!T min(T...)(T args)
1498if (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/**
1558Sequentially compares elements in $(D r1) and $(D r2) in lockstep, and
1559stops at the first mismatch (according to $(D pred), by default
1560equality). Returns a tuple with the reduced ranges that start with the
1561two mismatched values. Performs $(BIGOH min(r1.length, r2.length))
1562evaluations of $(D pred).
1563
1564See_Also:
1565 $(HTTP sgi.com/tech/stl/_mismatch.html, STL's _mismatch)
1566*/
1567Tuple!(Range1, Range2)
1568mismatch(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2)
1569if (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/**
1598Returns one of a collection of expressions based on the value of the switch
1599expression.
1600
1601$(D choices) needs to be composed of pairs of test expressions and return
1602expressions. 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
1606Both the test and the return expressions are lazily evaluated.
1607
1608Params:
1609
1610switchExpression = The first argument for the predicate.
1611
1612choices = Pairs of test expressions and return expressions. The test
1613expressions will be the second argument for the predicate, and the return
1614expression will be returned if the predicate yields true with $(D
1615switchExpression) and the test expression as arguments. May also have a
1616default return expression, that needs to be the last expression without a test
1617expression before it. A return expression may be of void type only if it
1618always throws.
1619
1620Returns: The return expression associated with the first test expression that
1621made the predicate yield true, or the default return expression if no test
1622expression matched.
1623
1624Throws: If there is no default return expression and the predicate does not
1625yield true with any test expression - $(D SwitchError) is thrown. $(D
1626SwitchError) is also thrown if a void return expression was executed without
1627throwing anything.
1628*/
1629auto 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/**
1736Checks if the two ranges have the same number of elements. This function is
1737optimized to always take advantage of the $(D length) member of either range
1738if it exists.
1739
1740If both ranges have a length member, this function is $(BIGOH 1). Otherwise,
1741this function is $(BIGOH min(r1.length, r2.length)).
1742
1743Params:
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
1747Returns:
1748 $(D true) if both ranges have the same length, $(D false) otherwise.
1749*/
1750bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
1751if (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
1865alias AllocateGC = Flag!"allocateGC";
1866
1867/**
1868Checks if both ranges are permutations of each other.
1869
1870This function can allocate if the $(D Yes.allocateGC) flag is passed. This has
1871the benefit of have better complexity than the $(D Yes.allocateGC) option. However,
1872this option is only available for ranges whose equality can be determined via each
1873element's $(D toHash) method. If customized equality is needed, then the $(D pred)
1874template parameter can be passed, and the function will automatically switch to
1875the non-allocating algorithm. See $(REF binaryFun, std,functional) for more details on
1876how to define $(D pred).
1877
1878Non-allocating forward range option: $(BIGOH n^2)
1879Non-allocating forward range option with custom $(D pred): $(BIGOH n^2)
1880Allocating forward range option: amortized $(BIGOH r1.length) + $(BIGOH r2.length)
1881
1882Params:
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
1888Returns:
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
1893bool isPermutation(AllocateGC allocate_gc, Range1, Range2)
1894(Range1 r1, Range2 r2)
1895if (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
1941bool isPermutation(alias pred = "a == b", Range1, Range2)
1942(Range1 r1, Range2 r2)
1943if (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/**
2079Get the _first argument `a` that passes an `if (unaryFun!pred(a))` test. If
2080no argument passes the test, return the last argument.
2081
2082Similar 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
2084returned upon no match.
2085
2086Simplifies logic, for instance, in parsing rules where a set of alternative
2087matchers are tried. The _first one that matches returns it match result,
2088typically as an abstract syntax tree (AST).
2089
2090Bugs:
2091Lazy parameters are currently, too restrictively, inferred by DMD to
2092always throw even though they don't need to be. This makes it impossible to
2093currently mark `either` as `nothrow`. See issue at $(BUGZILLA 12647).
2094
2095Returns:
2096 The _first argument that passes the test `pred`.
2097*/
2098CommonType!(T, Ts) either(alias pred = a => a, T, Ts...)(T first, lazy Ts alternatives)
2099if (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.
4module 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.
10package template algoFormat()
11{
12 import std.format : format;
13 alias algoFormat = format;
14}
15
16// Internal random array generators
17version (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
77package(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/**
3This is a submodule of $(MREF std, algorithm).
4It 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
56Copyright: Andrei Alexandrescu 2008-.
57
58License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
59
60Authors: $(HTTP erdani.com, Andrei Alexandrescu)
61
62Source: $(PHOBOSSRC std/algorithm/_iteration.d)
63
64Macros:
65T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
66 */
67module std.algorithm.iteration;
68
69// FIXME
70import std.functional; // : unaryFun, binaryFun;
71import std.range.primitives;
72import std.traits;
73
74private template aggregate(fun...)
75if (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)
121on each construction or call to $(D popFront),
122to store the result in a cache.
123The result is then directly returned when $(D front) is called,
124rather than re-evaluated.
125
126This can be a useful function to place in a chain, after functions
127that have expensive evaluation, as a lazy alternative to $(REF array, std,array).
128In particular, it can be placed after a call to $(D map), or before a call
129to $(D filter).
130
131$(D cache) may provide
132$(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
133iteration if needed, but since this comes at an increased cost, it must be explicitly requested via the
134call to $(D cacheBidirectional). Furthermore, a bidirectional cache will
135evaluate the "center" element twice, when there is only one element left in
136the range.
137
138$(D cache) does not provide random access primitives,
139as $(D cache) would be unable to cache the random accesses.
140If $(D Range) provides slicing primitives,
141then $(D cache) will provide the same slicing primitives,
142but $(D hasSlicing!Cache) will not yield true (as the $(REF hasSlicing, std,_range,primitives)
143trait also checks for random access).
144
145Params:
146 range = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
147
148Returns:
149 an input range with the cached values of range
150+/
151auto cache(Range)(Range range)
152if (isInputRange!Range)
153{
154 return _Cache!(Range, false)(range);
155}
156
157/// ditto
158auto cacheBidirectional(Range)(Range range)
159if (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/++
207Tip: $(D cache) is eager when evaluating elements. If calling front on the
208underlying _range has a side effect, it will be observable before calling
209front on the actual cached _range.
210
211Furthermore, care should be taken composing $(D cache) with $(REF take, std,_range).
212By placing $(D take) before $(D cache), then $(D cache) will be "aware"
213of when the _range ends, and correctly stop caching elements when needed.
214If calling front has no side effect though, placing $(D take) after $(D cache)
215may yield a faster _range.
216
217Either way, the resulting ranges will be equivalent, but maybe not at the
218same 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
309private 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
445Implements the homonym function (also known as $(D transform)) present
446in many languages of functional flavor. The call $(D map!(fun)(range))
447returns a range of which elements are obtained by applying $(D fun(a))
448left to right for all elements $(D a) in $(D range). The original ranges are
449not changed. Evaluation is done lazily.
450
451Params:
452 fun = one or more transformation functions
453 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
454
455Returns:
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
459See_Also:
460 $(HTTP en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function))
461*/
462template map(fun...)
463if (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/**
511Multiple functions can be passed to $(D map). In that case, the
512element type of $(D map) is a tuple containing one element for each
513function.
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/**
530You may alias $(D map) with some function(s) to a symbol and use
531it 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
553private 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/**
847Eagerly iterates over $(D r) and calls $(D pred) over _each element.
848
849If no predicate is specified, $(D each) will default to doing nothing
850but consuming the entire range. $(D .front) will be evaluated, but this
851can 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
855with e.g. $(REF parallel, std,parallelism).
856
857Params:
858 pred = predicate to apply to each element of the range
859 r = range or iterable over which each iterates
860
861See_Also: $(REF tee, std,range)
862
863 */
864template each(alias pred = "a")
865{
866 import std.meta : AliasSeq;
867 import std.traits : Parameters;
868
869private:
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
898public:
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
1086Implements the higher order _filter function. The predicate is passed to
1087$(REF unaryFun, std,functional), and can either accept a string, or any callable
1088that can be executed via $(D pred(element)).
1089
1090Params:
1091 predicate = Function to apply to each element of range
1092 range = Input range of elements
1093
1094Returns:
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
1098See_Also:
1099 $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function))
1100 */
1101template filter(alias predicate)
1102if (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
1139private 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 */
1322template 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
1349private 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/**
1398Groups consecutively equivalent elements into a single tuple of the element and
1399the number of its repetitions.
1400
1401Similarly to $(D uniq), $(D group) produces a range that iterates over unique
1402consecutive elements of the given range. Each element of this range is a tuple
1403of the element and the number of times it is repeated in the original range.
1404Equivalence of elements is assessed by using the predicate $(D pred), which
1405defaults to $(D "a == b"). The predicate is passed to $(REF binaryFun, std,functional),
1406and can either accept a string, or any callable that can be executed via
1407$(D pred(element, element)).
1408
1409Params:
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
1414Returns: A range of elements of type $(D Tuple!(ElementType!R, uint)),
1415representing each consecutively unique element and its respective number of
1416occurrences in that run. This will be an input range if $(D R) is an input
1417range, and a forward range in all other cases.
1418
1419See_Also: $(LREF chunkBy), which chunks an input range into subranges
1420 of equivalent adjacent elements.
1421*/
1422Group!(pred, Range) group(alias pred = "a == b", Range)(Range r)
1423{
1424 return typeof(return)(r);
1425}
1426
1427/// ditto
1428struct Group(alias pred, R)
1429if (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.
1604private struct ChunkByChunkImpl(alias pred, Range)
1605if (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
1627private 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.
1643private struct ChunkByImpl(alias pred, Range)
1644if (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.
1707private struct ChunkByImpl(alias pred, Range)
1708if (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 */
1923auto chunkBy(alias pred, Range)(Range r)
1924if (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
1956version (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
2097version (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/**
2118Lazily joins a range of ranges with a separator. The separator itself
2119is a range. If a separator is not provided, then the ranges are
2120joined directly without anything in between them (often called `flatten`
2121in other languages).
2122
2123Params:
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
2129Returns:
2130A range of elements in the joined range. This will be a forward range if
2131both outer and inner ranges of $(D RoR) are forward ranges; otherwise it will
2132be only an input range.
2133
2134See_also:
2135$(REF chain, std,range), which chains a sequence of ranges with compatible elements
2136into a single range.
2137 */
2138auto joiner(RoR, Separator)(RoR r, Separator sep)
2139if (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
2421auto joiner(RoR)(RoR r)
2422if (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/++
2729Implements the homonym function (also known as $(D accumulate), $(D
2730compress), $(D inject), or $(D foldl)) present in various programming
2731languages of functional flavor. There is also $(LREF fold) which does
2732the same thing but with the opposite parameter order.
2733The call $(D reduce!(fun)(seed, range)) first assigns $(D seed) to
2734an internal variable $(D result), also called the accumulator.
2735Then, for each element $(D x) in $(D range), $(D result = fun(result, x))
2736gets evaluated. Finally, $(D result) is returned.
2737The one-argument version $(D reduce!(fun)(range))
2738works similarly, but it uses the first element of the range as the
2739seed (the range must be non-empty).
2740
2741Returns:
2742 the accumulated $(D result)
2743
2744Params:
2745 fun = one or more functions
2746
2747See_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+/
2757template reduce(fun...)
2758if (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/**
2894Many aggregate range operations turn out to be solved with $(D reduce)
2895quickly and easily. The example below illustrates $(D reduce)'s
2896remarkable 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/**
2946Sometimes it is very useful to compute multiple aggregates in one pass.
2947One advantage is that the computation is faster because the looping overhead
2948is shared. That's why $(D reduce) accepts multiple functions.
2949If two or more functions are passed, $(D reduce) returns a
2950$(REF Tuple, std,typecons) object with one member per passed-in function.
2951The 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
3167private 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/++
3190Implements the homonym function (also known as $(D accumulate), $(D
3191compress), $(D inject), or $(D foldl)) present in various programming
3192languages of functional flavor. The call $(D fold!(fun)(range, seed))
3193first assigns $(D seed) to an internal variable $(D result),
3194also called the accumulator. Then, for each element $(D x) in $(D
3195range), $(D result = fun(result, x)) gets evaluated. Finally, $(D
3196result) is returned. The one-argument version $(D fold!(fun)(range))
3197works similarly, but it uses the first element of the range as the
3198seed (the range must be non-empty).
3199
3200Returns:
3201 the accumulated $(D result)
3202
3203See_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+/
3212template fold(fun...)
3213if (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/++
3267Similar to `fold`, but returns a range containing the successive reduced values.
3268The call $(D cumulativeFold!(fun)(range, seed)) first assigns `seed` to an
3269internal variable `result`, also called the accumulator.
3270The returned range contains the values $(D result = fun(result, x)) lazily
3271evaluated for each element `x` in `range`. Finally, the last element has the
3272same value as $(D fold!(fun)(seed, range)).
3273The one-argument version $(D cumulativeFold!(fun)(range)) works similarly, but
3274it returns the first element unchanged and uses it as seed for the next
3275elements.
3276This 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
3282Params:
3283 fun = one or more functions to use as fold operation
3284
3285Returns:
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
3290See_Also:
3291 $(HTTP en.wikipedia.org/wiki/Prefix_sum, Prefix Sum)
3292+/
3293template cumulativeFold(fun...)
3294if (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/**
3488Sometimes it is very useful to compute multiple aggregates in one pass.
3489One advantage is that the computation is faster because the looping overhead
3490is shared. That's why `cumulativeFold` accepts multiple functions.
3491If two or more functions are passed, `cumulativeFold` returns a $(REF Tuple,
3492std,typecons) object with one member per passed-in function.
3493The 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/**
3655Lazily splits a range using an element as a separator. This can be used with
3656any narrow string type or sliceable range type, but is most popular with string
3657types.
3658
3659Two adjacent separators are considered to surround an empty element in
3660the split range. Use $(D filter!(a => !a.empty)) on the result to compress
3661empty elements.
3662
3663The predicate is passed to $(REF binaryFun, std,functional), and can either accept
3664a string, or any callable that can be executed via $(D pred(element, s)).
3665
3666If the empty range is given, the result is a range with one empty
3667element. If a range with one separator is given, the result is a range
3668with two empty elements.
3669
3670If splitting a string on whitespace and token compression is desired,
3671consider using $(D splitter) without specifying a separator (see fourth overload
3672below).
3673
3674Params:
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
3682Constraints:
3683 The predicate $(D pred) needs to accept an element of $(D r) and the
3684 separator $(D s).
3685
3686Returns:
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
3692See_Also:
3693 $(REF _splitter, std,regex) for a version that splits using a regular
3694expression defined separator.
3695*/
3696auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
3697if (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/**
3943Similar to the previous overload of $(D splitter), except this one uses another
3944range as a separator. This can be used with any narrow string type or sliceable
3945range 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
3947that can be executed via $(D pred(r.front, s.front)).
3948
3949Two adjacent separators are considered to surround an empty element in
3950the split range. Use $(D filter!(a => !a.empty)) on the result to compress
3951empty elements.
3952
3953Params:
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
3961Constraints:
3962 The predicate $(D pred) needs to accept an element of $(D r) and an
3963 element of $(D s).
3964
3965Returns:
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
3970See_Also: $(REF _splitter, std,regex) for a version that splits using a regular
3971expression defined separator.
3972 */
3973auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
3974if (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
4207Similar to the previous overload of $(D splitter), except this one does not use a separator.
4208Instead, the predicate is an unary function on the input range's element type.
4209The $(D isTerminator) predicate is passed to $(REF unaryFun, std,functional) and can
4210either accept a string, or any callable that can be executed via $(D pred(element, s)).
4211
4212Two adjacent separators are considered to surround an empty element in
4213the split range. Use $(D filter!(a => !a.empty)) on the result to compress
4214empty elements.
4215
4216Params:
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
4221Constraints:
4222 The predicate $(D isTerminator) needs to accept an element of $(D input).
4223
4224Returns:
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
4229See_Also: $(REF _splitter, std,regex) for a version that splits using a regular
4230expression defined separator.
4231 */
4232auto splitter(alias isTerminator, Range)(Range input)
4233if (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
4256private 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/++
4460Lazily splits the string $(D s) into words, using whitespace as the delimiter.
4461
4462This 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
4466Params:
4467 s = The string to be split.
4468
4469Returns:
4470 An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of slices of
4471 the original string split by whitespace.
4472 +/
4473auto splitter(C)(C[] s)
4474if (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/**
4654Sums elements of $(D r), which must be a finite
4655$(REF_ALTTEXT input range, isInputRange, std,range,primitives). Although
4656conceptually $(D sum(r)) is equivalent to $(LREF fold)!((a, b) => a +
4657b)(r, 0), $(D sum) uses specialized algorithms to maximize accuracy,
4658as follows.
4659
4660$(UL
4661$(LI If $(D $(REF ElementType, std,range,primitives)!R) is a floating-point
4662type and $(D R) is a
4663$(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives) with
4664length and slicing, then $(D sum) uses the
4665$(HTTP en.wikipedia.org/wiki/Pairwise_summation, pairwise summation)
4666algorithm.)
4667$(LI If $(D ElementType!R) is a floating-point type and $(D R) is a
4668finite input range (but not a random-access range with slicing), then
4669$(D sum) uses the $(HTTP en.wikipedia.org/wiki/Kahan_summation,
4670Kahan summation) algorithm.)
4671$(LI In all other cases, a simple element by element addition is done.)
4672)
4673
4674For floating point inputs, calculations are made in
4675$(DDLINK spec/type, Types, $(D real))
4676precision for $(D real) inputs and in $(D double) precision otherwise
4677(Note this is a special case that deviates from $(D fold)'s behavior,
4678which would have kept $(D float) precision for a $(D float) range).
4679For all other types, the calculations are done in the same type obtained
4680from from adding two elements of the range, which may be a different
4681type from the elements themselves (for example, in case of
4682$(DDSUBLINK spec/type,integer-promotions, integral promotion)).
4683
4684A seed may be passed to $(D sum). Not only will this seed be used as an initial
4685value, but its type will override all the above, and determine the algorithm
4686and precision used for summation.
4687
4688Note that these specialized summing algorithms execute more primitive operations
4689than vanilla summation. Therefore, if in certain cases maximum speed is required
4690at expense of precision, one can use $(D fold!((a, b) => a + b)(r, 0)), which
4691is not specialized for summation.
4692
4693Params:
4694 seed = the initial value of the summation
4695 r = a finite input range
4696
4697Returns:
4698 The sum of all the elements in the range r.
4699 */
4700auto sum(R)(R r)
4701if (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
4711auto sum(R, E)(R r, E seed)
4712if (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
4731private auto sumPairwise(F, R)(R data)
4732if (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
4794private auto sumPairwise16(F, R)(R r)
4795if (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
4803private auto sumPair(bool needEmptyChecks, F, R)(ref R r)
4804if (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
4815private auto sumPairwiseN(size_t N, bool needEmptyChecks, F, R)(ref R r)
4816if (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
4826private 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/**
4948Lazily iterates unique consecutive elements of the given range (functionality
4949akin to the $(HTTP wikipedia.org/wiki/_Uniq, _uniq) system
4950utility). 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
4953that can be executed via $(D pred(element, element)). If the given range is
4954bidirectional, $(D uniq) also yields a
4955$(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives).
4956
4957Params:
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
4962Returns:
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*/
4967auto uniq(alias pred = "a == b", Range)(Range r)
4968if (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
4992private 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/**
3This is a submodule of $(MREF std, algorithm).
4It 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
67Copyright: Andrei Alexandrescu 2008-.
68
69License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
70
71Authors: $(HTTP erdani.com, Andrei Alexandrescu)
72
73Source: $(PHOBOSSRC std/algorithm/_mutation.d)
74
75Macros:
76T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
77 */
78module std.algorithm.mutation;
79
80import std.range.primitives;
81import std.traits : isArray, isBlitAssignable, isNarrowString, Unqual, isSomeChar;
82// FIXME
83import std.typecons; // : tuple, Tuple;
84
85// bringToFront
86/**
87The $(D bringToFront) function has considerable flexibility and
88usefulness. It can rotate elements in one buffer left or right, swap
89buffers of equal length, and even move elements across disjoint
90buffers of different types and different lengths.
91
92$(D bringToFront) takes two ranges $(D front) and $(D back), which may
93be of different types. Considering the concatenation of $(D front) and
94$(D back) one unified range, $(D bringToFront) rotates that unified
95range such that all elements in $(D back) are brought to the beginning
96of the unified range. The relative ordering of elements in $(D front)
97and $(D back), respectively, remains unchanged.
98
99The $(D bringToFront) function treats strings at the code unit
100level and it is not concerned with Unicode character integrity.
101$(D bringToFront) is designed as a function for moving elements
102in ranges, not as a string function.
103
104Performs $(BIGOH max(front.length, back.length)) evaluations of $(D
105swap).
106
107Preconditions:
108
109Either $(D front) and $(D back) are disjoint, or $(D back) is
110reachable from $(D front) and $(D front) is not reachable from $(D
111back).
112
113Params:
114 front = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
115 back = a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
116
117Returns:
118 The number of elements brought to the front, i.e., the length of $(D back).
119
120See_Also:
121 $(HTTP sgi.com/tech/stl/_rotate.html, STL's rotate)
122*/
123size_t bringToFront(InputRange, ForwardRange)(InputRange front, ForwardRange back)
124if (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
148private size_t bringToFrontImpl(InputRange, ForwardRange)(InputRange front, ForwardRange back)
149if (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/**
212The simplest use of $(D bringToFront) is for rotating elements in a
213buffer. 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/**
224The $(D front) range may actually "step over" the $(D back)
225range. This is very useful with forward ranges that cannot compute
226comfortably right-bounded subranges like $(D arr[0 .. 4]) above. In
227the 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/**
244Elements 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/**
259Unicode 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.
349private enum bool areCopyCompatibleArrays(T1, T2) =
350 isArray!T1 && isArray!T2 && is(typeof(T2.init[] = T1.init[]));
351
352// copy
353/**
354Copies the content of $(D source) into $(D target) and returns the
355remaining (unfilled) part of $(D target).
356
357Preconditions: $(D target) shall have enough room to accommodate
358the entirety of $(D source).
359
360Params:
361 source = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
362 target = an output range
363
364Returns:
365 The unfilled part of target
366
367See_Also:
368 $(HTTP sgi.com/tech/stl/_copy.html, STL's _copy)
369 */
370TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
371if (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
399TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
400if (!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/**
438As long as the target range elements support assignment from source
439range 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/**
449To _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/**
462To _copy just those elements from a range that satisfy a predicate,
463use $(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/**
542Assigns $(D value) to each element of input _range $(D range).
543
544Params:
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
551See_Also:
552 $(LREF uninitializedFill)
553 $(LREF initializeAll)
554 */
555void fill(Range, Value)(auto ref Range range, auto ref Value value)
556if ((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/**
716Fills $(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
718filler). If $(D filler) is empty, an exception is thrown.
719
720Params:
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 */
727void fill(InputRange, ForwardRange)(InputRange range, ForwardRange filler)
728if (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/**
835Initializes all elements of $(D range) with their $(D .init) value.
836Assumes that the elements of the range are uninitialized.
837
838Params:
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
844See_Also:
845 $(LREF fill)
846 $(LREF uninitializeFill)
847 */
848void initializeAll(Range)(Range range)
849if (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
897void initializeAll(Range)(Range range)
898if (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/**
1029Moves `source` into `target`, via a destructive copy when necessary.
1030
1031If `T` is a struct with a destructor or postblit defined, source is reset
1032to its `.init` value after it is moved into target, otherwise it is
1033left unchanged.
1034
1035Preconditions:
1036If source has internal pointers that point to itself, it cannot be moved, and
1037will trigger an assertion failure.
1038
1039Params:
1040 source = Data to copy.
1041 target = Where to copy into. The destructor, if any, is invoked before the
1042 copy is performed.
1043*/
1044void 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///
1067pure 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
1163T 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:
1173pure 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
1188private void trustedMoveImpl(T)(ref T source, ref T target) @trusted
1189{
1190 moveImpl(source, target);
1191}
1192
1193private 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
1207private T trustedMoveImpl(T)(ref T source) @trusted
1208{
1209 return moveImpl(source);
1210}
1211
1212private 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 */
1364void 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///
1412pure 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/**
1438Calls `move(a, b)` for each element `a` in `src` and the corresponding
1439element `b` in `tgt`, in increasing order.
1440
1441Preconditions:
1442`walkLength(src) <= walkLength(tgt)`.
1443This 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
1446Params:
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
1452Returns: The leftover portion of $(D tgt) after all elements from $(D src) have
1453been moved.
1454 */
1455InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1456if (isInputRange!InputRange1 && isInputRange!InputRange2
1457 && is(typeof(move(src.front, tgt.front))))
1458{
1459 return moveAllImpl!move(src, tgt);
1460}
1461
1462///
1463pure 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 */
1478InputRange2 moveEmplaceAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1479if (isInputRange!InputRange1 && isInputRange!InputRange2
1480 && is(typeof(moveEmplace(src.front, tgt.front))))
1481{
1482 return moveAllImpl!moveEmplace(src, tgt);
1483}
1484
1485///
1486pure 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
1522private 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/**
1549Calls `move(a, b)` for each element `a` in `src` and the corresponding
1550element `b` in `tgt`, in increasing order, stopping when either range has been
1551exhausted.
1552
1553Params:
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
1559Returns: The leftover portions of the two ranges after one or the other of the
1560ranges have been exhausted.
1561 */
1562Tuple!(InputRange1, InputRange2) moveSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1563if (isInputRange!InputRange1 && isInputRange!InputRange2
1564 && is(typeof(move(src.front, tgt.front))))
1565{
1566 return moveSomeImpl!move(src, tgt);
1567}
1568
1569///
1570pure 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 */
1584Tuple!(InputRange1, InputRange2) moveEmplaceSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1585if (isInputRange!InputRange1 && isInputRange!InputRange2
1586 && is(typeof(move(src.front, tgt.front))))
1587{
1588 return moveSomeImpl!moveEmplace(src, tgt);
1589}
1590
1591///
1592pure 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
1612private 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/**
1623Defines the swapping strategy for algorithms that need to swap
1624elements in a range (such as partition and sort). The strategy
1625concerns the swapping of elements that are not the core concern of the
1626algorithm. For example, consider an algorithm that sorts $(D [ "abc",
1627"b", "aBc" ]) according to $(D toUpper(a) < toUpper(b)). That
1628algorithm might choose to swap the two equivalent strings $(D "abc")
1629and $(D "aBc"). That does not affect the sorting since both $(D [
1630"abc", "aBc", "b" ]) and $(D [ "aBc", "abc", "b" ]) are valid
1631outcomes.
1632
1633Some situations require that the algorithm must NOT ever change the
1634relative ordering of equivalent elements (in the example above, only
1635$(D [ "abc", "aBc", "b" ]) would be the correct result). Such
1636algorithms are called $(B stable). If the ordering algorithm may swap
1637equivalent elements discretionarily, the ordering is called $(B
1638unstable).
1639
1640Yet another class of algorithms may choose an intermediate tradeoff by
1641being stable only on a well-defined subrange of the range. There is no
1642established terminology for such behavior; this library calls it $(B
1643semistable).
1644
1645Generally, the $(D stable) ordering strategy may be more costly in
1646time and/or space than the other two because it imposes additional
1647constraints. Similarly, $(D semistable) may be costlier than $(D
1648unstable). As (semi-)stability is not needed very often, the ordering
1649algorithms in this module parameterized by $(D SwapStrategy) all
1650choose $(D SwapStrategy.unstable) as the default.
1651*/
1652
1653enum 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/**
1703Eliminates elements at given offsets from `range` and returns the shortened
1704range.
1705
1706For example, here is how to _remove a single element from an array:
1707
1708----
1709string[] a = [ "a", "b", "c", "d" ];
1710a = a.remove(1); // remove element at offset 1
1711assert(a == [ "a", "c", "d"]);
1712----
1713
1714Note that `remove` does not change the length of the original _range directly;
1715instead, it returns the shortened _range. If its return value is not assigned to
1716the original _range, the original _range will retain its original length, though
1717its contents will have changed:
1718
1719----
1720int[] a = [ 3, 5, 7, 8 ];
1721assert(remove(a, 1) == [ 3, 7, 8 ]);
1722assert(a == [ 3, 7, 8, 8 ]);
1723----
1724
1725The element at _offset `1` has been removed and the rest of the elements have
1726shifted up to fill its place, however, the original array remains of the same
1727length. This is because all functions in `std.algorithm` only change $(I
1728content), not $(I topology). The value `8` is repeated because $(LREF move) was
1729invoked to rearrange elements, and on integers `move` simply copies the source
1730to the destination. To replace `a` with the effect of the removal, simply
1731assign the slice returned by `remove` to it, as shown in the first example.
1732
1733Multiple indices can be passed into $(D remove). In that case,
1734elements at the respective indices are all removed. The indices must
1735be passed in increasing order, otherwise an exception occurs.
1736
1737----
1738int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1739assert(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
1744in the array as it is being progressively shortened.) Finally, any
1745combination of integral offsets and tuples composed of two integral
1746offsets can be passed in.
1747
1748----
1749int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1750assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);
1751----
1752
1753In this case, the slots at positions 1, 3, 4, and 9 are removed from
1754the array. The tuple passes in a range closed to the left and open to
1755the right (consistent with built-in slices), e.g. $(D tuple(3, 5))
1756means indices $(D 3) and $(D 4) but not $(D 5).
1757
1758If the need is to remove some elements in the range but the order of
1759the remaining elements does not have to be preserved, you may want to
1760pass $(D SwapStrategy.unstable) to $(D remove).
1761
1762----
1763int[] a = [ 0, 1, 2, 3 ];
1764assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
1765----
1766
1767In the case above, the element at slot $(D 1) is removed, but replaced
1768with the last element of the range. Taking advantage of the relaxation
1769of the stability requirement, $(D remove) moved elements from the end
1770of the array over the slots to be removed. This way there is less data
1771movement to be done which improves the execution time of the function.
1772
1773The function $(D remove) works on bidirectional ranges that have assignable
1774lvalue elements. The moving strategy is (listed from fastest to slowest):
1775$(UL $(LI If $(D s == SwapStrategy.unstable && isRandomAccessRange!Range &&
1776hasLength!Range && hasLvalueElements!Range), then elements are moved from the
1777end of the range into the slots to be filled. In this case, the absolute
1778minimum of moves is performed.) $(LI Otherwise, if $(D s ==
1779SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range
1780&& hasLvalueElements!Range), then elements are still moved from the
1781end of the range, but time is spent on advancing between slots by repeated
1782calls to $(D range.popFront).) $(LI Otherwise, elements are moved
1783incrementally towards the front of $(D range); a given element is never
1784moved several times, but more elements are moved than in the previous
1785cases.))
1786
1787Params:
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
1793Returns:
1794 a range containing all of the elements of range with offset removed
1795 */
1796Range remove
1797(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
1798(Range range, Offset offset)
1799if (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
1883Range remove
1884(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
1885(Range range, Offset offset)
1886if (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/**
2023Reduces the length of the
2024$(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,_range,primitives) $(D range) by removing
2025elements that satisfy $(D pred). If $(D s = SwapStrategy.unstable),
2026elements are moved from the right end of the range over the elements
2027to eliminate. If $(D s = SwapStrategy.stable) (the default),
2028elements are moved progressively to front such that their relative
2029order is preserved. Returns the filtered range.
2030
2031Params:
2032 range = a bidirectional ranges with lvalue elements
2033
2034Returns:
2035 the range with all of the elements where $(D pred) is $(D true)
2036 removed
2037*/
2038Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)
2039(Range range)
2040if (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/**
2184Reverses $(D r) in-place. Performs $(D r.length / 2) evaluations of $(D
2185swap).
2186Params:
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
2190See_Also:
2191 $(HTTP sgi.com/tech/stl/_reverse.html, STL's _reverse), $(REF retro, std,range) for a lazy reversed range view
2192*/
2193void reverse(Range)(Range r)
2194if (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
2215void reverse(Range)(Range r)
2216if (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/**
2243Reverses $(D r) in-place, where $(D r) is a narrow string (having
2244elements of type $(D char) or $(D wchar)). UTF sequences consisting of
2245multiple code units are preserved properly.
2246
2247Params:
2248 s = a narrow string
2249
2250Bugs:
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*/
2256void reverse(Char)(Char[] s)
2257if (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*/
2331Range strip(Range, E)(Range range, E element)
2332if (isBidirectionalRange!Range && is(typeof(range.front == element) : bool))
2333{
2334 return range.stripLeft(element).stripRight(element);
2335}
2336
2337/// ditto
2338Range strip(alias pred, Range)(Range range)
2339if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2340{
2341 return range.stripLeft!pred().stripRight!pred();
2342}
2343
2344/// ditto
2345Range stripLeft(Range, E)(Range range, E element)
2346if (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
2353Range stripLeft(alias pred, Range)(Range range)
2354if (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
2363Range stripRight(Range, E)(Range range, E element)
2364if (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
2375Range stripRight(alias pred, Range)(Range range)
2376if (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/**
2448Swaps $(D lhs) and $(D rhs). The instances $(D lhs) and $(D rhs) are moved in
2449memory, without ever calling $(D opAssign), nor any other function. $(D T)
2450need not be assignable at all to be swapped.
2451
2452If $(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
2455its fields must also all be (recursively) mutable.
2456
2457Params:
2458 lhs = Data to be swapped with $(D rhs).
2459 rhs = Data to be swapped with $(D lhs).
2460*/
2461void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow @nogc
2462if (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
2690void swap(T)(ref T lhs, ref T rhs)
2691if (is(typeof(lhs.proxySwap(rhs))))
2692{
2693 lhs.proxySwap(rhs);
2694}
2695
2696/**
2697Swaps two elements in-place of a range `r`,
2698specified by their indices `i1` and `i2`.
2699
2700Params:
2701 r = a range with swappable elements
2702 i1 = first index
2703 i2 = second index
2704*/
2705void 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///
2726pure @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
2734pure @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
2742pure @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
2806private void swapFront(R1, R2)(R1 r1, R2 r2)
2807if (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/**
2823Swaps all elements of $(D r1) with successive elements in $(D r2).
2824Returns a tuple containing the remainder portions of $(D r1) and $(D
2825r2) that were not swapped (one of them will be empty). The ranges may
2826be of different types but must have the same element type and support
2827swapping.
2828
2829Params:
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
2835Returns:
2836 Tuple containing the remainder portions of r1 and r2 that were not swapped
2837*/
2838Tuple!(InputRange1, InputRange2)
2839swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
2840if (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/**
2863Initializes each element of $(D range) with $(D value).
2864Assumes that the elements of the range are uninitialized.
2865This is of interest for structs that
2866define copy constructors (for all other types, $(LREF fill) and
2867uninitializedFill are equivalent).
2868
2869Params:
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
2876See_Also:
2877 $(LREF fill)
2878 $(LREF initializeAll)
2879 */
2880void uninitializedFill(Range, Value)(Range range, Value value)
2881if (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///
2900nothrow @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/**
4This package implements generic algorithms oriented towards the processing of
5sequences. Sequences processed by these functions define range-based
6interfaces. 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
11Algorithms 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
151Many functions in this package are parameterized with a $(GLOSSARY predicate).
152The predicate may be any suitable callable type
153(a function, a delegate, a $(GLOSSARY functor), or a lambda), or a
154compile-time string. The string may consist of $(B any) legal D
155expression that uses the symbol $(D a) (for unary functions) or the
156symbols $(D a) and $(D b) (for binary functions). These names will NOT
157interfere with other homonym symbols in user code because they are
158evaluated in a different context. The default for all binary
159comparison predicates is $(D "a == b") for unordered operations and
160$(D "a < b") for ordered operations.
161
162Example:
163
164----
165int[] a = ...;
166static bool greater(int a, int b)
167{
168 return a > b;
169}
170sort!greater(a); // predicate as alias
171sort!((a, b) => a > b)(a); // predicate as a lambda.
172sort!"a > b"(a); // predicate as string
173 // (no ambiguity with array name)
174sort(a); // no predicate, "a < b" is implicit
175----
176
177Macros:
178SUBMODULE = $(MREF_ALTTEXT $1, std, algorithm, $2)
179SUBREF = $(REF_ALTTEXT $(TT $2), $2, std, algorithm, $1)$(NBSP)
180
181Copyright: Andrei Alexandrescu 2008-.
182
183License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
184
185Authors: $(HTTP erdani.com, Andrei Alexandrescu)
186
187Source: $(PHOBOSSRC std/_algorithm/package.d)
188 */
189module std.algorithm;
190
191public import std.algorithm.comparison;
192public import std.algorithm.iteration;
193public import std.algorithm.mutation;
194public import std.algorithm.searching;
195public import std.algorithm.setops;
196public import std.algorithm.sorting;
197
198static import std.functional;
gcc/libphobos/src/std/algorithm/searching.d+4600−0
@@ -0,0 +1,4600 @@
1// Written in the D programming language.
2/**
3This is a submodule of $(MREF std, algorithm).
4It 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
95Copyright: Andrei Alexandrescu 2008-.
96
97License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
98
99Authors: $(HTTP erdani.com, Andrei Alexandrescu)
100
101Source: $(PHOBOSSRC std/algorithm/_searching.d)
102
103Macros:
104T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
105 */
106module std.algorithm.searching;
107
108// FIXME
109import std.functional; // : unaryFun, binaryFun;
110import std.range.primitives;
111import std.traits;
112// FIXME
113import std.typecons; // : Tuple, Flag, Yes, No;
114
115/++
116Checks if $(I _all) of the elements verify $(D pred).
117 +/
118template 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
143evaluated to true or false in a conditional statement. This can be a
144convenient way to quickly evaluate that $(I _all) of the elements of a range
145are 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/++
160Checks 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).
163This is sometimes called `exists` in other languages.
164 +/
165template 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
189evaluated to true or false in a conditional statement. $(D !any) can be a
190convenient way to quickly test that $(I none) of the elements of a range
191evaluate 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/**
215Checks whether $(D r) has "balanced parentheses", i.e. all instances
216of $(D lPar) are closed by corresponding instances of $(D rPar). The
217parameter $(D maxNestingLevel) controls the nesting level allowed. The
218most common uses are the default or $(D 0). In the latter case, no
219nesting is allowed.
220
221Params:
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
227Returns:
228 true if the given range has balanced parenthesis within the given maximum
229 nesting level; false otherwise.
230*/
231bool balancedParens(Range, E)(Range r, E lPar, E rPar,
232 size_t maxNestingLevel = size_t.max)
233if (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 */
280struct BoyerMooreFinder(alias pred, Range)
281{
282private:
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/*
294This helper function checks whether the last "portion" bytes of
295"needle" (which is "nlen" bytes long) exist within the "needle" at
296offset "offset" (counted from the end of the string), and whether the
297character preceding "offset" is not a match. Notice that the range
298being checked may reach beyond the beginning of the string. Such range
299is 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
321public:
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
382BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder
383(alias pred = "a == b", Range)
384(Range needle)
385if ((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/**
406Returns the common prefix of two ranges.
407
408Params:
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
418Returns:
419A slice of $(D r1) which contains the characters that both ranges start with,
420if 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
422prefix of both ranges.
423
424See_Also:
425 $(REF takeExactly, std,range)
426 */
427auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2)
428if (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
467auto commonPrefix(alias pred, R1, R2)(R1 r1, R2 r2)
468if (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
488auto commonPrefix(R1, R2)(R1 r1, R2 r2)
489if (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
496auto commonPrefix(R1, R2)(R1 r1, R2 r2)
497if (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/**
594The first version counts the number of elements $(D x) in $(D r) for
595which $(D pred(x, value)) is $(D true). $(D pred) defaults to
596equality. Performs $(BIGOH haystack.length) evaluations of $(D pred).
597
598The second version returns the number of times $(D needle) occurs in
599$(D haystack). Throws an exception if $(D needle.empty), as the _count
600of the empty range in any range would be infinite. Overlapped counts
601are not considered, for example $(D count("aaa", "aa")) is $(D 1), not
602$(D 2).
603
604The third version counts the elements for which $(D pred(x)) is $(D
605true). Performs $(BIGOH haystack.length) evaluations of $(D pred).
606
607The fourth version counts the number of elements in a range. It is
608an optimization for the third version: if the given range has the
609`length` property the count is returned right away, otherwise
610performs $(BIGOH haystack.length) to walk the range.
611
612Note: Regardless of the overload, $(D count) will not accept
613infinite ranges for $(D haystack).
614
615Params:
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
620Returns:
621 The number of positions in the `haystack` for which `pred` returned true.
622*/
623size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle)
624if (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
677size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
678if (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
701size_t count(alias pred, R)(R haystack)
702if (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
713size_t count(R)(R haystack)
714if (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 +/
755ptrdiff_t countUntil(alias pred = "a == b", R, Rs...)(R haystack, Rs needles)
756if (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
843ptrdiff_t countUntil(alias pred = "a == b", R, N)(R haystack, N needle)
844if (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 +/
913ptrdiff_t countUntil(alias pred, R)(R haystack)
914if (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/**
997Checks if the given range ends with (one of) the given needle(s).
998The reciprocal of $(D startsWith).
999
1000Params:
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
1013Returns:
10140 if the needle(s) do not occur at the end of the given range;
1015otherwise the position of the matching needle, that is, 1 if the range ends
1016with $(D withOneOfThese[0]), 2 if it ends with $(D withOneOfThese[1]), and so
1017on.
1018
1019In the case when no needle parameters are given, return $(D true) iff back of
1020$(D doesThisStart) fulfils predicate $(D pred).
1021*/
1022uint endsWith(alias pred = "a == b", Range, Needles...)(Range doesThisEnd, Needles withOneOfThese)
1023if (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
1089bool endsWith(alias pred = "a == b", R1, R2)(R1 doesThisEnd, R2 withThis)
1090if (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
1117bool endsWith(alias pred = "a == b", R, E)(R doesThisEnd, E withThis)
1118if (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
1142bool endsWith(alias pred, R)(R doesThisEnd)
1143if (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/**
1261Iterates the passed range and selects the extreme element with `less`.
1262If the extreme element occurs multiple time, the first occurrence will be
1263returned.
1264
1265Params:
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
1271Returns:
1272 The extreme value according to `map` and `selector` of the passed-in values.
1273*/
1274private auto extremum(alias map, alias selector = "a < b", Range)(Range r)
1275if (isInputRange!Range && !isInfinite!Range &&
1276 is(typeof(unaryFun!map(ElementType!(Range).init))))
1277in
1278{
1279 assert(!r.empty, "r is an empty range");
1280}
1281body
1282{
1283 alias Element = ElementType!Range;
1284 Unqual!Element seed = r.front;
1285 r.popFront();
1286 return extremum!(map, selector)(r, seed);
1287}
1288
1289private auto extremum(alias map, alias selector = "a < b", Range,
1290 RangeElementType = ElementType!Range)
1291 (Range r, RangeElementType seedElement)
1292if (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
1335private 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
1346private 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/**
1460Finds an individual element in an input range. Elements of $(D
1461haystack) are compared with $(D needle) by using predicate $(D
1462pred). Performs $(BIGOH walkLength(haystack)) evaluations of $(D
1463pred).
1464
1465To _find the last occurrence of $(D needle) in $(D haystack), call $(D
1466find(retro(haystack), needle)). See $(REF retro, std,range).
1467
1468Params:
1469
1470pred = The predicate for comparing each element with the needle, defaulting to
1471$(D "a == b").
1472The negated predicate $(D "a != b") can be used to search instead for the first
1473element $(I not) matching the needle.
1474
1475haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1476searched in.
1477
1478needle = The element searched for.
1479
1480Constraints:
1481
1482$(D isInputRange!InputRange && is(typeof(binaryFun!pred(haystack.front, needle)
1483: bool)))
1484
1485Returns:
1486
1487$(D haystack) advanced such that the front element is the one searched for;
1488that is, until $(D binaryFun!pred(haystack.front, needle)) is $(D true). If no
1489such position exists, returns an empty $(D haystack).
1490
1491See_Also:
1492 $(HTTP sgi.com/tech/stl/_find.html, STL's _find)
1493 */
1494InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)
1495if (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/**
1769Advances the input range $(D haystack) by calling $(D haystack.popFront)
1770until either $(D pred(haystack.front)), or $(D
1771haystack.empty). Performs $(BIGOH haystack.length) evaluations of $(D
1772pred).
1773
1774To _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
1780Params:
1781
1782pred = The predicate for determining if a given element is the one being
1783searched for.
1784
1785haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
1786search in.
1787
1788Returns:
1789
1790$(D haystack) advanced such that the front element is the one searched for;
1791that is, until $(D binaryFun!pred(haystack.front, needle)) is $(D true). If no
1792such position exists, returns an empty $(D haystack).
1793
1794See_Also:
1795 $(HTTP sgi.com/tech/stl/find_if.html, STL's find_if)
1796*/
1797InputRange find(alias pred, InputRange)(InputRange haystack)
1798if (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/**
1851Finds the first occurrence of a forward range in another forward range.
1852
1853Performs $(BIGOH walkLength(haystack) * walkLength(needle)) comparisons in the
1854worst case. There are specializations that improve performance by taking
1855advantage of $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
1856or random access in the given ranges (where possible), depending on the statistics
1857of the two ranges' content.
1858
1859Params:
1860
1861pred = The predicate to use for comparing respective elements from the haystack
1862and the needle. Defaults to simple equality $(D "a == b").
1863
1864haystack = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
1865searched in.
1866
1867needle = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
1868searched for.
1869
1870Returns:
1871
1872$(D haystack) advanced such that $(D needle) is a prefix of it (if no
1873such position exists, returns $(D haystack) advanced to termination).
1874 */
1875R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)
1876if (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
2175private 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/**
2272Finds two or more $(D needles) into a $(D haystack). The predicate $(D
2273pred) is used throughout to compare elements. By default, elements are
2274compared for equality.
2275
2276Params:
2277
2278pred = The predicate to use for comparing elements.
2279
2280haystack = The target of the search. Must be an input range.
2281If any of $(D needles) is a range with elements comparable to
2282elements in $(D haystack), then $(D haystack) must be a
2283$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
2284such that the search can backtrack.
2285
2286needles = One or more items to search for. Each of $(D needles) must
2287be either comparable to one element in $(D haystack), or be itself a
2288forward range with elements comparable with elements in
2289$(D haystack).
2290
2291Returns:
2292
2293A tuple containing $(D haystack) positioned to match one of the
2294needles and also the 1-based index of the matching element in $(D
2295needles) (0 if none of $(D needles) matched, 1 if $(D needles[0])
2296matched, 2 if $(D needles[1]) matched...). The first needle to be found
2297will be the one that matches. If multiple needles are found at the
2298same 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
2301matches).
2302
2303The relationship between $(D haystack) and $(D needles) simply means
2304that one can e.g. search for individual $(D int)s or arrays of $(D
2305int)s in an array of $(D int)s. In addition, if elements are
2306individually comparable, searches of heterogeneous types are allowed
2307as well: a $(D double[]) can be searched for an $(D int) or a $(D
2308short[]), and conversely a $(D long) can be searched for a $(D float)
2309or a $(D double[]). This makes for efficient searches without the need
2310to coerce one side of the comparison into the other's side type.
2311
2312The complexity of the search is $(BIGOH haystack.length *
2313max(needles.length)). (For needles that are individual items, length
2314is considered to be 1.) The strategy used in searching several
2315subranges at once maximizes cache usage by moving in $(D haystack) as
2316few times as possible.
2317 */
2318Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)
2319(Range haystack, Ranges needles)
2320if (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 */
2433RandomAccessRange 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/++
2472Convenience function. Like find, but only returns whether or not the search
2473was successful.
2474
2475See_Also:
2476$(LREF among) for checking a value against multiple possibilities.
2477 +/
2478template 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/**
2572Advances $(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)
2574evaluations of $(D pred).
2575
2576Params:
2577 pred = The predicate to satisfy.
2578 r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
2579 search in.
2580
2581Returns:
2582$(D r) advanced to the first occurrence of two adjacent elements that satisfy
2583the given predicate. If there are no such two elements, returns $(D r) advanced
2584until empty.
2585
2586See_Also:
2587 $(HTTP sgi.com/tech/stl/adjacent_find.html, STL's adjacent_find)
2588*/
2589Range findAdjacent(alias pred = "a == b", Range)(Range r)
2590if (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/**
2645Searches the given range for an element that matches one of the given choices.
2646
2647Advances $(D seq) by calling $(D seq.popFront) until either
2648$(D find!(pred)(choices, seq.front)) is $(D true), or $(D seq) becomes empty.
2649Performs $(BIGOH seq.length * choices.length) evaluations of $(D pred).
2650
2651Params:
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
2658Returns:
2659$(D seq) advanced to the first matching element, or until empty if there are no
2660matching elements.
2661
2662See_Also:
2663 $(HTTP sgi.com/tech/stl/find_first_of.html, STL's find_first_of)
2664*/
2665InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)(
2666 InputRange seq, ForwardRange choices)
2667if (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 */
2710bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle)
2711if (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/**
2740These functions find the first occurrence of `needle` in `haystack` and then
2741split `haystack` as follows.
2742
2743`findSplit` returns a tuple `result` containing $(I three) ranges. `result[0]`
2744is 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`
2746after the match. If `needle` was not found, `result[0]` comprehends `haystack`
2747entirely and `result[1]` and `result[2]` are empty.
2748
2749`findSplitBefore` returns a tuple `result` containing two ranges. `result[0]` is
2750the 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]`
2752comprehends `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
2756match, and `result[1]` is the balance of `haystack` starting
2757after the match. If `needle` was not found, `result[0]` is empty
2758and `result[1]` is `haystack`.
2759
2760In all cases, the concatenation of the returned ranges spans the
2761entire `haystack`.
2762
2763If `haystack` is a random-access range, all three components of the tuple have
2764the same type as `haystack`. Otherwise, `haystack` must be a
2765$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and
2766the type of `result[0]` and `result[1]` is the same as $(REF takeExactly,
2767std,range).
2768
2769Params:
2770 pred = Predicate to use for comparing needle against haystack.
2771 haystack = The range to search.
2772 needle = What to look for.
2773
2774Returns:
2775
2776A sub-type of `Tuple!()` of the split portions of `haystack` (see above for
2777details). 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
2780shown in the following example.
2781
2782Example:
2783---
2784if (const split = haystack.findSplit(needle))
2785{
2786 doSomethingWithSplit(split);
2787}
2788---
2789 */
2790auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
2791if (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
2854auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
2855if (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
2914auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
2915if (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
3122Computes the minimum (respectively maximum) of `range` along with its number of
3123occurrences. Formally, the minimum is a value `x` in `range` such that $(D
3124pred(a, x)) is `false` for all values `a` in `range`. Conversely, the maximum is
3125a value `x` in `range` such that $(D pred(x, a)) is `false` for all values `a`
3126in `range` (note the swapped arguments to `pred`).
3127
3128These functions may be used for computing arbitrary extrema by choosing `pred`
3129appropriately. For corrrect functioning, `pred` must be a strict partial order,
3130i.e. transitive (if $(D pred(a, b) && pred(b, c)) then $(D pred(a, c))) and
3131irreflexive ($(D pred(a, a)) is `false`). The $(LUCKY trichotomy property of
3132inequality) 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,
3134i.e. $(D !pred(a, b) && !pred(b, a)).
3135
3136Params:
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
3141Returns: The minimum, respectively maximum element of a range together with the
3142number it occurs in the range.
3143
3144Throws: `Exception` if `range.empty`.
3145 */
3146Tuple!(ElementType!Range, size_t)
3147minCount(alias pred = "a < b", Range)(Range range)
3148if (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
3233Tuple!(ElementType!Range, size_t)
3234maxCount(alias pred = "a < b", Range)(Range range)
3235if (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/**
3336Iterates the passed range and returns the minimal element.
3337A custom mapping function can be passed to `map`.
3338In other languages this is sometimes called `argmin`.
3339
3340Complexity: O(n)
3341 Exactly `n - 1` comparisons are needed.
3342
3343Params:
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
3348Returns: The minimal element of the passed-in range.
3349
3350See_Also:
3351 $(REF min, std,algorithm,comparison)
3352*/
3353auto minElement(alias map, Range)(Range r)
3354if (isInputRange!Range && !isInfinite!Range)
3355{
3356 return extremum!map(r);
3357}
3358
3359/// ditto
3360auto minElement(Range)(Range r)
3361 if (isInputRange!Range && !isInfinite!Range)
3362{
3363 return extremum(r);
3364}
3365
3366/// ditto
3367auto minElement(alias map, Range, RangeElementType = ElementType!Range)
3368 (Range r, RangeElementType seed)
3369if (isInputRange!Range && !isInfinite!Range &&
3370 !is(CommonType!(ElementType!Range, RangeElementType) == void))
3371{
3372 return extremum!map(r, seed);
3373}
3374
3375/// ditto
3376auto 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/**
3450Iterates the passed range and returns the maximal element.
3451A custom mapping function can be passed to `map`.
3452In other languages this is sometimes called `argmax`.
3453
3454Complexity:
3455 Exactly `n - 1` comparisons are needed.
3456
3457Params:
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
3462Returns: The maximal element of the passed-in range.
3463
3464See_Also:
3465 $(REF max, std,algorithm,comparison)
3466*/
3467auto maxElement(alias map, Range)(Range r)
3468if (isInputRange!Range && !isInfinite!Range)
3469{
3470 return extremum!(map, "a > b")(r);
3471}
3472
3473/// ditto
3474auto maxElement(Range)(Range r)
3475if (isInputRange!Range && !isInfinite!Range)
3476{
3477 return extremum!`a > b`(r);
3478}
3479
3480/// ditto
3481auto maxElement(alias map, Range, RangeElementType = ElementType!Range)
3482 (Range r, RangeElementType seed)
3483if (isInputRange!Range && !isInfinite!Range &&
3484 !is(CommonType!(ElementType!Range, RangeElementType) == void))
3485{
3486 return extremum!(map, "a > b")(r, seed);
3487}
3488
3489/// ditto
3490auto maxElement(Range, RangeElementType = ElementType!Range)
3491 (Range r, RangeElementType seed)
3492if (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/**
3567Computes a subrange of `range` starting at the first occurrence of `range`'s
3568minimum (respectively maximum) and with the same ending as `range`, or the
3569empty range if `range` itself is empty.
3570
3571Formally, 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
3574the swapped arguments to `pred`).
3575
3576These functions may be used for computing arbitrary extrema by choosing `pred`
3577appropriately. For corrrect functioning, `pred` must be a strict partial order,
3578i.e. transitive (if $(D pred(a, b) && pred(b, c)) then $(D pred(a, c))) and
3579irreflexive ($(D pred(a, a)) is `false`).
3580
3581Params:
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
3586Returns: The position of the minimum (respectively maximum) element of forward
3587range `range`, i.e. a subrange of `range` starting at the position of its
3588smallest (respectively largest) element and with the same ending as `range`.
3589
3590*/
3591Range minPos(alias pred = "a < b", Range)(Range range)
3592if (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
3627Range maxPos(alias pred = "a < b", Range)(Range range)
3628if (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/**
3684Computes the index of the first occurrence of `range`'s minimum element.
3685
3686Params:
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
3691Complexity: O(n)
3692 Exactly `n - 1` comparisons are needed.
3693
3694Returns:
3695 The index of the first encounter of the minimum element in `range`. If the
3696 `range` is empty, -1 is returned.
3697
3698See_Also:
3699 $(REF min, std,algorithm,comparison), $(LREF minCount), $(LREF minElement), $(LREF minPos)
3700 */
3701sizediff_t minIndex(alias pred = "a < b", Range)(Range range)
3702if (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/**
3803Computes the index of the first occurrence of `range`'s maximum element.
3804
3805Complexity: O(n)
3806 Exactly `n - 1` comparisons are needed.
3807
3808Params:
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
3812Returns:
3813 The index of the first encounter of the maximum in `range`. If the
3814 `range` is empty, -1 is returned.
3815
3816See_Also:
3817 $(REF max, std,algorithm,comparison), $(LREF maxCount), $(LREF maxElement), $(LREF maxPos)
3818 */
3819sizediff_t maxIndex(alias pred = "a < b", Range)(Range range)
3820if (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/**
3892Skip over the initial portion of the first given range that matches the second
3893range, or if no second range is given skip over the elements that fullfil pred.
3894Do nothing if there is no match.
3895
3896Params:
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
3904Returns:
3905true if the initial segment of $(D r1) matches $(D r2) or $(D pred) evaluates to true,
3906and $(D r1) has been advanced to the point past this segment; otherwise false, and
3907$(D r1) is left in its original position.
3908 */
3909bool skipOver(R1, R2)(ref R1 r1, R2 r2)
3910if (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
3931bool skipOver(alias pred, R1, R2)(ref R1 r1, R2 r2)
3932if (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
3954bool skipOver(alias pred, R)(ref R r1)
3955if (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/**
3996Skip over the first element of the given range if it matches the given element,
3997otherwise do nothing.
3998
3999Params:
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
4008Returns:
4009true if the first element matches the given element according to the given
4010predicate, and the range has been advanced by one element; otherwise false, and
4011the range is left untouched.
4012 */
4013bool skipOver(R, E)(ref R r, E e)
4014if (isInputRange!R && is(typeof(r.front == e) : bool))
4015{
4016 return skipOver!((a, b) => a == b)(r, e);
4017}
4018
4019/// Ditto
4020bool skipOver(alias pred, R, E)(ref R r, E e)
4021if (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/**
4051Checks whether the given
4052$(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one
4053of) the given needle(s) or, if no needles are given,
4054if its front element fulfils predicate $(D pred).
4055
4056Params:
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
4069Returns:
4070
40710 if the needle(s) do not occur at the beginning of the given range;
4072otherwise the position of the matching needle, that is, 1 if the range starts
4073with $(D withOneOfThese[0]), 2 if it starts with $(D withOneOfThese[1]), and so
4074on.
4075
4076In the case where $(D doesThisStart) starts with multiple of the ranges or
4077elements in $(D withOneOfThese), then the shortest one matches (if there are
4078two which match which are of the same length (e.g. $(D "a") and $(D 'a')), then
4079the left-most of them in the argument
4080list matches).
4081
4082In the case when no needle parameters are given, return $(D true) iff front of
4083$(D doesThisStart) fulfils predicate $(D pred).
4084 */
4085uint startsWith(alias pred = "a == b", Range, Needles...)(Range doesThisStart, Needles withOneOfThese)
4086if (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
4158bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis)
4159if (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
4227bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis)
4228if (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
4252bool startsWith(alias pred, R)(R doesThisStart)
4253if (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.)
4384Consume all elements from $(D r) that are equal to one of the elements
4385$(D es).
4386 */
4387private 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/**
4412Interval option specifier for `until` (below) and others.
4413
4414If set to $(D OpenRight.yes), then the interval is open to the right
4415(last element is not included).
4416
4417Otherwise if set to $(D OpenRight.no), then the interval is closed to the right
4418(last element included).
4419 */
4420alias OpenRight = Flag!"openRight";
4421
4422/**
4423Lazily iterates $(D range) _until the element $(D e) for which
4424$(D pred(e, sentinel)) is true.
4425
4426This is similar to `takeWhile` in other languages.
4427
4428Params:
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
4437Returns:
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 */
4444Until!(pred, Range, Sentinel)
4445until(alias pred = "a == b", Range, Sentinel)
4446(Range range, Sentinel sentinel, OpenRight openRight = Yes.openRight)
4447if (!is(Sentinel == OpenRight))
4448{
4449 return typeof(return)(range, sentinel, openRight);
4450}
4451
4452/// Ditto
4453Until!(pred, Range, void)
4454until(alias pred, Range)
4455(Range range, OpenRight openRight = Yes.openRight)
4456{
4457 return typeof(return)(range, openRight);
4458}
4459
4460/// ditto
4461struct Until(alias pred, Range, Sentinel)
4462if (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/**
3This is a submodule of $(MREF std, algorithm).
4It contains generic algorithms that implement set operations.
5
6The functions $(LREF multiwayMerge), $(LREF multiwayUnion), $(LREF setDifference),
7$(LREF setIntersection), $(LREF setSymmetricDifference) expect a range of sorted
8ranges as input.
9
10All algorithms are generalized to accept as input not only sets but also
11$(HTTP https://en.wikipedia.org/wiki/Multiset, multisets). Each algorithm
12documents 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
37Copyright: Andrei Alexandrescu 2008-.
38
39License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
40
41Authors: $(HTTP erdani.com, Andrei Alexandrescu)
42
43Source: $(PHOBOSSRC std/algorithm/_setops.d)
44
45Macros:
46T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
47 */
48module std.algorithm.setops;
49
50import std.range.primitives;
51
52// FIXME
53import std.functional; // : unaryFun, binaryFun;
54import std.traits;
55// FIXME
56import std.meta; // : AliasSeq, staticMap, allSatisfy, anySatisfy;
57
58import std.algorithm.sorting; // : Merge;
59import std.typecons : No;
60
61// cartesianProduct
62/**
63Lazily computes the Cartesian product of two or more ranges. The product is a
64_range of tuples of elements from each respective range.
65
66The conditions for the two-range case are as follows:
67
68If both ranges are finite, then one must be (at least) a
69$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and the
70other an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
71
72If one _range is infinite and the other finite, then the finite _range must
73be a forward _range, and the infinite range can be an input _range.
74
75If both ranges are infinite, then both must be forward ranges.
76
77When there are more than two ranges, the above conditions apply to each
78adjacent pair of ranges.
79
80Params:
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
86Returns:
87 A forward range of $(REF Tuple, std,typecons) representing elements of the
88 cartesian product of the given ranges.
89*/
90auto cartesianProduct(R1, R2)(R1 range1, R2 range2)
91if (!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
352pure nothrow @safe @nogc unittest
353{
354 int[1] a = [1];
355 foreach (t; cartesianProduct(a[], a[])) {}
356}
357
358/// ditto
359auto cartesianProduct(RR...)(RR ranges)
360if (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
456auto cartesianProduct(R1, R2, RR...)(R1 range1, R2 range2, RR otherRanges)
457if (!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
535pure @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/**
559Given 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
561of occurrences. All ranges in $(D ror) are assumed to be sorted by $(D
562less). Only the most frequent $(D tgt.length) elements are returned.
563
564Params:
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
570The function $(D largestPartialIntersection) is useful for
571e.g. searching an $(LINK2 https://en.wikipedia.org/wiki/Inverted_index,
572inverted index) for the documents most
573likely to contain some terms of interest. The complexity of the search
574is $(BIGOH n * log(tgt.length)), where $(D n) is the sum of lengths of
575all input ranges. This approach is faster than keeping an associative
576array of the occurrences and then selecting its top items, and also
577requires less memory ($(D largestPartialIntersection) builds its
578result directly in $(D tgt) and requires no extra memory).
579
580If at least one of the ranges is a multiset, then all occurences
581of a duplicate element are taken into account. The result is
582equivalent to merging all ranges and picking the most frequent
583$(D tgt.length) elements.
584
585Warning: Because $(D largestPartialIntersection) does not allocate
586extra memory, it will leave $(D ror) modified. Namely, $(D
587largestPartialIntersection) assumes ownership of $(D ror) and
588discretionarily swaps and advances elements of it. If you want $(D
589ror) to preserve its contents after the call, you may want to pass a
590duplicate to $(D largestPartialIntersection) (and perhaps cache the
591duplicate in between calls).
592 */
593void 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
651import std.algorithm.sorting : SortOutput; // FIXME
652
653// largestPartialIntersectionWeighted
654/**
655Similar to $(D largestPartialIntersection), but associates a weight
656with each distinct element in the intersection.
657
658If at least one of the ranges is a multiset, then all occurences
659of a duplicate element are taken into account. The result
660is equivalent to merging all input ranges and picking the highest
661$(D tgt.length), weight-based ranking elements.
662
663Params:
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*/
672void 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/**
798Merges multiple sets. The input sets are passed as a
799range of ranges and each is assumed to be sorted by $(D
800less). Computation is done lazily, one union element at a time. The
801complexity of one $(D popFront) operation is $(BIGOH
802log(ror.length)). However, the length of $(D ror) decreases as ranges
803in it are exhausted, so the complexity of a full pass through $(D
804MultiwayMerge) is dependent on the distribution of the lengths of ranges
805contained within $(D ror). If all ranges have the same length $(D n)
806(worst case scenario), the complexity of a full pass through $(D
807MultiwayMerge) is $(BIGOH n * ror.length * log(ror.length)), i.e., $(D
808log(ror.length)) times worse than just spanning all ranges in
809turn. The output comes sorted (unstably) by $(D less).
810
811The length of the resulting range is the sum of all lengths of
812the ranges passed as input. This means that all elements (duplicates
813included) are transferred to the resulting range.
814
815For backward compatibility, `multiwayMerge` is available under
816the name `nWayUnion` and `MultiwayMerge` under the name of `NWayUnion` .
817Future code should use `multiwayMerge` and `MultiwayMerge` as `nWayUnion`
818and `NWayUnion` will be deprecated.
819
820Params:
821 less = Predicate the given ranges are sorted by.
822 ror = A range of ranges sorted by `less` to compute the union for.
823
824Returns:
825 A range of the union of the ranges in `ror`.
826
827Warning: Because $(D MultiwayMerge) does not allocate extra memory, it
828will leave $(D ror) modified. Namely, $(D MultiwayMerge) assumes ownership
829of $(D ror) and discretionarily swaps and advances elements of it. If
830you want $(D ror) to preserve its contents after the call, you may
831want to pass a duplicate to $(D MultiwayMerge) (and perhaps cache the
832duplicate in between calls).
833 */
834struct 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
891MultiwayMerge!(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
929alias nWayUnion = multiwayMerge;
930alias NWayUnion = MultiwayMerge;
931
932/**
933Computes the union of multiple ranges. The input ranges are passed
934as a range of ranges and each is assumed to be sorted by $(D
935less). 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
940Params:
941 less = Predicate the given ranges are sorted by.
942 ror = A range of ranges sorted by `less` to compute the intersection for.
943
944Returns:
945 A range of the union of the ranges in `ror`.
946
947See also: $(LREF multiwayMerge)
948 */
949auto 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/**
986Lazily computes the difference of $(D r1) and $(D r2). The two ranges
987are assumed to be sorted by $(D less). The element types of the two
988ranges must have a common type.
989
990
991In the case of multisets, considering that element `a` appears `x`
992times in $(D r1) and `y` times and $(D r2), the number of occurences
993of `a` in the resulting range is going to be `x-y` if x > y or 0 othwerise.
994
995Params:
996 less = Predicate the given ranges are sorted by.
997 r1 = The first range.
998 r2 = The range to subtract from `r1`.
999
1000Returns:
1001 A range of the difference of `r1` and `r2`.
1002
1003See_also: $(LREF setSymmetricDifference)
1004 */
1005struct SetDifference(alias less = "a < b", R1, R2)
1006if (isInputRange!(R1) && isInputRange!(R2))
1007{
1008private:
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
1031public:
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
1072SetDifference!(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/**
1110Lazily computes the intersection of two or more input ranges $(D
1111ranges). The ranges are assumed to be sorted by $(D less). The element
1112types of the ranges must have a common type.
1113
1114In the case of multisets, the range with the minimum number of
1115occurences of a given element, propagates the number of
1116occurences of this element to the resulting range.
1117
1118Params:
1119 less = Predicate the given ranges are sorted by.
1120 ranges = The ranges to compute the intersection for.
1121
1122Returns:
1123 A range containing the intersection of the given ranges.
1124 */
1125struct SetIntersection(alias less = "a < b", Rs...)
1126if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) &&
1127 !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1128{
1129private:
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
1160public:
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
1219SetIntersection!(less, Rs) setIntersection(alias less = "a < b", Rs...)(Rs ranges)
1220if (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/**
1277Lazily computes the symmetric difference of $(D r1) and $(D r2),
1278i.e. the elements that are present in exactly one of $(D r1) and $(D
1279r2). The two ranges are assumed to be sorted by $(D less), and the
1280output is also sorted by $(D less). The element types of the two
1281ranges must have a common type.
1282
1283If both ranges are sets (without duplicated elements), the resulting
1284range is going to be a set. If at least one of the ranges is a multiset,
1285the number of occurences of an element `x` in the resulting range is `abs(a-b)`
1286where `a` is the number of occurences of `x` in $(D r1), `b` is the number of
1287occurences of `x` in $(D r2), and `abs` is the absolute value.
1288
1289If both arguments are ranges of L-values of the same type then
1290$(D SetSymmetricDifference) will also be a range of L-values of
1291that type.
1292
1293Params:
1294 less = Predicate the given ranges are sorted by.
1295 r1 = The first range.
1296 r2 = The second range.
1297
1298Returns:
1299 A range of the symmetric difference between `r1` and `r2`.
1300
1301See_also: $(LREF setDifference)
1302 */
1303struct SetSymmetricDifference(alias less = "a < b", R1, R2)
1304if (isInputRange!(R1) && isInputRange!(R2))
1305{
1306private:
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
1326public:
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
1387SetSymmetricDifference!(less, R1, R2)
1388setSymmetricDifference(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/++
1434TODO: once SetUnion got deprecated we can provide the usual definition
1435(= merge + filter after uniqs)
1436See: https://github.com/dlang/phobos/pull/4249
1437/**
1438Lazily computes the union of two or more ranges $(D rs). The ranges
1439are assumed to be sorted by $(D less). Elements in the output are
1440unique. The element types of all ranges must have a common type.
1441
1442Params:
1443 less = Predicate the given ranges are sorted by.
1444 rs = The ranges to compute the union for.
1445
1446Returns:
1447 A range containing the unique union of the given ranges.
1448
1449See_Also:
1450 $(REF merge, std,algorithm,sorting)
1451 */
1452auto 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/**
3This is a submodule of $(MREF std, algorithm).
4It 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
65Copyright: Andrei Alexandrescu 2008-.
66
67License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
68
69Authors: $(HTTP erdani.com, Andrei Alexandrescu)
70
71Source: $(PHOBOSSRC std/algorithm/_sorting.d)
72
73Macros:
74T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
75 */
76module std.algorithm.sorting;
77
78import std.algorithm.mutation : SwapStrategy;
79import std.functional; // : unaryFun, binaryFun;
80import std.range.primitives;
81import std.typecons : Flag;
82// FIXME
83import std.meta; // : allSatisfy;
84import std.range; // : SortedRange;
85import std.traits;
86
87/**
88Specifies whether the output of certain algorithm is desired in sorted
89format.
90
91If set to $(D SortOutput.no), the output should not be sorted.
92
93Otherwise if set to $(D SortOutput.yes), the output should be sorted.
94 */
95alias SortOutput = Flag!"sortOutput";
96
97// completeSort
98/**
99Sorts the random-access range $(D chain(lhs, rhs)) according to
100predicate $(D less). The left-hand side of the range $(D lhs) is
101assumed to be already sorted; $(D rhs) is assumed to be unsorted. The
102exact 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 +
105rhs.length)) (worst-case) evaluations of $(D swap).
106
107Params:
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*/
114void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
115 RandomAccessRange1, RandomAccessRange2)(SortedRange!(RandomAccessRange1, less) lhs, RandomAccessRange2 rhs)
116if (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/**
145Checks whether a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
146is sorted according to the comparison operation $(D less). Performs $(BIGOH r.length)
147evaluations of $(D less).
148
149Unlike `isSorted`, `isStrictlyMonotonic` does not allow for equal values,
150i.e. values for which both `less(a, b)` and `less(b, a)` are false.
151
152With either function, the predicate must be a strict ordering just like with
153`isSorted`. For example, using `"a <= b"` instead of `"a < b"` is
154incorrect and will cause failed assertions.
155
156Params:
157 less = Predicate the range should be sorted by.
158 r = Forward range to check for sortedness.
159
160Returns:
161 `true` if the range is sorted, false otherwise. `isSorted` allows
162 duplicates, `isStrictlyMonotonic` not.
163*/
164bool isSorted(alias less = "a < b", Range)(Range r)
165if (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
254bool isStrictlyMonotonic(alias less = "a < b", Range)(Range r)
255if (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/**
294Like $(D isSorted), returns $(D true) if the given $(D values) are ordered
295according to the comparison operation $(D less). Unlike $(D isSorted), takes values
296directly 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
299that the values are ordered strictly monotonically, use $(D strictlyOrdered);
300$(D strictlyOrdered(1, 1, 2)) is $(D false).
301
302With either function, the predicate must be a strict ordering. For example,
303using $(D "a <= b") instead of $(D "a < b") is incorrect and will cause failed
304assertions.
305
306Params:
307 values = The tested value
308 less = The comparison predicate
309
310Returns:
311 $(D true) if the values are ordered; $(D ordered) allows for duplicates,
312 $(D strictlyOrdered) does not.
313*/
314
315bool ordered(alias less = "a < b", T...)(T values)
316if ((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
335bool strictlyOrdered(alias less = "a < b", T...)(T values)
336if (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/**
369Partitions a range in two using the given $(D predicate).
370Specifically, reorders the range $(D r = [left, right$(RPAREN)) using $(D swap)
371such that all elements $(D i) for which $(D predicate(i)) is $(D true) come
372before all elements $(D j) for which $(D predicate(j)) returns $(D false).
373
374Performs $(BIGOH r.length) (if unstable or semistable) or $(BIGOH
375r.length * log(r.length)) (if stable) evaluations of $(D less) and $(D
376swap). The unstable version computes the minimum possible evaluations
377of $(D swap) (roughly half of those performed by the semistable
378version).
379
380Params:
381 predicate = The predicate to partition by.
382 ss = The swapping strategy to employ.
383 r = The random-access range to partition.
384
385Returns:
386
387The right part of $(D r) after partitioning.
388
389If $(D ss == SwapStrategy.stable), $(D partition) preserves the relative
390ordering of all elements $(D a), $(D b) in $(D r) for which $(D predicate(a) ==
391predicate(b)). If $(D ss == SwapStrategy.semistable), $(D partition) preserves
392the relative ordering of all elements $(D a), $(D b) in the left part of $(D r)
393for which $(D predicate(a) == predicate(b)).
394
395See_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*/
399Range partition(alias predicate, SwapStrategy ss, Range)(Range r)
400if (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
421Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)
422if (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
576Partitions `r` around `pivot` using comparison function `less`, algorithm akin
577to $(LINK2 https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme,
578Hoare partition). Specifically, permutes elements of `r` and returns
579an 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
587predicate `less`))
588
589$(LI All elements `e` in subrange $(D r[0 .. k]) satisfy $(D !less(e,
590r[k])) (i.e. `r[k]` is less than or equal to each element to its right
591according to predicate `less`)))
592
593If `r` contains equivalent elements, multiple permutations of `r` satisfy these
594constraints. In such cases, `pivotPartition` attempts to distribute equivalent
595elements fairly to the left and right of `k` such that `k` stays close to $(D
596r.length / 2).
597
598Params:
599less = 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)
603r = The range being partitioned
604pivot = The index of the pivot for partitioning, must be less than `r.length` or
605`0` is `r.length` is `0`
606
607Returns:
608The new position of the pivot
609
610See_Also:
611$(HTTP jgrcs.info/index.php/jgrcs/article/view/142, Engineering of a Quicksort
612Partitioning Algorithm), D. Abhyankar, Journal of Global Research in Computer
613Science, February 2011. $(HTTPS youtube.com/watch?v=AxnotgLql0k, ACCU 2016
614Keynote), Andrei Alexandrescu.
615*/
616size_t pivotPartition(alias less = "a < b", Range)
617(Range r, size_t pivot)
618if (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/**
773Params:
774 pred = The predicate that the range should be partitioned by.
775 r = The range to check.
776Returns: $(D true) if $(D r) is partitioned according to predicate $(D pred).
777 */
778bool isPartitioned(alias pred, Range)(Range r)
779if (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/**
802Rearranges elements in $(D r) in three adjacent ranges and returns
803them. The first and leftmost range only contains elements in $(D r)
804less than $(D pivot). The second and middle range only contains
805elements in $(D r) that are equal to $(D pivot). Finally, the third
806and rightmost range only contains elements in $(D r) that are greater
807than $(D pivot). The less-than test is defined by the binary function
808$(D less).
809
810Params:
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
816Returns:
817 A $(REF Tuple, std,typecons) of the three resulting ranges. These ranges are
818 slices of the original range.
819
820BUGS: stable $(D partition3) has not been implemented yet.
821 */
822auto partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E)
823(Range r, E pivot)
824if (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/**
919Computes an index for $(D r) based on the comparison $(D less). The
920index is a sorted array of pointers or indices into the original
921range. This technique is similar to sorting, but it is more flexible
922because (1) it allows "sorting" of immutable collections, (2) allows
923binary search even if the original collection does not offer random
924access, (3) allows multiple indexes, each on a different predicate,
925and (4) may be faster when dealing with large objects. However, using
926an index may also be slower under certain circumstances due to the
927extra indirection, and is always larger than a sorting-based solution
928because it needs space for the index in addition to the original
929collection. The complexity is the same as $(D sort)'s.
930
931The first overload of $(D makeIndex) writes to a range containing
932pointers, and the second writes to a range containing offsets. The
933first overload requires $(D Range) to be a
934$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives), and the
935latter requires it to be a random-access range.
936
937$(D makeIndex) overwrites its second argument with the result, but
938never reallocates it.
939
940Params:
941 less = The comparison to use.
942 ss = The swapping strategy.
943 r = The range to index.
944 index = The resulting index.
945
946Returns: The pointer-based version returns a $(D SortedRange) wrapper
947over index, of type $(D SortedRange!(RangeIndex, (a, b) =>
948binaryFun!less(*a, *b))) thus reflecting the ordering of the
949index. The index-based version returns $(D void) because the ordering
950relation involves not only $(D index) but also $(D r).
951
952Throws: If the second argument's length is less than that of the range
953indexed, an exception is thrown.
954*/
955SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))
956makeIndex(
957 alias less = "a < b",
958 SwapStrategy ss = SwapStrategy.unstable,
959 Range,
960 RangeIndex)
961(Range r, RangeIndex index)
962if (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
979void makeIndex(
980 alias less = "a < b",
981 SwapStrategy ss = SwapStrategy.unstable,
982 Range,
983 RangeIndex)
984(Range r, RangeIndex index)
985if (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
1075struct Merge(alias less = "a < b", Rs...)
1076if (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
1282Params:
1283 less = Predicate the given ranges are sorted by.
1284 rs = The ranges to compute the union for.
1285
1286Returns:
1287 A range containing the union of the given ranges.
1288
1289Details:
1290
1291All 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*/
1312Merge!(less, Rs) merge(alias less = "a < b", Rs...)(Rs rs)
1313if (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
1430private 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
1446Sorts 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,
1448and sorts elements that have the same $(D id) by $(D date)
1449descending. 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
1451does fewer comparisons (in addition to being more convenient).
1452
1453Returns:
1454 The initial range wrapped as a $(D SortedRange) with its predicates
1455 converted to an equivalent single predicate.
1456 */
1457template 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
1488private 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
1499private 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
1603private 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/*
1624Sorting routine that is optimized for short ranges. Note: uses insertion sort
1625going downward. Benchmarked a similar routine that goes upward, for some reason
1626it's slower.
1627*/
1628private 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/*
1733Sorts the first 5 elements exactly of range r.
1734*/
1735private 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/**
1802Sorts 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
1804expensive computations on the _sort key, it may be worthwhile to use
1805$(LREF schwartzSort) instead.
1806
1807Stable sorting requires $(D hasAssignableElements!Range) to be true.
1808
1809$(D sort) returns a $(REF SortedRange, std,range) over the original range,
1810allowing functions that can take advantage of sorted data to know that the
1811range is sorted and adjust accordingly. The $(REF SortedRange, std,range) is a
1812wrapper around the original range, so both it and the original range are sorted.
1813Other functions can't know that the original range has been sorted, but
1814they $(I can) know that $(REF SortedRange, std,range) has been sorted.
1815
1816Preconditions:
1817
1818The predicate is expected to satisfy certain rules in order for $(D sort) to
1819behave as expected - otherwise, the program may fail on certain inputs (but not
1820others) when not compiled in release mode, due to the cursory $(D assumeSorted)
1821check. 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
1823imply $(D !less(a,c)). Note that the default predicate ($(D "a < b")) does not
1824always satisfy these conditions for floating point types, because the expression
1825will always be $(D false) when either $(D a) or $(D b) is NaN.
1826Use $(REF cmp, std,math) instead.
1827
1828Params:
1829 less = The predicate to sort by.
1830 ss = The swapping strategy to use.
1831 r = The range to sort.
1832
1833Returns: The initial range wrapped as a $(D SortedRange) with the predicate
1834$(D binaryFun!less).
1835
1836Algorithms: $(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.
1838Each algorithm has benefits beyond stability. Introsort is generally faster but
1839Timsort may achieve greater speeds on data with low entropy or if predicate calls
1840are expensive. Introsort performs no allocations whereas Timsort will perform one
1841or more allocations per call. Both algorithms have $(BIGOH n log n) worst-case
1842time complexity.
1843
1844See_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*/
1850SortedRange!(Range, less)
1851sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
1852 Range)(Range r)
1853if (((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
2055private 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
2113package(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
2230private 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/**
2860Alternative sorting method that should be used when comparing keys involves an
2861expensive 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
2864repeatedly computing it. Conversely, if the cost of `transform` is small
2865compared to the cost of allocating and filling the precomputed array, `sort`
2866may be faster and therefore preferable.
2867
2868This approach to sorting is akin to the $(HTTP
2869wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform), also known as
2870the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the
2871same as that of the corresponding `sort`, but `schwartzSort` evaluates
2872`transform` only `r.length` times (less than half when compared to regular
2873sorting). The usage can be best illustrated with an example.
2874
2875Example:
2876----
2877uint hashFun(string) { ... expensive computation ... }
2878string[] array = ...;
2879// Sort strings by hash, slow
2880sort!((a, b) => hashFun(a) < hashFun(b))(array);
2881// Sort strings by hash, fast (only computes arr.length hashes):
2882schwartzSort!(hashFun, "a < b")(array);
2883----
2884
2885The $(D schwartzSort) function might require less temporary data and
2886be faster than the Perl idiom or the decorate-sort-undecorate idiom
2887present in Python and Lisp. This is because sorting is done in-place
2888and only minimal extra data (one array of transformed elements) is
2889created.
2890
2891To check whether an array was sorted and benefit of the speedup of
2892Schwartz sorting, a function $(D schwartzIsSorted) is not provided
2893because the effect can be achieved by calling $(D
2894isSorted!less(map!transform(r))).
2895
2896Params:
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
2902Returns: The initial range wrapped as a $(D SortedRange) with the
2903predicate $(D (a, b) => binaryFun!less(transform(a),
2904transform(b))).
2905 */
2906SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a),
2907 unaryFun!transform(b))))
2908schwartzSort(alias transform, alias less = "a < b",
2909 SwapStrategy ss = SwapStrategy.unstable, R)(R r)
2910if (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/**
3021Reorders 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
3023the range $(D r[mid .. r.length]) in no particular order. Performs
3024$(BIGOH r.length * log(mid)) evaluations of $(D pred). The
3025implementation simply calls $(D topN!(less, ss)(r, n)) and then $(D
3026sort!(less, ss)(r[0 .. n])).
3027
3028Params:
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*/
3034void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3035 Range)(Range r, size_t n)
3036if (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/**
3050Stores the smallest elements of the two ranges in the left-hand range in sorted order.
3051
3052Params:
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
3059void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3060 Range1, Range2)(Range1 r1, Range2 r2)
3061if (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/**
3080Reorders the range $(D r) using $(D swap) such that $(D r[nth]) refers
3081to the element that would fall there if the range were fully
3082sorted. 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)),
3084and 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
3090If $(D n >= r.length), the algorithm has no effect and returns
3091`r[0 .. r.length]`.
3092
3093Params:
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
3100See_Also:
3101 $(LREF topNIndex),
3102 $(HTTP sgi.com/tech/stl/nth_element.html, STL's nth_element)
3103
3104BUGS:
3105
3106Stable topN has not been implemented yet.
3107*/
3108auto topN(alias less = "a < b",
3109 SwapStrategy ss = SwapStrategy.unstable,
3110 Range)(Range r, size_t nth)
3111if (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
3133private @trusted
3134void 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
3244private 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
3271private 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
3283private 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
3299private 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/*
3326Params:
3327less = predicate
3328r = range to partition
3329pivot = pivot to partition around
3330lo = value such that r[lo .. pivot] already less than r[pivot]
3331hi = value such that r[pivot .. hi] already greater than r[pivot]
3332
3333Returns: new position of pivot
3334*/
3335private
3336size_t expandPartition(alias lp, R)(R r, size_t lo, size_t pivot, size_t hi)
3337in
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 }
3346out
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}
3352body
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
3435done:
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
3450version (unittest)
3451private 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