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