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 `if (v.among(1, 2, 3)) // `v` is 1, 2 or 3`) 12 $(T2 castSwitch, 13 `(new A()).castSwitch((A a)=>1,(B b)=>2)` returns `1`.) 14 $(T2 clamp, 15 `clamp(1, 3, 6)` returns `3`. `clamp(4, 3, 6)` returns `4`.) 16 $(T2 cmp, 17 `cmp("abc", "abcd")` is `-1`, `cmp("abc", "aba")` is `1`, 18 and `cmp("abc", "abc")` is `0`.) 19 $(T2 either, 20 Return first parameter `p` that passes an `if (p)` test, e.g. 21 `either(0, 42, 43)` returns `42`.) 22 $(T2 equal, 23 Compares ranges for element-by-element equality, e.g. 24 `equal([1, 2, 3], [1.0, 2.0, 3.0])` returns `true`.) 25 $(T2 isPermutation, 26 `isPermutation([1, 2], [2, 1])` returns `true`.) 27 $(T2 isSameLength, 28 `isSameLength([1, 2, 3], [4, 5, 6])` returns `true`.) 29 $(T2 levenshteinDistance, 30 `levenshteinDistance("kitten", "sitting")` returns `3` by using 31 the $(LINK2 https://en.wikipedia.org/wiki/Levenshtein_distance, 32 Levenshtein distance algorithm).) 33 $(T2 levenshteinDistanceAndPath, 34 `levenshteinDistanceAndPath("kitten", "sitting")` returns 35 `tuple(3, "snnnsni")` by using the 36 $(LINK2 https://en.wikipedia.org/wiki/Levenshtein_distance, 37 Levenshtein distance algorithm).) 38 $(T2 max, 39 `max(3, 4, 2)` returns `4`.) 40 $(T2 min, 41 `min(3, 4, 2)` returns `2`.) 42 $(T2 mismatch, 43 `mismatch("oh hi", "ohayo")` returns `tuple(" hi", "ayo")`.) 44 $(T2 predSwitch, 45 `2.predSwitch(1, "one", 2, "two", 3, "three")` returns `"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 import std.functional : unaryFun, binaryFun, lessThan, greaterThan; 62 import std.range.primitives; 63 import std.traits; 64 import std.meta : allSatisfy, anySatisfy; 65 import std.typecons : tuple, Tuple, Flag, Yes; 66 67 import std.internal.attributes : betterC; 68 69 /** 70 Find `value` _among `values`, returning the 1-based index 71 of the first matching value in `values`, or `0` if `value` 72 is not _among `values`. The predicate `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 $(UL 86 $(LI $(REF_SHORT find, std,algorithm,searching) and 87 $(REF_SHORT canFind, std,algorithm,searching) for finding a value in a range.) 88 $(LI $(REF_ALTTEXT `value in iota(start, end)`, iota, std,range) to find a value in 89 a particular interval.) 90 ) 91 */ 92 uint among(alias pred = (a, b) => a == b, Value, Values...) 93 (Value value, Values values) 94 if (Values.length != 0) 95 { 96 foreach (uint i, ref v; values) 97 { 98 import std.functional : binaryFun; 99 if (binaryFun!pred(value, v)) return i + 1; 100 } 101 return 0; 102 } 103 104 /// Ditto 105 template among(values...) 106 if (isExpressionTuple!values) 107 { 108 uint among(Value)(Value value) 109 if (!is(CommonType!(Value, values) == void)) 110 { 111 switch (value) 112 { 113 foreach (uint i, v; values) 114 case v: 115 return i + 1; 116 default: 117 return 0; 118 } 119 } 120 } 121 122 /// 123 @safe @nogc @betterC unittest 124 { 125 assert(3.among(1, 42, 24, 3, 2)); 126 127 if (auto pos = "bar".among("foo", "bar", "baz")) 128 assert(pos == 2); 129 else 130 assert(false); 131 132 // 42 is larger than 24 133 assert(42.among!((lhs, rhs) => lhs > rhs)(43, 24, 100) == 2); 134 } 135 136 /** 137 Alternatively, `values` can be passed at compile-time, allowing for a more 138 efficient search, but one that only supports matching on equality: 139 */ 140 @safe @nogc @betterC unittest 141 { 142 assert(3.among!(2, 3, 4)); 143 assert("bar".among!("foo", "bar", "baz") == 2); 144 } 145 146 @safe unittest 147 { 148 import std.meta : AliasSeq; 149 150 if (auto pos = 3.among(1, 2, 3)) 151 assert(pos == 3); 152 else 153 assert(false); 154 assert(!4.among(1, 2, 3)); 155 156 auto position = "hello".among("hello", "world"); 157 assert(position); 158 assert(position == 1); 159 160 alias values = AliasSeq!("foo", "bar", "baz"); 161 auto arr = [values]; 162 assert(arr[0 .. "foo".among(values)] == ["foo"]); 163 assert(arr[0 .. "bar".among(values)] == ["foo", "bar"]); 164 assert(arr[0 .. "baz".among(values)] == arr); 165 assert("foobar".among(values) == 0); 166 167 if (auto pos = 3.among!(1, 2, 3)) 168 assert(pos == 3); 169 else 170 assert(false); 171 assert(!4.among!(1, 2, 3)); 172 173 position = "hello".among!("hello", "world"); 174 assert(position); 175 assert(position == 1); 176 177 static assert(!__traits(compiles, "a".among!("a", 42))); 178 static assert(!__traits(compiles, (Object.init).among!(42, "a"))); 179 } 180 181 // Used in castSwitch to find the first choice that overshadows the last choice 182 // in a tuple. 183 private template indexOfFirstOvershadowingChoiceOnLast(choices...) 184 { 185 alias firstParameterTypes = Parameters!(choices[0]); 186 alias lastParameterTypes = Parameters!(choices[$ - 1]); 187 188 static if (lastParameterTypes.length == 0) 189 { 190 // If the last is null-typed choice, check if the first is null-typed. 191 enum isOvershadowing = firstParameterTypes.length == 0; 192 } 193 else static if (firstParameterTypes.length == 1) 194 { 195 // If the both first and last are not null-typed, check for overshadowing. 196 enum isOvershadowing = 197 is(firstParameterTypes[0] == Object) // Object overshadows all other classes!(this is needed for interfaces) 198 || is(lastParameterTypes[0] : firstParameterTypes[0]); 199 } 200 else 201 { 202 // If the first is null typed and the last is not - the is no overshadowing. 203 enum isOvershadowing = false; 204 } 205 206 static if (isOvershadowing) 207 { 208 enum indexOfFirstOvershadowingChoiceOnLast = 0; 209 } 210 else 211 { 212 enum indexOfFirstOvershadowingChoiceOnLast = 213 1 + indexOfFirstOvershadowingChoiceOnLast!(choices[1..$]); 214 } 215 } 216 217 /** 218 Executes and returns one of a collection of handlers based on the type of the 219 switch object. 220 221 The first choice that `switchObject` can be casted to the type 222 of argument it accepts will be called with `switchObject` casted to that 223 type, and the value it'll return will be returned by `castSwitch`. 224 225 If a choice's return type is void, the choice must throw an exception, unless 226 all the choices are void. In that case, castSwitch itself will return void. 227 228 Throws: If none of the choice matches, a `SwitchError` will be thrown. $(D 229 SwitchError) will also be thrown if not all the choices are void and a void 230 choice was executed without throwing anything. 231 232 Params: 233 choices = The `choices` needs to be composed of function or delegate 234 handlers that accept one argument. There can also be a choice that 235 accepts zero arguments. That choice will be invoked if the $(D 236 switchObject) is null. 237 switchObject = the object against which the tests are being made. 238 239 Returns: 240 The value of the selected choice. 241 242 Note: `castSwitch` can only be used with object types. 243 */ 244 auto castSwitch(choices...)(Object switchObject) 245 { 246 import core.exception : SwitchError; 247 import std.format : format; 248 249 // Check to see if all handlers return void. 250 enum areAllHandlersVoidResult = { 251 bool result = true; 252 foreach (index, choice; choices) 253 { 254 result &= is(ReturnType!choice : void); // void or noreturn 255 } 256 return result; 257 }(); 258 259 if (switchObject !is null) 260 { 261 // Checking for exact matches: 262 const classInfo = typeid(switchObject); 263 foreach (index, choice; choices) 264 { 265 static assert(isCallable!choice, 266 "A choice handler must be callable"); 267 268 alias choiceParameterTypes = Parameters!choice; 269 static assert(choiceParameterTypes.length <= 1, 270 "A choice handler can not have more than one argument."); 271 272 static if (choiceParameterTypes.length == 1) 273 { 274 alias CastClass = choiceParameterTypes[0]; 275 static assert(is(CastClass == class) || is(CastClass == interface), 276 "A choice handler can have only class or interface typed argument."); 277 278 // Check for overshadowing: 279 immutable indexOfOvershadowingChoice = 280 indexOfFirstOvershadowingChoiceOnLast!(choices[0 .. index + 1]); 281 static assert(indexOfOvershadowingChoice == index, 282 "choice number %d(type %s) is overshadowed by choice number %d(type %s)".format( 283 index + 1, CastClass.stringof, indexOfOvershadowingChoice + 1, 284 Parameters!(choices[indexOfOvershadowingChoice])[0].stringof)); 285 286 if (classInfo == typeid(CastClass)) 287 { 288 static if (is(ReturnType!(choice) == void)) 289 { 290 choice(cast(CastClass) switchObject); 291 static if (areAllHandlersVoidResult) 292 { 293 return; 294 } 295 else 296 { 297 throw new SwitchError("Handlers that return void should throw"); 298 } 299 } 300 else 301 { 302 return choice(cast(CastClass) switchObject); 303 } 304 } 305 } 306 } 307 308 // Checking for derived matches: 309 foreach (choice; choices) 310 { 311 alias choiceParameterTypes = Parameters!choice; 312 static if (choiceParameterTypes.length == 1) 313 { 314 if (auto castedObject = cast(choiceParameterTypes[0]) switchObject) 315 { 316 static if (is(ReturnType!(choice) == void)) 317 { 318 choice(castedObject); 319 static if (areAllHandlersVoidResult) 320 { 321 return; 322 } 323 else 324 { 325 throw new SwitchError("Handlers that return void should throw"); 326 } 327 } 328 else 329 { 330 return choice(castedObject); 331 } 332 } 333 } 334 } 335 } 336 else // If switchObject is null: 337 { 338 // Checking for null matches: 339 foreach (index, choice; choices) 340 { 341 static if (Parameters!(choice).length == 0) 342 { 343 immutable indexOfOvershadowingChoice = 344 indexOfFirstOvershadowingChoiceOnLast!(choices[0 .. index + 1]); 345 346 // Check for overshadowing: 347 static assert(indexOfOvershadowingChoice == index, 348 "choice number %d(null reference) is overshadowed by choice number %d(null reference)".format( 349 index + 1, indexOfOvershadowingChoice + 1)); 350 351 if (switchObject is null) 352 { 353 static if (is(ReturnType!(choice) == void)) 354 { 355 choice(); 356 static if (areAllHandlersVoidResult) 357 { 358 return; 359 } 360 else 361 { 362 throw new SwitchError("Handlers that return void should throw"); 363 } 364 } 365 else 366 { 367 return choice(); 368 } 369 } 370 } 371 } 372 } 373 374 // In case nothing matched: 375 throw new SwitchError("Input not matched by any choice"); 376 } 377 378 /// 379 @system unittest 380 { 381 import std.algorithm.iteration : map; 382 import std.format : format; 383 384 class A 385 { 386 int a; 387 this(int a) {this.a = a;} 388 @property int i() { return a; } 389 } 390 interface I { } 391 class B : I { } 392 393 Object[] arr = [new A(1), new B(), null]; 394 395 auto results = arr.map!(castSwitch!( 396 (A a) => "A with a value of %d".format(a.a), 397 (I i) => "derived from I", 398 () => "null reference", 399 ))(); 400 401 // A is handled directly: 402 assert(results[0] == "A with a value of 1"); 403 // B has no handler - it is handled by the handler of I: 404 assert(results[1] == "derived from I"); 405 // null is handled by the null handler: 406 assert(results[2] == "null reference"); 407 } 408 409 /// Using with void handlers: 410 @system unittest 411 { 412 import std.exception : assertThrown; 413 414 class A { } 415 class B { } 416 // Void handlers are allowed if they throw: 417 assertThrown!Exception( 418 new B().castSwitch!( 419 (A a) => 1, 420 (B d) { throw new Exception("B is not allowed!"); } 421 )() 422 ); 423 424 // Void handlers are also allowed if all the handlers are void: 425 new A().castSwitch!( 426 (A a) { }, 427 (B b) { assert(false); }, 428 )(); 429 } 430 431 @system unittest 432 { 433 import core.exception : SwitchError; 434 import std.exception : assertThrown; 435 436 interface I { } 437 class A : I { } 438 class B { } 439 440 // Nothing matches: 441 assertThrown!SwitchError((new A()).castSwitch!( 442 (B b) => 1, 443 () => 2, 444 )()); 445 446 // Choices with multiple arguments are not allowed: 447 static assert(!__traits(compiles, 448 (new A()).castSwitch!( 449 (A a, B b) => 0, 450 )())); 451 452 // Only callable handlers allowed: 453 static assert(!__traits(compiles, 454 (new A()).castSwitch!( 455 1234, 456 )())); 457 458 // Only object arguments allowed: 459 static assert(!__traits(compiles, 460 (new A()).castSwitch!( 461 (int x) => 0, 462 )())); 463 464 // Object overshadows regular classes: 465 static assert(!__traits(compiles, 466 (new A()).castSwitch!( 467 (Object o) => 0, 468 (A a) => 1, 469 )())); 470 471 // Object overshadows interfaces: 472 static assert(!__traits(compiles, 473 (new A()).castSwitch!( 474 (Object o) => 0, 475 (I i) => 1, 476 )())); 477 478 // No multiple null handlers allowed: 479 static assert(!__traits(compiles, 480 (new A()).castSwitch!( 481 () => 0, 482 () => 1, 483 )())); 484 485 // No non-throwing void handlers allowed(when there are non-void handlers): 486 assertThrown!SwitchError((new A()).castSwitch!( 487 (A a) {}, 488 (B b) => 2, 489 )()); 490 491 // All-void handlers work for the null case: 492 null.castSwitch!( 493 (Object o) { assert(false); }, 494 () { }, 495 )(); 496 497 // Throwing void handlers work for the null case: 498 assertThrown!Exception(null.castSwitch!( 499 (Object o) => 1, 500 () { throw new Exception("null"); }, 501 )()); 502 } 503 504 @system unittest 505 { 506 interface I { } 507 class B : I { } 508 class C : I { } 509 510 assert((new B()).castSwitch!( 511 (B b) => "class B", 512 (I i) => "derived from I", 513 ) == "class B"); 514 515 assert((new C()).castSwitch!( 516 (B b) => "class B", 517 (I i) => "derived from I", 518 ) == "derived from I"); 519 } 520 521 // https://issues.dlang.org/show_bug.cgi?id=22384 522 @system unittest 523 { 524 // Use explicit methods to enforce return types 525 static void objectSkip(Object) {} 526 static void defaultSkip() {} 527 528 static noreturn objectError(Object) { assert(false); } 529 static noreturn defaultError() { assert(false); } 530 531 { 532 alias test = castSwitch!(objectSkip, defaultError); 533 static assert(is(ReturnType!test == void)); 534 }{ 535 alias test = castSwitch!(objectError, defaultSkip); 536 static assert(is(ReturnType!test == void)); 537 }{ 538 alias test = castSwitch!(objectError, defaultError); 539 static assert(is(ReturnType!test == noreturn)); 540 } 541 542 // Also works with non-void handlers 543 static int objectValue(Object) { return 1;} 544 static int defaultValue() { return 2; } 545 546 { 547 alias test = castSwitch!(objectValue, defaultError); 548 static assert(is(ReturnType!test == int)); 549 }{ 550 alias test = castSwitch!(objectError, defaultValue); 551 static assert(is(ReturnType!test == int)); 552 } 553 554 // No confusion w.r.t. void callbacks 555 alias FP = void function(); 556 static FP objectFunc(Object) { return &defaultSkip; } 557 static FP defaultFunc() { return &defaultSkip; } 558 559 { 560 alias test = castSwitch!(objectFunc, defaultError); 561 static assert(is(ReturnType!test == FP)); 562 }{ 563 alias test = castSwitch!(objectError, defaultFunc); 564 static assert(is(ReturnType!test == FP)); 565 } 566 } 567 568 /** Clamps `val` into the given bounds. Result has the same type as `val`. 569 570 Params: 571 val = The value to _clamp. 572 lower = The _lower bound of the _clamp. 573 upper = The _upper bound of the _clamp. 574 575 Returns: 576 `lower` if `val` is less than `lower`, `upper` if `val` is greater than 577 `upper`, and `val` in all other cases. Comparisons are made 578 correctly (using $(REF lessThan, std,functional) and the return value 579 is converted to the return type using the standard integer coversion rules 580 $(REF greaterThan, std,functional)) even if the signedness of `T1`, `T2`, 581 and `T3` are different. 582 */ 583 T1 clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper) 584 { 585 static assert(is(T2 : T1), "T2 of type '", T2.stringof 586 , "' must be implicitly convertible to type of T1 '" 587 , T1.stringof, "'"); 588 static assert(is(T3 : T1), "T3 of type '", T3.stringof 589 , "' must be implicitly convertible to type of T1 '" 590 , T1.stringof, "'"); 591 592 assert(!lower.greaterThan(upper), "Lower can't be greater than upper."); 593 594 // `if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1)) 595 // because of https://issues.dlang.org/show_bug.cgi?id=16235. 596 // Once that is fixed, we can simply use the ternary in both the template constraint 597 // and the template body 598 if (val.lessThan(lower)) 599 return lower; 600 else if (val.greaterThan(upper)) 601 return upper; 602 return val; 603 } 604 605 /// 606 @safe @nogc @betterC unittest 607 { 608 assert(clamp(2, 1, 3) == 2); 609 assert(clamp(0, 1, 3) == 1); 610 assert(clamp(4, 1, 3) == 3); 611 612 assert(clamp(1, 1, 1) == 1); 613 614 assert(clamp(5, -1, 2u) == 2); 615 616 auto x = clamp(42, uint.max, uint.max); 617 static assert(is(typeof(x) == int)); 618 assert(x == -1); 619 } 620 621 @safe unittest 622 { 623 int a = 1; 624 short b = 6; 625 double c = 2; 626 static assert(is(typeof(clamp(c,a,b)) == double)); 627 assert(clamp(c, a, b) == c); 628 assert(clamp(a-c, a, b) == a); 629 assert(clamp(b+c, a, b) == b); 630 // mixed sign 631 a = -5; 632 uint f = 5; 633 static assert(is(typeof(clamp(f, a, b)) == uint)); 634 assert(clamp(f, a, b) == f); 635 // similar type deduction for (u)long 636 static assert(is(typeof(clamp(-1L, -2L, 2UL)) == long)); 637 638 // user-defined types 639 import std.datetime : Date; 640 assert(clamp(Date(1982, 1, 4), Date(1012, 12, 21), Date(2012, 12, 21)) == Date(1982, 1, 4)); 641 assert(clamp(Date(1982, 1, 4), Date.min, Date.max) == Date(1982, 1, 4)); 642 // UFCS style 643 assert(Date(1982, 1, 4).clamp(Date.min, Date.max) == Date(1982, 1, 4)); 644 645 // Stability 646 struct A { 647 int x, y; 648 int opCmp(ref const A rhs) const { return (x > rhs.x) - (x < rhs.x); } 649 } 650 A x, lo, hi; 651 x.y = 42; 652 assert(x.clamp(lo, hi).y == 42); 653 } 654 655 // https://issues.dlang.org/show_bug.cgi?id=23268 656 @safe pure nothrow @nogc unittest 657 { 658 static assert(__traits(compiles, clamp(short.init, short.init, cast(const) short.init))); 659 } 660 661 // cmp 662 /********************************** 663 Performs a lexicographical comparison on two 664 $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives). 665 Iterating `r1` and `r2` in lockstep, `cmp` compares each element 666 `e1` of `r1` with the corresponding element `e2` in `r2`. If one 667 of the ranges has been finished, `cmp` returns a negative value 668 if `r1` has fewer elements than `r2`, a positive value if `r1` 669 has more elements than `r2`, and `0` if the ranges have the same 670 number of elements. 671 672 If the ranges are strings, `cmp` performs UTF decoding 673 appropriately and compares the ranges one code point at a time. 674 675 A custom predicate may be specified, in which case `cmp` performs 676 a three-way lexicographical comparison using `pred`. Otherwise 677 the elements are compared using `opCmp`. 678 679 Params: 680 pred = Predicate used for comparison. Without a predicate 681 specified the ordering implied by `opCmp` is used. 682 r1 = The first range. 683 r2 = The second range. 684 685 Returns: 686 `0` if the ranges compare equal. A negative value if `r1` is a prefix of `r2` or 687 the first differing element of `r1` is less than the corresponding element of `r2` 688 according to `pred`. A positive value if `r2` is a prefix of `r1` or the first 689 differing element of `r2` is less than the corresponding element of `r1` 690 according to `pred`. 691 692 Note: 693 An earlier version of the documentation incorrectly stated that `-1` is the 694 only negative value returned and `1` is the only positive value returned. 695 Whether that is true depends on the types being compared. 696 */ 697 auto cmp(R1, R2)(R1 r1, R2 r2) 698 if (isInputRange!R1 && isInputRange!R2) 699 { 700 alias E1 = ElementEncodingType!R1; 701 alias E2 = ElementEncodingType!R2; 702 703 static if (isDynamicArray!R1 && isDynamicArray!R2 704 && __traits(isUnsigned, E1) && __traits(isUnsigned, E2) 705 && E1.sizeof == 1 && E2.sizeof == 1 706 // Both or neither must auto-decode. 707 && (is(immutable E1 == immutable char) == is(immutable E2 == immutable char))) 708 { 709 // dstrcmp algorithm is correct for both ubyte[] and for char[]. 710 import core.internal.string : dstrcmp; 711 return dstrcmp(cast(const char[]) r1, cast(const char[]) r2); 712 } 713 else static if (!(isSomeString!R1 && isSomeString!R2)) 714 { 715 for (;; r1.popFront(), r2.popFront()) 716 { 717 static if (is(typeof(r1.front.opCmp(r2.front)) R)) 718 alias Result = R; 719 else 720 alias Result = int; 721 if (r2.empty) return Result(!r1.empty); 722 if (r1.empty) return Result(-1); 723 static if (is(typeof(r1.front.opCmp(r2.front)))) 724 { 725 auto c = r1.front.opCmp(r2.front); 726 if (c != 0) return c; 727 } 728 else 729 { 730 auto a = r1.front, b = r2.front; 731 if (auto result = (b < a) - (a < b)) return result; 732 } 733 } 734 } 735 else 736 { 737 static if (typeof(r1[0]).sizeof == typeof(r2[0]).sizeof) 738 { 739 return () @trusted 740 { 741 auto p1 = r1.ptr, p2 = r2.ptr, 742 pEnd = p1 + min(r1.length, r2.length); 743 for (; p1 != pEnd; ++p1, ++p2) 744 { 745 if (*p1 != *p2) return cast(int) *p1 - cast(int) *p2; 746 } 747 static if (typeof(r1[0]).sizeof >= 2 && size_t.sizeof <= uint.sizeof) 748 return cast(int) r1.length - cast(int) r2.length; 749 else 750 return int(r1.length > r2.length) - int(r1.length < r2.length); 751 }(); 752 } 753 else 754 { 755 import std.utf : decode; 756 757 for (size_t i1, i2;;) 758 { 759 if (i1 == r1.length) return -int(i2 < r2.length); 760 if (i2 == r2.length) return int(1); 761 immutable c1 = decode(r1, i1), 762 c2 = decode(r2, i2); 763 if (c1 != c2) return cast(int) c1 - cast(int) c2; 764 } 765 } 766 } 767 } 768 769 /// ditto 770 int cmp(alias pred, R1, R2)(R1 r1, R2 r2) 771 if (isInputRange!R1 && isInputRange!R2) 772 { 773 static if (!(isSomeString!R1 && isSomeString!R2)) 774 { 775 for (;; r1.popFront(), r2.popFront()) 776 { 777 if (r2.empty) return !r1.empty; 778 if (r1.empty) return -1; 779 auto a = r1.front, b = r2.front; 780 if (binaryFun!pred(a, b)) return -1; 781 if (binaryFun!pred(b, a)) return 1; 782 } 783 } 784 else 785 { 786 import std.utf : decode; 787 788 for (size_t i1, i2;;) 789 { 790 if (i1 == r1.length) return -int(i2 < r2.length); 791 if (i2 == r2.length) return 1; 792 immutable c1 = decode(r1, i1), 793 c2 = decode(r2, i2); 794 if (c1 != c2) 795 { 796 if (binaryFun!pred(c2, c1)) return 1; 797 if (binaryFun!pred(c1, c2)) return -1; 798 } 799 } 800 } 801 } 802 803 /// 804 pure @safe unittest 805 { 806 int result; 807 808 result = cmp("abc", "abc"); 809 assert(result == 0); 810 result = cmp("", ""); 811 assert(result == 0); 812 result = cmp("abc", "abcd"); 813 assert(result < 0); 814 result = cmp("abcd", "abc"); 815 assert(result > 0); 816 result = cmp("abc"d, "abd"); 817 assert(result < 0); 818 result = cmp("bbc", "abc"w); 819 assert(result > 0); 820 result = cmp("aaa", "aaaa"d); 821 assert(result < 0); 822 result = cmp("aaaa", "aaa"d); 823 assert(result > 0); 824 result = cmp("aaa", "aaa"d); 825 assert(result == 0); 826 result = cmp("aaa"d, "aaa"d); 827 assert(result == 0); 828 result = cmp(cast(int[])[], cast(int[])[]); 829 assert(result == 0); 830 result = cmp([1, 2, 3], [1, 2, 3]); 831 assert(result == 0); 832 result = cmp([1, 3, 2], [1, 2, 3]); 833 assert(result > 0); 834 result = cmp([1, 2, 3], [1L, 2, 3, 4]); 835 assert(result < 0); 836 result = cmp([1L, 2, 3], [1, 2]); 837 assert(result > 0); 838 } 839 840 /// Example predicate that compares individual elements in reverse lexical order 841 pure @safe unittest 842 { 843 int result; 844 845 result = cmp!"a > b"("abc", "abc"); 846 assert(result == 0); 847 result = cmp!"a > b"("", ""); 848 assert(result == 0); 849 result = cmp!"a > b"("abc", "abcd"); 850 assert(result < 0); 851 result = cmp!"a > b"("abcd", "abc"); 852 assert(result > 0); 853 result = cmp!"a > b"("abc"d, "abd"); 854 assert(result > 0); 855 result = cmp!"a > b"("bbc", "abc"w); 856 assert(result < 0); 857 result = cmp!"a > b"("aaa", "aaaa"d); 858 assert(result < 0); 859 result = cmp!"a > b"("aaaa", "aaa"d); 860 assert(result > 0); 861 result = cmp!"a > b"("aaa", "aaa"d); 862 assert(result == 0); 863 result = cmp("aaa"d, "aaa"d); 864 assert(result == 0); 865 result = cmp!"a > b"(cast(int[])[], cast(int[])[]); 866 assert(result == 0); 867 result = cmp!"a > b"([1, 2, 3], [1, 2, 3]); 868 assert(result == 0); 869 result = cmp!"a > b"([1, 3, 2], [1, 2, 3]); 870 assert(result < 0); 871 result = cmp!"a > b"([1, 2, 3], [1L, 2, 3, 4]); 872 assert(result < 0); 873 result = cmp!"a > b"([1L, 2, 3], [1, 2]); 874 assert(result > 0); 875 } 876 877 // cmp for string with custom predicate fails if distinct chars can compare equal 878 // https://issues.dlang.org/show_bug.cgi?id=18286 879 @nogc nothrow pure @safe unittest 880 { 881 static bool ltCi(dchar a, dchar b)// less than, case insensitive 882 { 883 import std.ascii : toUpper; 884 return toUpper(a) < toUpper(b); 885 } 886 static assert(cmp!ltCi("apple2", "APPLE1") > 0); 887 static assert(cmp!ltCi("apple1", "APPLE2") < 0); 888 static assert(cmp!ltCi("apple", "APPLE1") < 0); 889 static assert(cmp!ltCi("APPLE", "apple1") < 0); 890 static assert(cmp!ltCi("apple", "APPLE") == 0); 891 } 892 893 // for non-string ranges check that opCmp is evaluated only once per pair. 894 // https://issues.dlang.org/show_bug.cgi?id=18280 895 @nogc nothrow @safe unittest 896 { 897 static int ctr = 0; 898 struct S 899 { 900 int opCmp(ref const S rhs) const 901 { 902 ++ctr; 903 return 0; 904 } 905 bool opEquals(T)(T o) const { return false; } 906 size_t toHash() const { return 0; } 907 } 908 immutable S[4] a; 909 immutable S[4] b; 910 immutable result = cmp(a[], b[]); 911 assert(result == 0, "neither should compare greater than the other!"); 912 assert(ctr == a.length, "opCmp should be called exactly once per pair of items!"); 913 } 914 915 nothrow pure @safe @nogc unittest 916 { 917 import std.array : staticArray; 918 // Test cmp when opCmp returns float. 919 struct F 920 { 921 float value; 922 float opCmp(const ref F rhs) const 923 { 924 return value - rhs.value; 925 } 926 bool opEquals(T)(T o) const { return false; } 927 size_t toHash() const { return 0; } 928 } 929 auto result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2), F(3)].staticArray[]); 930 assert(result == 0); 931 assert(is(typeof(result) == float)); 932 result = cmp([F(1), F(3), F(2)].staticArray[], [F(1), F(2), F(3)].staticArray[]); 933 assert(result > 0); 934 result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2), F(3), F(4)].staticArray[]); 935 assert(result < 0); 936 result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2)].staticArray[]); 937 assert(result > 0); 938 } 939 940 nothrow pure @safe unittest 941 { 942 // Parallelism (was broken by inferred return type "immutable int") 943 import std.parallelism : task; 944 auto t = task!cmp("foo", "bar"); 945 } 946 947 // equal 948 /** 949 Compares two or more ranges for equality, as defined by predicate `pred` 950 (which is `==` by default). 951 */ 952 template equal(alias pred = "a == b") 953 { 954 /++ 955 Compares two or more ranges for equality. The ranges may have 956 different element types, as long as all are comparable by means of 957 the `pred`. 958 Performs $(BIGOH min(rs[0].length, rs[1].length, ...)) evaluations of `pred`. However, if 959 `equal` is invoked with the default predicate, the implementation may take the liberty 960 to use faster implementations that have the theoretical worst-case 961 $(BIGOH max(rs[0].length, rs[1].length, ...)). 962 963 At least one of the ranges must be finite. If one range involved is infinite, the result is 964 (statically known to be) `false`. 965 966 If the ranges have different kinds of UTF code unit (`char`, `wchar`, or 967 `dchar`), then they are compared using UTF decoding to avoid 968 accidentally integer-promoting units. 969 970 Params: 971 rs = The ranges to be compared. 972 973 Returns: 974 `true` if and only if all ranges compare _equal element 975 for element, according to binary predicate `pred`. 976 +/ 977 bool equal(Ranges...)(Ranges rs) 978 if (rs.length > 1 979 && allSatisfy!(isInputRange, Ranges) 980 && !allSatisfy!(isInfinite, Ranges) 981 && is(typeof(binaryFun!pred(rs[0].front, rs[1].front))) 982 && (rs.length == 2 || is(typeof(equal!pred(rs[1 .. $])) == bool)) 983 ) 984 { 985 alias ElementEncodingTypes = staticMap!(ElementEncodingType, Ranges); 986 enum differentSize(T) = T.sizeof != ElementEncodingTypes[0].sizeof; 987 enum useCodePoint = allSatisfy!(isSomeChar, ElementEncodingTypes) && 988 anySatisfy!(differentSize, ElementEncodingTypes); 989 enum bool comparableWithEq(alias r) = is(typeof(rs[0] == r)); 990 991 static if (anySatisfy!(isInfinite, Ranges)) 992 { 993 return false; 994 } 995 else static if (useCodePoint) 996 { 997 import std.utf : byDchar; 998 static bool allByDchar(size_t done, Ranges...)(auto ref Ranges rs) 999 { 1000 static if (done == rs.length) 1001 return equalLoop(rs); 1002 else 1003 return allByDchar!(done + 1)(rs[0 .. done], rs[done].byDchar, rs[done + 1 .. $]); 1004 } 1005 return allByDchar!0(rs); 1006 } 1007 else static if (is(typeof(pred) == string) && pred == "a == b" && 1008 allSatisfy!(isArray, Ranges) && allSatisfy!(comparableWithEq, rs)) 1009 { 1010 static foreach (r; rs[1 .. $]) 1011 if (rs[0] != r) 1012 return false; 1013 return true; 1014 } 1015 // if one of the arguments is a string and the other isn't, then auto-decoding 1016 // can be avoided if they have the same ElementEncodingType 1017 // TODO: generalize this 1018 else static if (rs.length == 2 && is(typeof(pred) == string) && pred == "a == b" && 1019 isAutodecodableString!(Ranges[0]) != isAutodecodableString!(Ranges[1]) && 1020 is(immutable ElementEncodingType!(Ranges[0]) == immutable ElementEncodingType!(Ranges[1]))) 1021 { 1022 import std.utf : byCodeUnit; 1023 static if (isAutodecodableString!(Ranges[0])) 1024 return equal(rs[0].byCodeUnit, rs[1]); 1025 else 1026 return equal(rs[1].byCodeUnit, rs[0]); 1027 } 1028 else 1029 { 1030 static foreach (i, R; Ranges) 1031 { 1032 static if (hasLength!R) 1033 { 1034 static if (!is(typeof(firstLength))) 1035 { 1036 // Found the first range that has length 1037 auto firstLength = rs[i].length; 1038 } 1039 else 1040 { 1041 // Compare the length of the current range against the first with length 1042 if (firstLength != rs[i].length) 1043 return false; 1044 } 1045 } 1046 } 1047 return equalLoop(rs); 1048 } 1049 } 1050 1051 private bool equalLoop(Rs...)(ref Rs rs) 1052 { 1053 for (; !rs[0].empty; rs[0].popFront) 1054 static foreach (r; rs[1 .. $]) 1055 if (r.empty || !binaryFun!pred(rs[0].front, r.front)) 1056 return false; 1057 else 1058 r.popFront; 1059 static foreach (r; rs[1 .. $]) 1060 if (!r.empty) 1061 return false; 1062 return true; 1063 } 1064 } 1065 1066 /// 1067 @safe @nogc unittest 1068 { 1069 import std.algorithm.comparison : equal; 1070 import std.math.operations : isClose; 1071 1072 int[4] a = [ 1, 2, 4, 3 ]; 1073 assert(!equal(a[], a[1..$])); 1074 assert(equal(a[], a[])); 1075 assert(equal!((a, b) => a == b)(a[], a[])); 1076 1077 // different types 1078 double[4] b = [ 1.0, 2, 4, 3]; 1079 assert(!equal(a[], b[1..$])); 1080 assert(equal(a[], b[])); 1081 1082 // predicated: ensure that two vectors are approximately equal 1083 double[4] c = [ 1.0000000005, 2, 4, 3]; 1084 assert(equal!isClose(b[], c[])); 1085 } 1086 1087 @safe @nogc unittest 1088 { 1089 import std.algorithm.comparison : equal; 1090 import std.math.operations : isClose; 1091 1092 auto s1 = "abc", s2 = "abc"w; 1093 assert(equal(s1, s2, s2)); 1094 assert(equal(s1, s2, s2, s1)); 1095 assert(!equal(s1, s2, s2[1 .. $])); 1096 1097 int[4] a = [ 1, 2, 4, 3 ]; 1098 assert(!equal(a[], a[1..$], a[])); 1099 assert(equal(a[], a[], a[])); 1100 assert(equal!((a, b) => a == b)(a[], a[], a[])); 1101 1102 // different types 1103 double[4] b = [ 1.0, 2, 4, 3]; 1104 assert(!equal(a[], b[1..$], b[])); 1105 assert(equal(a[], b[], a[], b[])); 1106 1107 // predicated: ensure that two vectors are approximately equal 1108 double[4] c = [ 1.0000000005, 2, 4, 3]; 1109 assert(equal!isClose(b[], c[], b[])); 1110 } 1111 1112 /++ 1113 Tip: `equal` can itself be used as a predicate to other functions. 1114 This can be very useful when the element type of a range is itself a 1115 range. In particular, `equal` can be its own predicate, allowing 1116 range of range (of range...) comparisons. 1117 +/ 1118 @safe unittest 1119 { 1120 import std.algorithm.comparison : equal; 1121 import std.range : iota, chunks; 1122 assert(equal!(equal!equal)( 1123 [[[0, 1], [2, 3]], [[4, 5], [6, 7]]], 1124 iota(0, 8).chunks(2).chunks(2) 1125 )); 1126 } 1127 1128 @safe unittest 1129 { 1130 import std.algorithm.iteration : map; 1131 import std.internal.test.dummyrange : ReferenceForwardRange, 1132 ReferenceInputRange, ReferenceInfiniteForwardRange; 1133 import std.math.operations : isClose; 1134 1135 // various strings 1136 assert(equal("æøå", "æøå")); //UTF8 vs UTF8 1137 assert(!equal("???", "æøå")); //UTF8 vs UTF8 1138 assert(equal("æøå"w, "æøå"d)); //UTF16 vs UTF32 1139 assert(!equal("???"w, "æøå"d));//UTF16 vs UTF32 1140 assert(equal("æøå"d, "æøå"d)); //UTF32 vs UTF32 1141 assert(!equal("???"d, "æøå"d));//UTF32 vs UTF32 1142 assert(!equal("hello", "world")); 1143 1144 // same strings, but "explicit non default" comparison (to test the non optimized array comparison) 1145 assert( equal!("a == b")("æøå", "æøå")); //UTF8 vs UTF8 1146 assert(!equal!("a == b")("???", "æøå")); //UTF8 vs UTF8 1147 assert( equal!("a == b")("æøå"w, "æøå"d)); //UTF16 vs UTF32 1148 assert(!equal!("a == b")("???"w, "æøå"d));//UTF16 vs UTF32 1149 assert( equal!("a == b")("æøå"d, "æøå"d)); //UTF32 vs UTF32 1150 assert(!equal!("a == b")("???"d, "æøå"d));//UTF32 vs UTF32 1151 assert(!equal!("a == b")("hello", "world")); 1152 1153 //Array of string 1154 assert(equal(["hello", "world"], ["hello", "world"])); 1155 assert(!equal(["hello", "world"], ["hello"])); 1156 assert(!equal(["hello", "world"], ["hello", "Bob!"])); 1157 1158 //Should not compile, because "string == dstring" is illegal 1159 static assert(!is(typeof(equal(["hello", "world"], ["hello"d, "world"d])))); 1160 //However, arrays of non-matching string can be compared using equal!equal. Neat-o! 1161 equal!equal(["hello", "world"], ["hello"d, "world"d]); 1162 1163 //Tests, with more fancy map ranges 1164 int[] a = [ 1, 2, 4, 3 ]; 1165 assert(equal([2, 4, 8, 6], map!"a*2"(a))); 1166 double[] b = [ 1.0, 2, 4, 3]; 1167 double[] c = [ 1.0000000005, 2, 4, 3]; 1168 assert(equal!isClose(map!"a*2"(b), map!"a*2"(c))); 1169 assert(!equal([2, 4, 1, 3], map!"a*2"(a))); 1170 assert(!equal([2, 4, 1], map!"a*2"(a))); 1171 assert(!equal!isClose(map!"a*3"(b), map!"a*2"(c))); 1172 1173 //Tests with some fancy reference ranges. 1174 ReferenceInputRange!int cir = new ReferenceInputRange!int([1, 2, 4, 3]); 1175 ReferenceForwardRange!int cfr = new ReferenceForwardRange!int([1, 2, 4, 3]); 1176 assert(equal(cir, a)); 1177 cir = new ReferenceInputRange!int([1, 2, 4, 3]); 1178 assert(equal(cir, cfr.save)); 1179 assert(equal(cfr.save, cfr.save)); 1180 cir = new ReferenceInputRange!int([1, 2, 8, 1]); 1181 assert(!equal(cir, cfr)); 1182 1183 //Test with an infinite range 1184 auto ifr = new ReferenceInfiniteForwardRange!int; 1185 assert(!equal(a, ifr)); 1186 assert(!equal(ifr, a)); 1187 //Test InputRange without length 1188 assert(!equal(ifr, cir)); 1189 assert(!equal(cir, ifr)); 1190 } 1191 1192 @safe @nogc pure unittest 1193 { 1194 import std.utf : byChar, byDchar, byWchar; 1195 1196 assert(equal("æøå".byChar, "æøå")); 1197 assert(equal("æøå".byChar, "æøå"w)); 1198 assert(equal("æøå".byChar, "æøå"d)); 1199 assert(equal("æøå", "æøå".byChar)); 1200 assert(equal("æøå"w, "æøå".byChar)); 1201 assert(equal("æøå"d, "æøå".byChar)); 1202 1203 assert(equal("æøå".byWchar, "æøå")); 1204 assert(equal("æøå".byWchar, "æøå"w)); 1205 assert(equal("æøå".byWchar, "æøå"d)); 1206 assert(equal("æøå", "æøå".byWchar)); 1207 assert(equal("æøå"w, "æøå".byWchar)); 1208 assert(equal("æøå"d, "æøå".byWchar)); 1209 1210 assert(equal("æøå".byDchar, "æøå")); 1211 assert(equal("æøå".byDchar, "æøå"w)); 1212 assert(equal("æøå".byDchar, "æøå"d)); 1213 assert(equal("æøå", "æøå".byDchar)); 1214 assert(equal("æøå"w, "æøå".byDchar)); 1215 assert(equal("æøå"d, "æøå".byDchar)); 1216 } 1217 1218 @safe @nogc pure unittest 1219 { 1220 struct R(bool _empty) { 1221 enum empty = _empty; 1222 @property char front(){assert(0);} 1223 void popFront(){assert(0);} 1224 } 1225 alias I = R!false; 1226 static assert(!__traits(compiles, I().equal(I()))); 1227 // strings have fixed length so don't need to compare elements 1228 assert(!I().equal("foo")); 1229 assert(!"bar".equal(I())); 1230 1231 alias E = R!true; 1232 assert(E().equal(E())); 1233 assert(E().equal("")); 1234 assert("".equal(E())); 1235 assert(!E().equal("foo")); 1236 assert(!"bar".equal(E())); 1237 } 1238 1239 // levenshteinDistance 1240 /** 1241 Encodes $(HTTP realityinteractive.com/rgrzywinski/archives/000249.html, 1242 edit operations) necessary to transform one sequence into 1243 another. Given sequences `s` (source) and `t` (target), a 1244 sequence of `EditOp` encodes the steps that need to be taken to 1245 convert `s` into `t`. For example, if `s = "cat"` and $(D 1246 "cars"), the minimal sequence that transforms `s` into `t` is: 1247 skip two characters, replace 't' with 'r', and insert an 's'. Working 1248 with edit operations is useful in applications such as spell-checkers 1249 (to find the closest word to a given misspelled word), approximate 1250 searches, diff-style programs that compute the difference between 1251 files, efficient encoding of patches, DNA sequence analysis, and 1252 plagiarism detection. 1253 */ 1254 1255 enum EditOp : char 1256 { 1257 /** Current items are equal; no editing is necessary. */ 1258 none = 'n', 1259 /** Substitute current item in target with current item in source. */ 1260 substitute = 's', 1261 /** Insert current item from the source into the target. */ 1262 insert = 'i', 1263 /** Remove current item from the target. */ 1264 remove = 'r' 1265 } 1266 1267 /// 1268 @safe unittest 1269 { 1270 with(EditOp) 1271 { 1272 assert(levenshteinDistanceAndPath("foo", "foobar")[1] == [none, none, none, insert, insert, insert]); 1273 assert(levenshteinDistanceAndPath("banana", "fazan")[1] == [substitute, none, substitute, none, none, remove]); 1274 } 1275 } 1276 1277 private struct Levenshtein(Range, alias equals, CostType = size_t) 1278 { 1279 EditOp[] path() 1280 { 1281 import std.algorithm.mutation : reverse; 1282 1283 EditOp[] result; 1284 size_t i = rows - 1, j = cols - 1; 1285 // restore the path 1286 while (i || j) 1287 { 1288 auto cIns = j == 0 ? CostType.max : matrix(i,j - 1); 1289 auto cDel = i == 0 ? CostType.max : matrix(i - 1,j); 1290 auto cSub = i == 0 || j == 0 1291 ? CostType.max 1292 : matrix(i - 1,j - 1); 1293 switch (min_index(cSub, cIns, cDel)) 1294 { 1295 case 0: 1296 result ~= matrix(i - 1,j - 1) == matrix(i,j) 1297 ? EditOp.none 1298 : EditOp.substitute; 1299 --i; 1300 --j; 1301 break; 1302 case 1: 1303 result ~= EditOp.insert; 1304 --j; 1305 break; 1306 default: 1307 result ~= EditOp.remove; 1308 --i; 1309 break; 1310 } 1311 } 1312 reverse(result); 1313 return result; 1314 } 1315 1316 ~this() { 1317 FreeMatrix(); 1318 } 1319 1320 private: 1321 CostType _deletionIncrement = 1, 1322 _insertionIncrement = 1, 1323 _substitutionIncrement = 1; 1324 CostType[] _matrix; 1325 size_t rows, cols; 1326 1327 // Treat _matrix as a rectangular array 1328 ref CostType matrix(size_t row, size_t col) { return _matrix[row * cols + col]; } 1329 1330 void AllocMatrix(size_t r, size_t c) @trusted { 1331 import core.checkedint : mulu; 1332 bool overflow; 1333 const rc = mulu(r, c, overflow); 1334 assert(!overflow, "Overflow during multiplication to determine number " 1335 ~ " of matrix elements"); 1336 rows = r; 1337 cols = c; 1338 if (_matrix.length < rc) 1339 { 1340 import core.exception : onOutOfMemoryError; 1341 import core.stdc.stdlib : realloc; 1342 const nbytes = mulu(rc, _matrix[0].sizeof, overflow); 1343 assert(!overflow, "Overflow during multiplication to determine " 1344 ~ " number of bytes of matrix"); 1345 auto m = cast(CostType *) realloc(_matrix.ptr, nbytes); 1346 if (!m) 1347 onOutOfMemoryError(); 1348 _matrix = m[0 .. r * c]; 1349 InitMatrix(); 1350 } 1351 } 1352 1353 void FreeMatrix() @trusted { 1354 import core.stdc.stdlib : free; 1355 1356 free(_matrix.ptr); 1357 _matrix = null; 1358 } 1359 1360 void InitMatrix() { 1361 foreach (r; 0 .. rows) 1362 matrix(r,0) = r * _deletionIncrement; 1363 foreach (c; 0 .. cols) 1364 matrix(0,c) = c * _insertionIncrement; 1365 } 1366 1367 static uint min_index(CostType i0, CostType i1, CostType i2) 1368 { 1369 if (i0 <= i1) 1370 { 1371 return i0 <= i2 ? 0 : 2; 1372 } 1373 else 1374 { 1375 return i1 <= i2 ? 1 : 2; 1376 } 1377 } 1378 1379 CostType distanceWithPath(Range s, Range t) 1380 { 1381 auto slen = walkLength(s.save), tlen = walkLength(t.save); 1382 AllocMatrix(slen + 1, tlen + 1); 1383 foreach (i; 1 .. rows) 1384 { 1385 auto sfront = s.front; 1386 auto tt = t.save; 1387 foreach (j; 1 .. cols) 1388 { 1389 auto cSub = matrix(i - 1,j - 1) 1390 + (equals(sfront, tt.front) ? 0 : _substitutionIncrement); 1391 tt.popFront(); 1392 auto cIns = matrix(i,j - 1) + _insertionIncrement; 1393 auto cDel = matrix(i - 1,j) + _deletionIncrement; 1394 switch (min_index(cSub, cIns, cDel)) 1395 { 1396 case 0: 1397 matrix(i,j) = cSub; 1398 break; 1399 case 1: 1400 matrix(i,j) = cIns; 1401 break; 1402 default: 1403 matrix(i,j) = cDel; 1404 break; 1405 } 1406 } 1407 s.popFront(); 1408 } 1409 return matrix(slen,tlen); 1410 } 1411 1412 CostType distanceLowMem(Range s, Range t, CostType slen, CostType tlen) 1413 { 1414 CostType lastdiag, olddiag; 1415 AllocMatrix(slen + 1, 1); 1416 foreach (y; 1 .. slen + 1) 1417 { 1418 _matrix[y] = y; 1419 } 1420 foreach (x; 1 .. tlen + 1) 1421 { 1422 auto tfront = t.front; 1423 auto ss = s.save; 1424 _matrix[0] = x; 1425 lastdiag = x - 1; 1426 foreach (y; 1 .. rows) 1427 { 1428 olddiag = _matrix[y]; 1429 auto cSub = lastdiag + (equals(ss.front, tfront) ? 0 : _substitutionIncrement); 1430 ss.popFront(); 1431 auto cIns = _matrix[y - 1] + _insertionIncrement; 1432 auto cDel = _matrix[y] + _deletionIncrement; 1433 switch (min_index(cSub, cIns, cDel)) 1434 { 1435 case 0: 1436 _matrix[y] = cSub; 1437 break; 1438 case 1: 1439 _matrix[y] = cIns; 1440 break; 1441 default: 1442 _matrix[y] = cDel; 1443 break; 1444 } 1445 lastdiag = olddiag; 1446 } 1447 t.popFront(); 1448 } 1449 return _matrix[slen]; 1450 } 1451 } 1452 1453 /** 1454 Returns the $(HTTP wikipedia.org/wiki/Levenshtein_distance, Levenshtein 1455 distance) between `s` and `t`. The Levenshtein distance computes 1456 the minimal amount of edit operations necessary to transform `s` 1457 into `t`. Performs $(BIGOH s.length * t.length) evaluations of $(D 1458 equals) and occupies $(BIGOH min(s.length, t.length)) storage. 1459 1460 Params: 1461 equals = The binary predicate to compare the elements of the two ranges. 1462 s = The original range. 1463 t = The transformation target 1464 1465 Returns: 1466 The minimal number of edits to transform s into t. 1467 1468 Does not allocate GC memory. 1469 */ 1470 size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2) 1471 (Range1 s, Range2 t) 1472 if (isForwardRange!(Range1) && isForwardRange!(Range2)) 1473 { 1474 alias eq = binaryFun!(equals); 1475 1476 for (;;) 1477 { 1478 if (s.empty) return t.walkLength; 1479 if (t.empty) return s.walkLength; 1480 if (eq(s.front, t.front)) 1481 { 1482 s.popFront(); 1483 t.popFront(); 1484 continue; 1485 } 1486 static if (isBidirectionalRange!(Range1) && isBidirectionalRange!(Range2)) 1487 { 1488 if (eq(s.back, t.back)) 1489 { 1490 s.popBack(); 1491 t.popBack(); 1492 continue; 1493 } 1494 } 1495 break; 1496 } 1497 1498 auto slen = walkLength(s.save); 1499 auto tlen = walkLength(t.save); 1500 1501 if (slen == 1 && tlen == 1) 1502 { 1503 return eq(s.front, t.front) ? 0 : 1; 1504 } 1505 1506 if (slen < tlen) 1507 { 1508 Levenshtein!(Range1, eq, size_t) lev; 1509 return lev.distanceLowMem(s, t, slen, tlen); 1510 } 1511 else 1512 { 1513 Levenshtein!(Range2, eq, size_t) lev; 1514 return lev.distanceLowMem(t, s, tlen, slen); 1515 } 1516 } 1517 1518 /// 1519 @safe unittest 1520 { 1521 import std.algorithm.iteration : filter; 1522 import std.uni : toUpper; 1523 1524 assert(levenshteinDistance("cat", "rat") == 1); 1525 assert(levenshteinDistance("parks", "spark") == 2); 1526 assert(levenshteinDistance("abcde", "abcde") == 0); 1527 assert(levenshteinDistance("abcde", "abCde") == 1); 1528 assert(levenshteinDistance("kitten", "sitting") == 3); 1529 assert(levenshteinDistance!((a, b) => toUpper(a) == toUpper(b)) 1530 ("parks", "SPARK") == 2); 1531 assert(levenshteinDistance("parks".filter!"true", "spark".filter!"true") == 2); 1532 assert(levenshteinDistance("ID", "I♥D") == 1); 1533 } 1534 1535 @safe @nogc nothrow unittest 1536 { 1537 assert(levenshteinDistance("cat"d, "rat"d) == 1); 1538 } 1539 1540 /// ditto 1541 size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2) 1542 (auto ref Range1 s, auto ref Range2 t) 1543 if (isConvertibleToString!Range1 || isConvertibleToString!Range2) 1544 { 1545 import std.meta : staticMap; 1546 alias Types = staticMap!(convertToString, Range1, Range2); 1547 return levenshteinDistance!(equals, Types)(s, t); 1548 } 1549 1550 @safe unittest 1551 { 1552 static struct S { string s; alias s this; } 1553 assert(levenshteinDistance(S("cat"), S("rat")) == 1); 1554 assert(levenshteinDistance("cat", S("rat")) == 1); 1555 assert(levenshteinDistance(S("cat"), "rat") == 1); 1556 } 1557 1558 @safe @nogc nothrow unittest 1559 { 1560 static struct S { dstring s; alias s this; } 1561 assert(levenshteinDistance(S("cat"d), S("rat"d)) == 1); 1562 assert(levenshteinDistance("cat"d, S("rat"d)) == 1); 1563 assert(levenshteinDistance(S("cat"d), "rat"d) == 1); 1564 } 1565 1566 /** 1567 Returns the Levenshtein distance and the edit path between `s` and 1568 `t`. 1569 1570 Params: 1571 equals = The binary predicate to compare the elements of the two ranges. 1572 s = The original range. 1573 t = The transformation target 1574 1575 Returns: 1576 Tuple with the first element being the minimal amount of edits to transform s into t and 1577 the second element being the sequence of edits to effect this transformation. 1578 1579 Allocates GC memory for the returned EditOp[] array. 1580 */ 1581 Tuple!(size_t, EditOp[]) 1582 levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2) 1583 (Range1 s, Range2 t) 1584 if (isForwardRange!(Range1) && isForwardRange!(Range2)) 1585 { 1586 Levenshtein!(Range1, binaryFun!(equals)) lev; 1587 auto d = lev.distanceWithPath(s, t); 1588 return tuple(d, lev.path()); 1589 } 1590 1591 /// 1592 @safe unittest 1593 { 1594 string a = "Saturday", b = "Sundays"; 1595 auto p = levenshteinDistanceAndPath(a, b); 1596 assert(p[0] == 4); 1597 assert(equal(p[1], "nrrnsnnni")); 1598 } 1599 1600 @safe unittest 1601 { 1602 assert(levenshteinDistance("a", "a") == 0); 1603 assert(levenshteinDistance("a", "b") == 1); 1604 assert(levenshteinDistance("aa", "ab") == 1); 1605 assert(levenshteinDistance("aa", "abc") == 2); 1606 assert(levenshteinDistance("Saturday", "Sunday") == 3); 1607 assert(levenshteinDistance("kitten", "sitting") == 3); 1608 } 1609 1610 /// ditto 1611 Tuple!(size_t, EditOp[]) 1612 levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2) 1613 (auto ref Range1 s, auto ref Range2 t) 1614 if (isConvertibleToString!Range1 || isConvertibleToString!Range2) 1615 { 1616 import std.meta : staticMap; 1617 alias Types = staticMap!(convertToString, Range1, Range2); 1618 return levenshteinDistanceAndPath!(equals, Types)(s, t); 1619 } 1620 1621 @safe unittest 1622 { 1623 static struct S { string s; alias s this; } 1624 assert(levenshteinDistanceAndPath(S("cat"), S("rat"))[0] == 1); 1625 assert(levenshteinDistanceAndPath("cat", S("rat"))[0] == 1); 1626 assert(levenshteinDistanceAndPath(S("cat"), "rat")[0] == 1); 1627 } 1628 1629 1630 // max 1631 /** 1632 Iterates the passed arguments and returns the maximum value. 1633 1634 Params: 1635 args = The values to select the maximum from. At least two arguments must 1636 be passed, and they must be comparable with `<`. 1637 1638 Returns: 1639 The maximum of the passed-in values. The type of the returned value is 1640 the type among the passed arguments that is able to store the largest value. 1641 If at least one of the arguments is NaN, the result is an unspecified value. 1642 See $(REF maxElement, std,algorithm,searching) for examples on how to cope 1643 with NaNs. 1644 1645 See_Also: 1646 $(REF maxElement, std,algorithm,searching) 1647 */ 1648 auto max(T...)(T args) 1649 if (T.length >= 2 && !is(CommonType!T == void)) 1650 { 1651 // Get left-hand side of the comparison. 1652 static if (T.length == 2) 1653 alias a = args[0]; 1654 else 1655 auto a = max(args[0 .. ($ + 1) / 2]); 1656 alias T0 = typeof(a); 1657 1658 // Get right-hand side. 1659 static if (T.length <= 3) 1660 alias b = args[$ - 1]; 1661 else 1662 auto b = max(args[($ + 1) / 2 .. $]); 1663 alias T1 = typeof(b); 1664 1665 static assert(is(typeof(a < b)), 1666 "Invalid arguments: Cannot compare types " ~ T0.stringof ~ 1667 " and " ~ T1.stringof ~ " for ordering."); 1668 1669 // Compute the returned type. 1670 static if (is(typeof(mostNegative!T0 < mostNegative!T1))) 1671 // Both are numeric (or character or Boolean), so we choose the one with the highest maximum. 1672 // (We use mostNegative for num/bool/char testing purposes even if it's not used otherwise.) 1673 alias Result = Select!(T1.max > T0.max, T1, T0); 1674 else 1675 // At least one is non-numeric, so just go with the common type. 1676 alias Result = CommonType!(T0, T1); 1677 1678 // Perform the computation. 1679 import std.functional : lessThan; 1680 immutable chooseB = lessThan!(T0, T1)(a, b); 1681 return cast(Result) (chooseB ? b : a); 1682 } 1683 1684 /// ditto 1685 T max(T, U)(T a, U b) 1686 if (is(T == U) && is(typeof(a < b))) 1687 { 1688 /* Handle the common case without all the template expansions 1689 * of the general case 1690 */ 1691 return a < b ? b : a; 1692 } 1693 1694 /// 1695 @safe @betterC @nogc unittest 1696 { 1697 int a = 5; 1698 short b = 6; 1699 double c = 2; 1700 auto d = max(a, b); 1701 assert(is(typeof(d) == int)); 1702 assert(d == 6); 1703 auto e = min(a, b, c); 1704 assert(is(typeof(e) == double)); 1705 assert(e == 2); 1706 } 1707 1708 @safe unittest // not @nogc due to `Date` 1709 { 1710 int a = 5; 1711 short b = 6; 1712 double c = 2; 1713 auto d = max(a, b); 1714 static assert(is(typeof(d) == int)); 1715 assert(d == 6); 1716 auto e = max(a, b, c); 1717 static assert(is(typeof(e) == double)); 1718 assert(e == 6); 1719 // mixed sign 1720 a = -5; 1721 uint f = 5; 1722 static assert(is(typeof(max(a, f)) == uint)); 1723 assert(max(a, f) == 5); 1724 1725 //Test user-defined types 1726 import std.datetime : Date; 1727 assert(max(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(2012, 12, 21)); 1728 assert(max(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(2012, 12, 21)); 1729 assert(max(Date(1982, 1, 4), Date.min) == Date(1982, 1, 4)); 1730 assert(max(Date.min, Date(1982, 1, 4)) == Date(1982, 1, 4)); 1731 assert(max(Date(1982, 1, 4), Date.max) == Date.max); 1732 assert(max(Date.max, Date(1982, 1, 4)) == Date.max); 1733 assert(max(Date.min, Date.max) == Date.max); 1734 assert(max(Date.max, Date.min) == Date.max); 1735 } 1736 1737 // min 1738 /** 1739 Iterates the passed arguments and returns the minimum value. 1740 1741 Params: 1742 args = The values to select the minimum from. At least two arguments must 1743 be passed, and they must be comparable with `<`. 1744 1745 Returns: 1746 The minimum of the passed-in values. The type of the returned value is 1747 the type among the passed arguments that is able to store the smallest value. 1748 If at least one of the arguments is NaN, the result is an unspecified value. 1749 See $(REF minElement, std,algorithm,searching) for examples on how to cope 1750 with NaNs. 1751 1752 See_Also: 1753 $(REF minElement, std,algorithm,searching) 1754 */ 1755 auto min(T...)(T args) 1756 if (T.length >= 2 && !is(CommonType!T == void)) 1757 { 1758 // Get the left-hand side of the comparison. 1759 static if (T.length <= 2) 1760 alias a = args[0]; 1761 else 1762 auto a = min(args[0 .. ($ + 1) / 2]); 1763 alias T0 = typeof(a); 1764 1765 // Get the right-hand side. 1766 static if (T.length <= 3) 1767 alias b = args[$ - 1]; 1768 else 1769 auto b = min(args[($ + 1) / 2 .. $]); 1770 alias T1 = typeof(b); 1771 1772 static assert(is(typeof(a < b)), 1773 "Invalid arguments: Cannot compare types " ~ T0.stringof ~ 1774 " and " ~ T1.stringof ~ " for ordering."); 1775 1776 // Compute the returned type. 1777 static if (is(typeof(mostNegative!T0 < mostNegative!T1))) 1778 // Both are numeric (or character or Boolean), so we choose the one with the lowest minimum. 1779 // If they have the same minimum, choose the one with the smallest size. 1780 // If both mostNegative and sizeof are equal, go for stability: pick the type of the first one. 1781 alias Result = Select!(mostNegative!T1 < mostNegative!T0 || 1782 mostNegative!T1 == mostNegative!T0 && T1.sizeof < T0.sizeof, 1783 T1, T0); 1784 else 1785 // At least one is non-numeric, so just go with the common type. 1786 alias Result = CommonType!(T0, T1); 1787 1788 // Engage! 1789 import std.functional : lessThan; 1790 immutable chooseB = lessThan!(T1, T0)(b, a); 1791 return cast(Result) (chooseB ? b : a); 1792 } 1793 1794 /// ditto 1795 T min(T, U)(T a, U b) 1796 if (is(T == U) && is(typeof(a < b))) 1797 { 1798 /* Handle the common case without all the template expansions 1799 * of the general case 1800 */ 1801 return b < a ? b : a; 1802 } 1803 1804 1805 /// 1806 @safe @nogc @betterC unittest 1807 { 1808 int a = 5; 1809 short b = 6; 1810 double c = 2; 1811 auto d = min(a, b); 1812 static assert(is(typeof(d) == int)); 1813 assert(d == 5); 1814 auto e = min(a, b, c); 1815 static assert(is(typeof(e) == double)); 1816 assert(e == 2); 1817 ulong f = 0xffff_ffff_ffff; 1818 const uint g = min(f, 0xffff_0000); 1819 assert(g == 0xffff_0000); 1820 dchar h = 100; 1821 uint i = 101; 1822 static assert(is(typeof(min(h, i)) == dchar)); 1823 static assert(is(typeof(min(i, h)) == uint)); 1824 assert(min(h, i) == 100); 1825 } 1826 1827 /** 1828 With arguments of mixed signedness, the return type is the one that can 1829 store the lowest values. 1830 */ 1831 @safe @nogc @betterC unittest 1832 { 1833 int a = -10; 1834 uint f = 10; 1835 static assert(is(typeof(min(a, f)) == int)); 1836 assert(min(a, f) == -10); 1837 } 1838 1839 /// User-defined types that support comparison with < are supported. 1840 @safe unittest // not @nogc due to `Date` 1841 { 1842 import std.datetime; 1843 assert(min(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(1982, 1, 4)); 1844 assert(min(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(1982, 1, 4)); 1845 assert(min(Date(1982, 1, 4), Date.min) == Date.min); 1846 assert(min(Date.min, Date(1982, 1, 4)) == Date.min); 1847 assert(min(Date(1982, 1, 4), Date.max) == Date(1982, 1, 4)); 1848 assert(min(Date.max, Date(1982, 1, 4)) == Date(1982, 1, 4)); 1849 assert(min(Date.min, Date.max) == Date.min); 1850 assert(min(Date.max, Date.min) == Date.min); 1851 } 1852 1853 // min must be stable: when in doubt, return the first argument. 1854 @safe unittest 1855 { 1856 assert(min(1.0, double.nan) == 1.0); 1857 assert(min(double.nan, 1.0) is double.nan); 1858 static struct A { 1859 int x; 1860 string y; 1861 int opCmp(const A a) const { return int(x > a.x) - int(x < a.x); } 1862 } 1863 assert(min(A(1, "first"), A(1, "second")) == A(1, "first")); 1864 } 1865 1866 // mismatch 1867 /** 1868 Sequentially compares elements in `rs` in lockstep, and 1869 stops at the first mismatch (according to `pred`, by default 1870 equality). Returns a tuple with the reduced ranges that start with the 1871 two mismatched values. Performs $(BIGOH min(r[0].length, r[1].length, ...)) 1872 evaluations of `pred`. 1873 */ 1874 Tuple!(Ranges) 1875 mismatch(alias pred = (a, b) => a == b, Ranges...)(Ranges rs) 1876 if (rs.length >= 2 && allSatisfy!(isInputRange, Ranges)) 1877 { 1878 loop: for (; !rs[0].empty; rs[0].popFront) 1879 { 1880 static foreach (r; rs[1 .. $]) 1881 { 1882 if (r.empty || !binaryFun!pred(rs[0].front, r.front)) 1883 break loop; 1884 r.popFront; 1885 } 1886 } 1887 return tuple(rs); 1888 } 1889 1890 /// 1891 @safe @nogc unittest 1892 { 1893 int[6] x = [ 1, 5, 2, 7, 4, 3 ]; 1894 double[6] y = [ 1.0, 5, 2, 7.3, 4, 8 ]; 1895 auto m = mismatch(x[], y[]); 1896 assert(m[0] == x[3 .. $]); 1897 assert(m[1] == y[3 .. $]); 1898 1899 auto m2 = mismatch(x[], y[], x[], y[]); 1900 assert(m2[0] == x[3 .. $]); 1901 assert(m2[1] == y[3 .. $]); 1902 assert(m2[2] == x[3 .. $]); 1903 assert(m2[3] == y[3 .. $]); 1904 } 1905 1906 @safe @nogc unittest 1907 { 1908 import std.range : only; 1909 1910 int[3] a = [ 1, 2, 3 ]; 1911 int[4] b = [ 1, 2, 4, 5 ]; 1912 auto mm = mismatch(a[], b[]); 1913 assert(equal(mm[0], only(3))); 1914 assert(equal(mm[1], only(4, 5))); 1915 } 1916 1917 /** 1918 Returns one of a collection of expressions based on the value of the switch 1919 expression. 1920 1921 `choices` needs to be composed of pairs of test expressions and return 1922 expressions. Each test-expression is compared with `switchExpression` using 1923 `pred`(`switchExpression` is the first argument) and if that yields true - 1924 the return expression is returned. 1925 1926 Both the test and the return expressions are lazily evaluated. 1927 1928 Params: 1929 1930 switchExpression = The first argument for the predicate. 1931 1932 choices = Pairs of test expressions and return expressions. The test 1933 expressions will be the second argument for the predicate, and the return 1934 expression will be returned if the predicate yields true with $(D 1935 switchExpression) and the test expression as arguments. May also have a 1936 default return expression, that needs to be the last expression without a test 1937 expression before it. A return expression may be of void type only if it 1938 always throws. 1939 1940 Returns: The return expression associated with the first test expression that 1941 made the predicate yield true, or the default return expression if no test 1942 expression matched. 1943 1944 Throws: If there is no default return expression and the predicate does not 1945 yield true with any test expression - `SwitchError` is thrown. $(D 1946 SwitchError) is also thrown if a void return expression was executed without 1947 throwing anything. 1948 */ 1949 auto predSwitch(alias pred = "a == b", T, R ...)(T switchExpression, lazy R choices) 1950 { 1951 import core.exception : SwitchError; 1952 alias predicate = binaryFun!(pred); 1953 1954 foreach (index, ChoiceType; R) 1955 { 1956 //The even places in `choices` are for the predicate. 1957 static if (index % 2 == 1) 1958 { 1959 if (predicate(switchExpression, choices[index - 1]())) 1960 { 1961 static if (is(typeof(choices[index]()) == void)) 1962 { 1963 choices[index](); 1964 throw new SwitchError("Choices that return void should throw"); 1965 } 1966 else 1967 { 1968 return choices[index](); 1969 } 1970 } 1971 } 1972 } 1973 1974 //In case nothing matched: 1975 static if (R.length % 2 == 1) //If there is a default return expression: 1976 { 1977 static if (is(typeof(choices[$ - 1]()) == void)) 1978 { 1979 choices[$ - 1](); 1980 throw new SwitchError("Choices that return void should throw"); 1981 } 1982 else 1983 { 1984 return choices[$ - 1](); 1985 } 1986 } 1987 else //If there is no default return expression: 1988 { 1989 throw new SwitchError("Input not matched by any pattern"); 1990 } 1991 } 1992 1993 /// 1994 @safe unittest 1995 { 1996 string res = 2.predSwitch!"a < b"( 1997 1, "less than 1", 1998 5, "less than 5", 1999 10, "less than 10", 2000 "greater or equal to 10"); 2001 2002 assert(res == "less than 5"); 2003 2004 //The arguments are lazy, which allows us to use predSwitch to create 2005 //recursive functions: 2006 int factorial(int n) 2007 { 2008 return n.predSwitch!"a <= b"( 2009 -1, {throw new Exception("Can not calculate n! for n < 0");}(), 2010 0, 1, // 0! = 1 2011 n * factorial(n - 1) // n! = n * (n - 1)! for n >= 0 2012 ); 2013 } 2014 assert(factorial(3) == 6); 2015 2016 //Void return expressions are allowed if they always throw: 2017 import std.exception : assertThrown; 2018 assertThrown!Exception(factorial(-9)); 2019 } 2020 2021 @system unittest 2022 { 2023 import core.exception : SwitchError; 2024 import std.exception : assertThrown; 2025 2026 //Nothing matches - with default return expression: 2027 assert(20.predSwitch!"a < b"( 2028 1, "less than 1", 2029 5, "less than 5", 2030 10, "less than 10", 2031 "greater or equal to 10") == "greater or equal to 10"); 2032 2033 //Nothing matches - without default return expression: 2034 assertThrown!SwitchError(20.predSwitch!"a < b"( 2035 1, "less than 1", 2036 5, "less than 5", 2037 10, "less than 10", 2038 )); 2039 2040 //Using the default predicate: 2041 assert(2.predSwitch( 2042 1, "one", 2043 2, "two", 2044 3, "three", 2045 ) == "two"); 2046 2047 //Void return expressions must always throw: 2048 assertThrown!SwitchError(1.predSwitch( 2049 0, "zero", 2050 1, {}(), //A void return expression that doesn't throw 2051 2, "two", 2052 )); 2053 } 2054 2055 /** 2056 Checks if two or more ranges have the same number of elements. This function is 2057 optimized to always take advantage of the `length` member of either range 2058 if it exists. 2059 2060 If all ranges have a `length` member or at least one is infinite, 2061 `_isSameLength`'s complexity is $(BIGOH 1). Otherwise, complexity is 2062 $(BIGOH n), where `n` is the smallest of the lengths of ranges with unknown 2063 length. 2064 2065 Infinite ranges are considered of the same length. An infinite range has never 2066 the same length as a finite range. 2067 2068 Params: 2069 rs = two or more $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) 2070 2071 Returns: 2072 `true` if both ranges have the same length, `false` otherwise. 2073 */ 2074 bool isSameLength(Ranges...)(Ranges rs) 2075 if (allSatisfy!(isInputRange, Ranges)) 2076 { 2077 static if (anySatisfy!(isInfinite, Ranges)) 2078 { 2079 return allSatisfy!(isInfinite, Ranges); 2080 } 2081 else static if (anySatisfy!(hasLength, Ranges)) 2082 { 2083 // Compute the O(1) length 2084 auto baselineLength = size_t.max; 2085 static foreach (i, R; Ranges) 2086 { 2087 static if (hasLength!R) 2088 { 2089 if (baselineLength == size_t.max) 2090 baselineLength = rs[i].length; 2091 else if (rs[i].length != baselineLength) 2092 return false; 2093 } 2094 } 2095 // Iterate all ranges without known length 2096 foreach (_; 0 .. baselineLength) 2097 static foreach (i, R; Ranges) 2098 { 2099 static if (!hasLength!R) 2100 { 2101 // All must be non-empty 2102 if (rs[i].empty) 2103 return false; 2104 rs[i].popFront; 2105 } 2106 } 2107 static foreach (i, R; Ranges) 2108 { 2109 static if (!hasLength!R) 2110 { 2111 // All must be now empty 2112 if (!rs[i].empty) 2113 return false; 2114 } 2115 } 2116 return true; 2117 } 2118 else 2119 { 2120 // All have unknown length, iterate in lockstep 2121 for (;;) 2122 static foreach (i, r; rs) 2123 { 2124 if (r.empty) 2125 { 2126 // One is empty, so all must be empty 2127 static if (i != 0) 2128 { 2129 return false; 2130 } 2131 else 2132 { 2133 static foreach (j, r1; rs[1 .. $]) 2134 if (!r1.empty) 2135 return false; 2136 return true; 2137 } 2138 } 2139 r.popFront; 2140 } 2141 } 2142 } 2143 2144 /// 2145 @safe nothrow pure unittest 2146 { 2147 assert(isSameLength([1, 2, 3], [4, 5, 6])); 2148 assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9])); 2149 assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3])); 2150 assert(isSameLength("abc", "xyz")); 2151 assert(isSameLength("abc", "xyz", [1, 2, 3])); 2152 2153 int[] a; 2154 int[] b; 2155 assert(isSameLength(a, b)); 2156 assert(isSameLength(a, b, a, a, b, b, b)); 2157 2158 assert(!isSameLength([1, 2, 3], [4, 5])); 2159 assert(!isSameLength([1, 2, 3], [4, 5, 6], [7, 8])); 2160 assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3])); 2161 assert(!isSameLength("abcd", "xyz")); 2162 assert(!isSameLength("abcd", "xyz", "123")); 2163 assert(!isSameLength("abcd", "xyz", "1234")); 2164 } 2165 2166 // Test CTFE 2167 @safe @nogc pure @betterC unittest 2168 { 2169 static assert(isSameLength([1, 2, 3], [4, 5, 6])); 2170 static assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9])); 2171 static assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3])); 2172 static assert(!isSameLength([1], [0.3, 90.4], [42])); 2173 } 2174 2175 @safe @nogc pure unittest 2176 { 2177 import std.range : only; 2178 assert(isSameLength(only(1, 2, 3), only(4, 5, 6))); 2179 assert(isSameLength(only(1, 2, 3), only(4, 5, 6), only(7, 8, 9))); 2180 assert(isSameLength(only(0.3, 90.4, 23.7, 119.2), only(42.6, 23.6, 95.5, 6.3))); 2181 assert(!isSameLength(only(1, 3, 3), only(4, 5))); 2182 assert(!isSameLength(only(1, 3, 3), only(1, 3, 3), only(4, 5))); 2183 assert(!isSameLength(only(1, 3, 3), only(4, 5), only(1, 3, 3))); 2184 } 2185 2186 @safe nothrow pure unittest 2187 { 2188 import std.internal.test.dummyrange; 2189 2190 auto r1 = new ReferenceInputRange!int([1, 2, 3]); 2191 auto r2 = new ReferenceInputRange!int([4, 5, 6]); 2192 assert(isSameLength(r1, r2)); 2193 2194 auto r3 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 2195 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r4; 2196 assert(isSameLength(r3, r4)); 2197 2198 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r5; 2199 auto r6 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 2200 assert(isSameLength(r5, r6)); 2201 2202 auto r7 = new ReferenceInputRange!int([1, 2]); 2203 auto r8 = new ReferenceInputRange!int([4, 5, 6]); 2204 assert(!isSameLength(r7, r8)); 2205 2206 auto r9 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]); 2207 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r10; 2208 assert(!isSameLength(r9, r10)); 2209 2210 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r11; 2211 auto r12 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]); 2212 assert(!isSameLength(r11, r12)); 2213 2214 import std.algorithm.iteration : filter; 2215 2216 assert(isSameLength(filter!"a >= 1"([1, 2, 3]), [4, 5, 6])); 2217 assert(!isSameLength(filter!"a > 1"([1, 2, 3]), [4, 5, 6])); 2218 2219 assert(isSameLength(filter!"a > 1"([1, 2, 3]), filter!"a > 4"([4, 5, 6]))); 2220 assert(isSameLength(filter!"a > 1"([1, 2, 3]), 2221 filter!"a > 4"([4, 5, 6]), filter!"a >= 5"([4, 5, 6]))); 2222 } 2223 2224 // Still functional but not documented anymore. 2225 alias AllocateGC = Flag!"allocateGC"; 2226 2227 /** 2228 Checks if both ranges are permutations of each other. 2229 2230 This function can allocate if the `Yes.allocateGC` flag is passed. This has 2231 the benefit of have better complexity than the `Yes.allocateGC` option. However, 2232 this option is only available for ranges whose equality can be determined via each 2233 element's `toHash` method. If customized equality is needed, then the `pred` 2234 template parameter can be passed, and the function will automatically switch to 2235 the non-allocating algorithm. See $(REF binaryFun, std,functional) for more details on 2236 how to define `pred`. 2237 2238 Non-allocating forward range option: $(BIGOH n^2) 2239 Non-allocating forward range option with custom `pred`: $(BIGOH n^2) 2240 Allocating forward range option: amortized $(BIGOH r1.length) + $(BIGOH r2.length) 2241 2242 Params: 2243 pred = an optional parameter to change how equality is defined 2244 allocateGC = `Yes.allocateGC`/`No.allocateGC` 2245 r1 = A finite $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) 2246 r2 = A finite $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) 2247 2248 Returns: 2249 `true` if all of the elements in `r1` appear the same number of times in `r2`. 2250 Otherwise, returns `false`. 2251 */ 2252 2253 bool isPermutation(Flag!"allocateGC" allocateGC, Range1, Range2) 2254 (Range1 r1, Range2 r2) 2255 if (allocateGC == Yes.allocateGC && 2256 isForwardRange!Range1 && 2257 isForwardRange!Range2 && 2258 !isInfinite!Range1 && 2259 !isInfinite!Range2) 2260 { 2261 alias E1 = Unqual!(ElementType!Range1); 2262 alias E2 = Unqual!(ElementType!Range2); 2263 2264 if (!isSameLength(r1.save, r2.save)) 2265 { 2266 return false; 2267 } 2268 2269 // Skip the elements at the beginning where r1.front == r2.front, 2270 // they are in the same order and don't need to be counted. 2271 while (!r1.empty && !r2.empty && r1.front == r2.front) 2272 { 2273 r1.popFront(); 2274 r2.popFront(); 2275 } 2276 2277 if (r1.empty && r2.empty) 2278 { 2279 return true; 2280 } 2281 2282 int[CommonType!(E1, E2)] counts; 2283 2284 foreach (item; r1) 2285 { 2286 ++counts[item]; 2287 } 2288 2289 foreach (item; r2) 2290 { 2291 if (--counts[item] < 0) 2292 { 2293 return false; 2294 } 2295 } 2296 2297 return true; 2298 } 2299 2300 /// ditto 2301 bool isPermutation(alias pred = "a == b", Range1, Range2) 2302 (Range1 r1, Range2 r2) 2303 if (is(typeof(binaryFun!(pred))) && 2304 isForwardRange!Range1 && 2305 isForwardRange!Range2 && 2306 !isInfinite!Range1 && 2307 !isInfinite!Range2) 2308 { 2309 import std.algorithm.searching : count; 2310 2311 alias predEquals = binaryFun!(pred); 2312 alias E1 = Unqual!(ElementType!Range1); 2313 alias E2 = Unqual!(ElementType!Range2); 2314 2315 if (!isSameLength(r1.save, r2.save)) 2316 { 2317 return false; 2318 } 2319 2320 // Skip the elements at the beginning where r1.front == r2.front, 2321 // they are in the same order and don't need to be counted. 2322 while (!r1.empty && !r2.empty && predEquals(r1.front, r2.front)) 2323 { 2324 r1.popFront(); 2325 r2.popFront(); 2326 } 2327 2328 if (r1.empty && r2.empty) 2329 { 2330 return true; 2331 } 2332 2333 size_t r1_count; 2334 size_t r2_count; 2335 2336 // At each element item, when computing the count of item, scan it while 2337 // also keeping track of the scanning index. If the first occurrence 2338 // of item in the scanning loop has an index smaller than the current index, 2339 // then you know that the element has been seen before 2340 size_t index; 2341 outloop: for (auto r1s1 = r1.save; !r1s1.empty; r1s1.popFront, index++) 2342 { 2343 auto item = r1s1.front; 2344 r1_count = 0; 2345 r2_count = 0; 2346 2347 size_t i; 2348 for (auto r1s2 = r1.save; !r1s2.empty; r1s2.popFront, i++) 2349 { 2350 auto e = r1s2.front; 2351 if (predEquals(e, item) && i < index) 2352 { 2353 continue outloop; 2354 } 2355 else if (predEquals(e, item)) 2356 { 2357 ++r1_count; 2358 } 2359 } 2360 2361 r2_count = r2.save.count!pred(item); 2362 2363 if (r1_count != r2_count) 2364 { 2365 return false; 2366 } 2367 } 2368 2369 return true; 2370 } 2371 2372 /// 2373 @safe pure unittest 2374 { 2375 import std.typecons : Yes; 2376 2377 assert(isPermutation([1, 2, 3], [3, 2, 1])); 2378 assert(isPermutation([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); 2379 assert(isPermutation("abc", "bca")); 2380 2381 assert(!isPermutation([1, 2], [3, 4])); 2382 assert(!isPermutation([1, 1, 2, 3], [1, 2, 2, 3])); 2383 assert(!isPermutation([1, 1], [1, 1, 1])); 2384 2385 // Faster, but allocates GC handled memory 2386 assert(isPermutation!(Yes.allocateGC)([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); 2387 assert(!isPermutation!(Yes.allocateGC)([1, 2], [3, 4])); 2388 } 2389 2390 // Test @nogc inference 2391 @safe @nogc pure unittest 2392 { 2393 static immutable arr1 = [1, 2, 3]; 2394 static immutable arr2 = [3, 2, 1]; 2395 assert(isPermutation(arr1, arr2)); 2396 2397 static immutable arr3 = [1, 1, 2, 3]; 2398 static immutable arr4 = [1, 2, 2, 3]; 2399 assert(!isPermutation(arr3, arr4)); 2400 } 2401 2402 @safe pure unittest 2403 { 2404 import std.internal.test.dummyrange; 2405 2406 auto r1 = new ReferenceForwardRange!int([1, 2, 3, 4]); 2407 auto r2 = new ReferenceForwardRange!int([1, 2, 4, 3]); 2408 assert(isPermutation(r1, r2)); 2409 2410 auto r3 = new ReferenceForwardRange!int([1, 2, 3, 4]); 2411 auto r4 = new ReferenceForwardRange!int([4, 2, 1, 3]); 2412 assert(isPermutation!(Yes.allocateGC)(r3, r4)); 2413 2414 auto r5 = new ReferenceForwardRange!int([1, 2, 3]); 2415 auto r6 = new ReferenceForwardRange!int([4, 2, 1, 3]); 2416 assert(!isPermutation(r5, r6)); 2417 2418 auto r7 = new ReferenceForwardRange!int([4, 2, 1, 3]); 2419 auto r8 = new ReferenceForwardRange!int([1, 2, 3]); 2420 assert(!isPermutation!(Yes.allocateGC)(r7, r8)); 2421 2422 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r9; 2423 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r10; 2424 assert(isPermutation(r9, r10)); 2425 2426 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r11; 2427 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r12; 2428 assert(isPermutation!(Yes.allocateGC)(r11, r12)); 2429 2430 alias mytuple = Tuple!(int, int); 2431 2432 assert(isPermutation!"a[0] == b[0]"( 2433 [mytuple(1, 4), mytuple(2, 5)], 2434 [mytuple(2, 3), mytuple(1, 2)] 2435 )); 2436 } 2437 2438 /** 2439 Get the _first argument `a` that passes an `if (unaryFun!pred(a))` test. If 2440 no argument passes the test, return the last argument. 2441 2442 Similar to behaviour of the `or` operator in dynamic languages such as Lisp's 2443 `(or ...)` and Python's `a or b or ...` except that the last argument is 2444 returned upon no match. 2445 2446 Simplifies logic, for instance, in parsing rules where a set of alternative 2447 matchers are tried. The _first one that matches returns it match result, 2448 typically as an abstract syntax tree (AST). 2449 2450 Bugs: 2451 Lazy parameters are currently, too restrictively, inferred by DMD to 2452 always throw even though they don't need to be. This makes it impossible to 2453 currently mark `either` as `nothrow`. See issue at $(BUGZILLA 12647). 2454 2455 Returns: 2456 The _first argument that passes the test `pred`. 2457 */ 2458 CommonType!(T, Ts) either(alias pred = a => a, T, Ts...)(T first, lazy Ts alternatives) 2459 if (alternatives.length >= 1 && 2460 !is(CommonType!(T, Ts) == void) && 2461 allSatisfy!(ifTestable, T, Ts)) 2462 { 2463 alias predFun = unaryFun!pred; 2464 2465 if (predFun(first)) return first; 2466 2467 foreach (e; alternatives[0 .. $ - 1]) 2468 if (predFun(e)) return e; 2469 2470 return alternatives[$ - 1]; 2471 } 2472 2473 /// 2474 @safe pure @betterC unittest 2475 { 2476 const a = 1; 2477 const b = 2; 2478 auto ab = either(a, b); 2479 static assert(is(typeof(ab) == const(int))); 2480 assert(ab == a); 2481 2482 auto c = 2; 2483 const d = 3; 2484 auto cd = either!(a => a == 3)(c, d); // use predicate 2485 static assert(is(typeof(cd) == int)); 2486 assert(cd == d); 2487 2488 auto e = 0; 2489 const f = 2; 2490 auto ef = either(e, f); 2491 static assert(is(typeof(ef) == int)); 2492 assert(ef == f); 2493 } 2494 2495 /// 2496 @safe pure unittest 2497 { 2498 immutable p = 1; 2499 immutable q = 2; 2500 auto pq = either(p, q); 2501 static assert(is(typeof(pq) == immutable(int))); 2502 assert(pq == p); 2503 2504 assert(either(3, 4) == 3); 2505 assert(either(0, 4) == 4); 2506 assert(either(0, 0) == 0); 2507 assert(either("", "a") == ""); 2508 } 2509 2510 /// 2511 @safe pure unittest 2512 { 2513 string r = null; 2514 assert(either(r, "a") == "a"); 2515 assert(either("a", "") == "a"); 2516 2517 immutable s = [1, 2]; 2518 assert(either(s, s) == s); 2519 2520 assert(either([0, 1], [1, 2]) == [0, 1]); 2521 assert(either([0, 1], [1]) == [0, 1]); 2522 assert(either("a", "b") == "a"); 2523 2524 static assert(!__traits(compiles, either(1, "a"))); 2525 static assert(!__traits(compiles, either(1.0, "a"))); 2526 static assert(!__traits(compiles, either('a', "a"))); 2527 }