1 // Written in the D programming language. 2 /** 3 This is a submodule of $(MREF std, algorithm). 4 It contains generic searching algorithms. 5 6 $(SCRIPT inhibitQuickIndex = 1;) 7 $(BOOKTABLE Cheat Sheet, 8 $(TR $(TH Function Name) $(TH Description)) 9 $(T2 all, 10 `all!"a > 0"([1, 2, 3, 4])` returns `true` because all elements 11 are positive) 12 $(T2 any, 13 `any!"a > 0"([1, 2, -3, -4])` returns `true` because at least one 14 element is positive) 15 $(T2 balancedParens, 16 `balancedParens("((1 + 1) / 2)", '(', ')')` returns `true` because the 17 string has balanced parentheses.) 18 $(T2 boyerMooreFinder, 19 `find("hello world", boyerMooreFinder("or"))` returns `"orld"` 20 using the $(LINK2 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm, 21 Boyer-Moore _algorithm).) 22 $(T2 canFind, 23 `canFind("hello world", "or")` returns `true`.) 24 $(T2 count, 25 Counts all elements or elements matching a predicate, specific element or sub-range.$(BR) 26 `count([1, 2, 1])` returns `3`, 27 `count([1, 2, 1], 1)` returns `2` and 28 `count!"a < 0"([1, -3, 0])` returns `1`.) 29 $(T2 countUntil, 30 `countUntil(a, b)` returns the number of steps taken in `a` to 31 reach `b`; for example, `countUntil("hello!", "o")` returns 32 `4`.) 33 $(T2 commonPrefix, 34 `commonPrefix("parakeet", "parachute")` returns `"para"`.) 35 $(T2 endsWith, 36 `endsWith("rocks", "ks")` returns `true`.) 37 $(T2 extrema, `extrema([2, 1, 3, 5, 4])` returns `[1, 5]`.) 38 $(T2 find, 39 `find("hello world", "or")` returns `"orld"` using linear search. 40 (For binary search refer to $(REF SortedRange, std,range).)) 41 $(T2 findAdjacent, 42 `findAdjacent([1, 2, 3, 3, 4])` returns the subrange starting with 43 two equal adjacent elements, i.e. `[3, 3, 4]`.) 44 $(T2 findAmong, 45 `findAmong("abcd", "qcx")` returns `"cd"` because `'c'` is 46 among `"qcx"`.) 47 $(T2 findSkip, 48 If `a = "abcde"`, then `findSkip(a, "x")` returns `false` and 49 leaves `a` unchanged, whereas `findSkip(a, "c")` advances `a` 50 to `"de"` and returns `true`.) 51 $(T2 findSplit, 52 `findSplit("abcdefg", "de")` returns a tuple of three ranges `"abc"`, 53 `"de"`, and `"fg"`.) 54 $(T2 findSplitAfter, 55 `findSplitAfter("abcdefg", "de")` returns a tuple of two ranges `"abcde"` 56 and `"fg"`.) 57 $(T2 findSplitBefore, 58 `findSplitBefore("abcdefg", "de")` returns a tuple of two ranges `"abc"` 59 and `"defg"`.) 60 $(T2 minCount, 61 `minCount([2, 1, 1, 4, 1])` returns `tuple(1, 3)`.) 62 $(T2 maxCount, 63 `maxCount([2, 4, 1, 4, 1])` returns `tuple(4, 2)`.) 64 $(T2 minElement, 65 Selects the minimal element of a range. 66 `minElement([3, 4, 1, 2])` returns `1`.) 67 $(T2 maxElement, 68 Selects the maximal element of a range. 69 `maxElement([3, 4, 1, 2])` returns `4`.) 70 $(T2 minIndex, 71 Index of the minimal element of a range. 72 `minIndex([3, 4, 1, 2])` returns `2`.) 73 $(T2 maxIndex, 74 Index of the maximal element of a range. 75 `maxIndex([3, 4, 1, 2])` returns `1`.) 76 $(T2 minPos, 77 `minPos([2, 3, 1, 3, 4, 1])` returns the subrange `[1, 3, 4, 1]`, 78 i.e., positions the range at the first occurrence of its minimal 79 element.) 80 $(T2 maxPos, 81 `maxPos([2, 3, 1, 3, 4, 1])` returns the subrange `[4, 1]`, 82 i.e., positions the range at the first occurrence of its maximal 83 element.) 84 $(T2 skipOver, 85 Assume `a = "blah"`. Then `skipOver(a, "bi")` leaves `a` 86 unchanged and returns `false`, whereas `skipOver(a, "bl")` 87 advances `a` to refer to `"ah"` and returns `true`.) 88 $(T2 startsWith, 89 `startsWith("hello, world", "hello")` returns `true`.) 90 $(T2 until, 91 Lazily iterates a range until a specific value is found.) 92 ) 93 94 Copyright: Andrei Alexandrescu 2008-. 95 96 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 97 98 Authors: $(HTTP erdani.com, Andrei Alexandrescu) 99 100 Source: $(PHOBOSSRC std/algorithm/searching.d) 101 102 Macros: 103 T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) 104 */ 105 module std.algorithm.searching; 106 107 import std.functional : unaryFun, binaryFun; 108 import std.meta : allSatisfy; 109 import std.range.primitives; 110 import std.traits; 111 import std.typecons : Tuple, Flag, Yes, No, tuple; 112 113 /++ 114 Checks if $(I _all) of the elements satisfy `pred`. 115 +/ 116 template all(alias pred = "a") 117 { 118 /++ 119 Returns `true` if and only if the input range `range` is empty 120 or $(I _all) values found in `range` satisfy the predicate `pred`. 121 Performs (at most) $(BIGOH range.length) evaluations of `pred`. 122 +/ 123 bool all(Range)(Range range) 124 if (isInputRange!Range && 125 (__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front))))) 126 { 127 import std.functional : not; 128 129 return find!(not!(unaryFun!pred))(range).empty; 130 } 131 } 132 133 /// 134 @safe unittest 135 { 136 assert( all!"a & 1"([1, 3, 5, 7, 9])); 137 assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); 138 } 139 140 /++ 141 `all` can also be used without a predicate, if its items can be 142 evaluated to true or false in a conditional statement. This can be a 143 convenient way to quickly evaluate that $(I _all) of the elements of a range 144 are true. 145 +/ 146 @safe unittest 147 { 148 int[3] vals = [5, 3, 18]; 149 assert( all(vals[])); 150 } 151 152 @safe unittest 153 { 154 int x = 1; 155 assert(all!(a => a > x)([2, 3])); 156 assert(all!"a == 0x00c9"("\xc3\x89")); // Test that `all` auto-decodes. 157 } 158 159 /++ 160 Checks if $(I _any) of the elements satisfies `pred`. 161 `!any` can be used to verify that $(I none) of the elements satisfy 162 `pred`. 163 This is sometimes called `exists` in other languages. 164 +/ 165 template any(alias pred = "a") 166 { 167 /++ 168 Returns `true` if and only if the input range `range` is non-empty 169 and $(I _any) value found in `range` satisfies the predicate 170 `pred`. 171 Performs (at most) $(BIGOH range.length) evaluations of `pred`. 172 +/ 173 bool any(Range)(Range range) 174 if (isInputRange!Range && 175 (__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front))))) 176 { 177 return !find!pred(range).empty; 178 } 179 } 180 181 /// 182 @safe unittest 183 { 184 import std.ascii : isWhite; 185 assert( all!(any!isWhite)(["a a", "b b"])); 186 assert(!any!(all!isWhite)(["a a", "b b"])); 187 } 188 189 /++ 190 `any` can also be used without a predicate, if its items can be 191 evaluated to true or false in a conditional statement. `!any` can be a 192 convenient way to quickly test that $(I none) of the elements of a range 193 evaluate to true. 194 +/ 195 @safe unittest 196 { 197 int[3] vals1 = [0, 0, 0]; 198 assert(!any(vals1[])); //none of vals1 evaluate to true 199 200 int[3] vals2 = [2, 0, 2]; 201 assert( any(vals2[])); 202 assert(!all(vals2[])); 203 204 int[3] vals3 = [3, 3, 3]; 205 assert( any(vals3[])); 206 assert( all(vals3[])); 207 } 208 209 @safe unittest 210 { 211 auto a = [ 1, 2, 0, 4 ]; 212 assert(any!"a == 2"(a)); 213 assert(any!"a == 0x3000"("\xe3\x80\x80")); // Test that `any` auto-decodes. 214 } 215 216 // balancedParens 217 /** 218 Checks whether `r` has "balanced parentheses", i.e. all instances 219 of `lPar` are closed by corresponding instances of `rPar`. The 220 parameter `maxNestingLevel` controls the nesting level allowed. The 221 most common uses are the default or `0`. In the latter case, no 222 nesting is allowed. 223 224 Params: 225 r = The range to check. 226 lPar = The element corresponding with a left (opening) parenthesis. 227 rPar = The element corresponding with a right (closing) parenthesis. 228 maxNestingLevel = The maximum allowed nesting level. 229 230 Returns: 231 true if the given range has balanced parenthesis within the given maximum 232 nesting level; false otherwise. 233 */ 234 bool balancedParens(Range, E)(Range r, E lPar, E rPar, 235 size_t maxNestingLevel = size_t.max) 236 if (isInputRange!(Range) && is(typeof(r.front == lPar))) 237 { 238 size_t count; 239 240 static if (is(immutable ElementEncodingType!Range == immutable E) && isNarrowString!Range) 241 { 242 import std.utf : byCodeUnit; 243 auto rn = r.byCodeUnit; 244 } 245 else 246 { 247 alias rn = r; 248 } 249 250 for (; !rn.empty; rn.popFront()) 251 { 252 if (rn.front == lPar) 253 { 254 if (count > maxNestingLevel) return false; 255 ++count; 256 } 257 else if (rn.front == rPar) 258 { 259 if (!count) return false; 260 --count; 261 } 262 } 263 return count == 0; 264 } 265 266 /// 267 @safe pure unittest 268 { 269 auto s = "1 + (2 * (3 + 1 / 2)"; 270 assert(!balancedParens(s, '(', ')')); 271 s = "1 + (2 * (3 + 1) / 2)"; 272 assert(balancedParens(s, '(', ')')); 273 s = "1 + (2 * (3 + 1) / 2)"; 274 assert(!balancedParens(s, '(', ')', 0)); 275 s = "1 + (2 * 3 + 1) / (2 - 5)"; 276 assert(balancedParens(s, '(', ')', 0)); 277 s = "f(x) = ⌈x⌉"; 278 assert(balancedParens(s, '⌈', '⌉')); 279 } 280 281 /** 282 * Sets up Boyer-Moore matching for use with `find` below. 283 * By default, elements are compared for equality. 284 * 285 * `BoyerMooreFinder` allocates GC memory. 286 * 287 * Params: 288 * pred = Predicate used to compare elements. 289 * needle = A random-access range with length and slicing. 290 * 291 * Returns: 292 * An instance of `BoyerMooreFinder` that can be used with `find()` to 293 * invoke the Boyer-Moore matching algorithm for finding of `needle` in a 294 * given haystack. 295 */ 296 struct BoyerMooreFinder(alias pred, Range) 297 { 298 private: 299 size_t[] skip; // GC allocated 300 ptrdiff_t[ElementType!(Range)] occ; // GC allocated 301 Range needle; 302 303 ptrdiff_t occurrence(ElementType!(Range) c) scope 304 { 305 auto p = c in occ; 306 return p ? *p : -1; 307 } 308 309 /* 310 This helper function checks whether the last "portion" bytes of 311 "needle" (which is "nlen" bytes long) exist within the "needle" at 312 offset "offset" (counted from the end of the string), and whether the 313 character preceding "offset" is not a match. Notice that the range 314 being checked may reach beyond the beginning of the string. Such range 315 is ignored. 316 */ 317 static bool needlematch(R)(R needle, 318 size_t portion, size_t offset) 319 { 320 import std.algorithm.comparison : equal; 321 ptrdiff_t virtual_begin = needle.length - offset - portion; 322 ptrdiff_t ignore = 0; 323 if (virtual_begin < 0) 324 { 325 ignore = -virtual_begin; 326 virtual_begin = 0; 327 } 328 if (virtual_begin > 0 329 && needle[virtual_begin - 1] == needle[$ - portion - 1]) 330 return 0; 331 332 immutable delta = portion - ignore; 333 return equal(needle[needle.length - delta .. needle.length], 334 needle[virtual_begin .. virtual_begin + delta]); 335 } 336 337 public: 338 /// 339 this(Range needle) 340 { 341 if (!needle.length) return; 342 this.needle = needle; 343 /* Populate table with the analysis of the needle */ 344 /* But ignoring the last letter */ 345 foreach (i, n ; needle[0 .. $ - 1]) 346 { 347 this.occ[n] = i; 348 } 349 /* Preprocess #2: init skip[] */ 350 /* Note: This step could be made a lot faster. 351 * A simple implementation is shown here. */ 352 this.skip = new size_t[needle.length]; 353 foreach (a; 0 .. needle.length) 354 { 355 size_t value = 0; 356 while (value < needle.length 357 && !needlematch(needle, a, value)) 358 { 359 ++value; 360 } 361 this.skip[needle.length - a - 1] = value; 362 } 363 } 364 365 /// 366 Range beFound(Range haystack) scope 367 { 368 import std.algorithm.comparison : max; 369 370 if (!needle.length) return haystack; 371 if (needle.length > haystack.length) return haystack[$ .. $]; 372 /* Search: */ 373 immutable limit = haystack.length - needle.length; 374 for (size_t hpos = 0; hpos <= limit; ) 375 { 376 size_t npos = needle.length - 1; 377 while (pred(needle[npos], haystack[npos+hpos])) 378 { 379 if (npos == 0) return haystack[hpos .. $]; 380 --npos; 381 } 382 hpos += max(skip[npos], cast(ptrdiff_t) npos - occurrence(haystack[npos+hpos])); 383 } 384 return haystack[$ .. $]; 385 } 386 387 /// 388 @property size_t length() 389 { 390 return needle.length; 391 } 392 393 /// 394 alias opDollar = length; 395 } 396 397 /// Ditto 398 BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder 399 (alias pred = "a == b", Range) 400 (Range needle) 401 if ((isRandomAccessRange!(Range) && hasSlicing!Range) || isSomeString!Range) 402 { 403 return typeof(return)(needle); 404 } 405 406 /// 407 @safe pure nothrow unittest 408 { 409 auto bmFinder = boyerMooreFinder("TG"); 410 411 string r = "TAGTGCCTGA"; 412 // search for the first match in the haystack r 413 r = bmFinder.beFound(r); 414 assert(r == "TGCCTGA"); 415 416 // continue search in haystack 417 r = bmFinder.beFound(r[2 .. $]); 418 assert(r == "TGA"); 419 } 420 421 /** 422 Returns the common prefix of two ranges. 423 424 Params: 425 pred = The predicate to use in comparing elements for commonality. Defaults 426 to equality `"a == b"`. 427 428 r1 = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) of 429 elements. 430 431 r2 = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of 432 elements. 433 434 Returns: 435 A slice of `r1` which contains the characters that both ranges start with, 436 if the first argument is a string; otherwise, the same as the result of 437 `takeExactly(r1, n)`, where `n` is the number of elements in the common 438 prefix of both ranges. 439 440 See_Also: 441 $(REF takeExactly, std,range) 442 */ 443 auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2) 444 if (isForwardRange!R1 && isInputRange!R2 && 445 !isNarrowString!R1 && 446 is(typeof(binaryFun!pred(r1.front, r2.front)))) 447 { 448 import std.algorithm.comparison : min; 449 static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && 450 hasLength!R1 && hasLength!R2 && 451 hasSlicing!R1) 452 { 453 immutable limit = min(r1.length, r2.length); 454 foreach (i; 0 .. limit) 455 { 456 if (!binaryFun!pred(r1[i], r2[i])) 457 { 458 return r1[0 .. i]; 459 } 460 } 461 return r1[0 .. limit]; 462 } 463 else 464 { 465 import std.range : takeExactly; 466 auto result = r1.save; 467 size_t i = 0; 468 for (; 469 !r1.empty && !r2.empty && binaryFun!pred(r1.front, r2.front); 470 ++i, r1.popFront(), r2.popFront()) 471 {} 472 return takeExactly(result, i); 473 } 474 } 475 476 /// 477 @safe unittest 478 { 479 assert(commonPrefix("hello, world", "hello, there") == "hello, "); 480 } 481 482 /// ditto 483 auto commonPrefix(alias pred, R1, R2)(R1 r1, R2 r2) 484 if (isNarrowString!R1 && isInputRange!R2 && 485 is(typeof(binaryFun!pred(r1.front, r2.front)))) 486 { 487 import std.utf : decode; 488 489 auto result = r1.save; 490 immutable len = r1.length; 491 size_t i = 0; 492 493 for (size_t j = 0; i < len && !r2.empty; r2.popFront(), i = j) 494 { 495 immutable f = decode(r1, j); 496 if (!binaryFun!pred(f, r2.front)) 497 break; 498 } 499 500 return result[0 .. i]; 501 } 502 503 /// ditto 504 auto commonPrefix(R1, R2)(R1 r1, R2 r2) 505 if (isNarrowString!R1 && isInputRange!R2 && !isNarrowString!R2 && 506 is(typeof(r1.front == r2.front))) 507 { 508 return commonPrefix!"a == b"(r1, r2); 509 } 510 511 /// ditto 512 auto commonPrefix(R1, R2)(R1 r1, R2 r2) 513 if (isNarrowString!R1 && isNarrowString!R2) 514 { 515 import std.algorithm.comparison : min; 516 517 static if (ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof) 518 { 519 import std.utf : stride, UTFException; 520 521 immutable limit = min(r1.length, r2.length); 522 for (size_t i = 0; i < limit;) 523 { 524 immutable codeLen = stride(r1, i); 525 size_t j = 0; 526 527 for (; j < codeLen && i < limit; ++i, ++j) 528 { 529 if (r1[i] != r2[i]) 530 return r1[0 .. i - j]; 531 } 532 533 if (i == limit && j < codeLen) 534 throw new UTFException("Invalid UTF-8 sequence", i); 535 } 536 return r1[0 .. limit]; 537 } 538 else 539 return commonPrefix!"a == b"(r1, r2); 540 } 541 542 @safe unittest 543 { 544 import std.algorithm.comparison : equal; 545 import std.algorithm.iteration : filter; 546 import std.conv : to; 547 import std.exception : assertThrown; 548 import std.meta : AliasSeq; 549 import std.range; 550 import std.utf : UTFException; 551 552 assert(commonPrefix([1, 2, 3], [1, 2, 3, 4, 5]) == [1, 2, 3]); 553 assert(commonPrefix([1, 2, 3, 4, 5], [1, 2, 3]) == [1, 2, 3]); 554 assert(commonPrefix([1, 2, 3, 4], [1, 2, 3, 4]) == [1, 2, 3, 4]); 555 assert(commonPrefix([1, 2, 3], [7, 2, 3, 4, 5]).empty); 556 assert(commonPrefix([7, 2, 3, 4, 5], [1, 2, 3]).empty); 557 assert(commonPrefix([1, 2, 3], cast(int[]) null).empty); 558 assert(commonPrefix(cast(int[]) null, [1, 2, 3]).empty); 559 assert(commonPrefix(cast(int[]) null, cast(int[]) null).empty); 560 561 static foreach (S; AliasSeq!(char[], const(char)[], string, 562 wchar[], const(wchar)[], wstring, 563 dchar[], const(dchar)[], dstring)) 564 { 565 static foreach (T; AliasSeq!(string, wstring, dstring)) 566 { 567 assert(commonPrefix(to!S(""), to!T("")).empty); 568 assert(commonPrefix(to!S(""), to!T("hello")).empty); 569 assert(commonPrefix(to!S("hello"), to!T("")).empty); 570 assert(commonPrefix(to!S("hello, world"), to!T("hello, there")) == to!S("hello, ")); 571 assert(commonPrefix(to!S("hello, there"), to!T("hello, world")) == to!S("hello, ")); 572 assert(commonPrefix(to!S("hello, "), to!T("hello, world")) == to!S("hello, ")); 573 assert(commonPrefix(to!S("hello, world"), to!T("hello, ")) == to!S("hello, ")); 574 assert(commonPrefix(to!S("hello, world"), to!T("hello, world")) == to!S("hello, world")); 575 576 // https://issues.dlang.org/show_bug.cgi?id=8890 577 assert(commonPrefix(to!S("Пиво"), to!T("Пони"))== to!S("П")); 578 assert(commonPrefix(to!S("Пони"), to!T("Пиво"))== to!S("П")); 579 assert(commonPrefix(to!S("Пиво"), to!T("Пиво"))== to!S("Пиво")); 580 assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFE"), 581 to!T("\U0010FFFF\U0010FFFB\U0010FFFC")) == to!S("\U0010FFFF\U0010FFFB")); 582 assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFC"), 583 to!T("\U0010FFFF\U0010FFFB\U0010FFFE")) == to!S("\U0010FFFF\U0010FFFB")); 584 assert(commonPrefix!"a != b"(to!S("Пиво"), to!T("онво")) == to!S("Пи")); 585 assert(commonPrefix!"a != b"(to!S("онво"), to!T("Пиво")) == to!S("он")); 586 } 587 588 static assert(is(typeof(commonPrefix(to!S("Пиво"), filter!"true"("Пони"))) == S)); 589 assert(equal(commonPrefix(to!S("Пиво"), filter!"true"("Пони")), to!S("П"))); 590 591 static assert(is(typeof(commonPrefix(filter!"true"("Пиво"), to!S("Пони"))) == 592 typeof(takeExactly(filter!"true"("П"), 1)))); 593 assert(equal(commonPrefix(filter!"true"("Пиво"), to!S("Пони")), takeExactly(filter!"true"("П"), 1))); 594 } 595 596 assertThrown!UTFException(commonPrefix("\U0010FFFF\U0010FFFB", "\U0010FFFF\U0010FFFB"[0 .. $ - 1])); 597 598 assert(commonPrefix("12345"d, [49, 50, 51, 60, 60]) == "123"d); 599 assert(commonPrefix([49, 50, 51, 60, 60], "12345" ) == [49, 50, 51]); 600 assert(commonPrefix([49, 50, 51, 60, 60], "12345"d) == [49, 50, 51]); 601 602 assert(commonPrefix!"a == ('0' + b)"("12345" , [1, 2, 3, 9, 9]) == "123"); 603 assert(commonPrefix!"a == ('0' + b)"("12345"d, [1, 2, 3, 9, 9]) == "123"d); 604 assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345" ) == [1, 2, 3]); 605 assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345"d) == [1, 2, 3]); 606 } 607 608 // count 609 /** 610 Counts matches of `needle` in `haystack`. 611 612 The first overload counts each element `e` in `haystack` for 613 which `pred(e, needle)` is `true`. `pred` defaults to 614 equality. Performs $(BIGOH haystack.length) evaluations of `pred`. 615 616 The second overload counts the number of times `needle` was matched in 617 `haystack`. `pred` compares elements in each range. 618 Throws an exception if `needle.empty` is `true`, as the _count 619 of the empty range in any range would be infinite. Overlapped counts 620 are *not* considered, for example `count("aaa", "aa")` is `1`, not 621 `2`. 622 623 Note: Regardless of the overload, `count` will not accept 624 infinite ranges for `haystack`. 625 626 Params: 627 pred = The predicate to compare elements. 628 haystack = The range to _count. 629 needle = The element or sub-range to _count in `haystack`. 630 631 Returns: 632 The number of matches in `haystack`. 633 */ 634 size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle) 635 if (isInputRange!Range && !isInfinite!Range && 636 is(typeof(binaryFun!pred(haystack.front, needle)))) 637 { 638 bool pred2(ElementType!Range a) { return binaryFun!pred(a, needle); } 639 return count!pred2(haystack); 640 } 641 642 /// 643 @safe unittest 644 { 645 // count elements in range 646 int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; 647 assert(count(a, 2) == 3); 648 assert(count!("a > b")(a, 2) == 5); 649 } 650 651 /// 652 @safe unittest 653 { 654 import std.uni : toLower; 655 // count range in range 656 assert(count("abcadfabf", "ab") == 2); 657 assert(count("ababab", "abab") == 1); 658 assert(count("ababab", "abx") == 0); 659 // fuzzy count range in range 660 assert(count!((a, b) => toLower(a) == toLower(b))("AbcAdFaBf", "ab") == 2); 661 } 662 663 @safe unittest 664 { 665 import std.conv : text; 666 667 int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; 668 assert(count(a, 2) == 3, text(count(a, 2))); 669 assert(count!("a > b")(a, 2) == 5, text(count!("a > b")(a, 2))); 670 671 // check strings 672 assert(count("日本語") == 3); 673 assert(count("日本語"w) == 3); 674 assert(count("日本語"d) == 3); 675 676 assert(count!("a == '日'")("日本語") == 1); 677 assert(count!("a == '本'")("日本語"w) == 1); 678 assert(count!("a == '語'")("日本語"d) == 1); 679 } 680 681 @safe unittest 682 { 683 string s = "This is a fofofof list"; 684 string sub = "fof"; 685 assert(count(s, sub) == 2); 686 } 687 688 /// Ditto 689 size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 690 if (isForwardRange!R1 && !isInfinite!R1 && 691 isForwardRange!R2 && 692 is(typeof(binaryFun!pred(haystack.front, needle.front)))) 693 { 694 assert(!needle.empty, "Cannot count occurrences of an empty range"); 695 696 static if (isInfinite!R2) 697 { 698 //Note: This is the special case of looking for an infinite inside a finite... 699 //"How many instances of the Fibonacci sequence can you count in [1, 2, 3]?" - "None." 700 return 0; 701 } 702 else 703 { 704 size_t result; 705 //Note: haystack is not saved, because findskip is designed to modify it 706 for ( ; findSkip!pred(haystack, needle.save) ; ++result) 707 {} 708 return result; 709 } 710 } 711 712 /** 713 Counts all elements or elements satisfying a predicate in `haystack`. 714 715 The first overload counts each element `e` in `haystack` for which `pred(e)` is $(D 716 true). Performs $(BIGOH haystack.length) evaluations of `pred`. 717 718 The second overload counts the number of elements in a range. 719 If the given range has the `length` property, 720 that is returned right away, otherwise 721 performs $(BIGOH haystack.length) to walk the range. 722 723 Params: 724 pred = Optional predicate to find elements. 725 haystack = The range to _count. 726 727 Returns: 728 The number of elements in `haystack` (for which `pred` returned true). 729 */ 730 size_t count(alias pred, R)(R haystack) 731 if (isInputRange!R && !isInfinite!R && 732 is(typeof(unaryFun!pred(haystack.front)))) 733 { 734 size_t result; 735 alias T = ElementType!R; //For narrow strings forces dchar iteration 736 foreach (T elem; haystack) 737 if (unaryFun!pred(elem)) ++result; 738 return result; 739 } 740 741 /// 742 @safe unittest 743 { 744 // count elements in range 745 int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; 746 assert(count(a) == 9); 747 // count predicate in range 748 assert(count!("a > 2")(a) == 5); 749 } 750 751 /// Ditto 752 size_t count(R)(R haystack) 753 if (isInputRange!R && !isInfinite!R) 754 { 755 return walkLength(haystack); 756 } 757 758 @safe unittest 759 { 760 int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; 761 assert(count!("a == 3")(a) == 2); 762 assert(count("日本語") == 3); 763 } 764 765 // https://issues.dlang.org/show_bug.cgi?id=11253 766 @safe nothrow unittest 767 { 768 assert([1, 2, 3].count([2, 3]) == 1); 769 } 770 771 // https://issues.dlang.org/show_bug.cgi?id=22582 772 @safe unittest 773 { 774 assert([1, 2, 3].count!"a & 1" == 2); 775 } 776 777 /++ 778 Counts elements in the given 779 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 780 until the given predicate is true for one of the given `needles` or `needle`. 781 782 Params: 783 pred = Binary predicate for determining when to stop counting, 784 which will be passed each element of `haystack` and a needle. 785 haystack = The 786 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be 787 counted. Must be a 788 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to 789 use multiple needles. 790 needles = A sequence of values or 791 $(REF_ALTTEXT forward ranges, isForwardRange, std,range,primitives) 792 of values, to be evaluated in turn by calling `pred(element, needle)` 793 with each element of `haystack`. 794 needle = A value passed as the 2nd argument to `pred`. 795 796 Returns: 797 - The number of elements which must be popped from the front of 798 `haystack` before reaching an element for which 799 $(LREF startsWith)`!pred(haystack, needles)` is `true`. 800 - If 801 `startsWith!pred(haystack, needles)` is not `true` for any element in 802 `haystack`, then `-1` is returned. 803 - If more than one needle is provided, 804 `countUntil` will wrap the result in a pseudo-tuple similar to 805 `Tuple!(ptrdiff_t, "steps", ptrdiff_t, "needle")`. 806 - `steps` is the count value, which can be implicitly tested for equality. 807 - `needle` is the index into `needles` which matched. 808 - Both are `-1` if there was no match. 809 810 Warning: Due to $(LINK2 https://tour.dlang.org/tour/en/gems/unicode, 811 auto-decoding), the return value of this function may $(I not) correspond 812 to the array index for strings. To find the index of an element matching 813 the predicate in a string, use $(REF indexOf, std,string) instead. 814 815 See_Also: $(REF indexOf, std,string) 816 +/ 817 auto countUntil(alias pred = "a == b", R, Rs...)(R haystack, Rs needles) 818 if (isForwardRange!R 819 && Rs.length > 0 820 && isForwardRange!(Rs[0]) == isInputRange!(Rs[0]) 821 && allSatisfy!(canTestStartsWith!(pred, R), Rs)) 822 { 823 static if (needles.length == 1) 824 { 825 static if (hasLength!R) //Note: Narrow strings don't have length. 826 { 827 //We delegate to find because find is very efficient. 828 //We store the length of the haystack so we don't have to save it. 829 auto len = haystack.length; 830 auto r2 = find!pred(haystack, needles[0]); 831 if (!r2.empty) 832 return ptrdiff_t(len - r2.length); 833 } 834 else 835 { 836 import std.range : dropOne; 837 838 if (needles[0].empty) 839 return ptrdiff_t(0); 840 841 ptrdiff_t result; 842 843 //Default case, slower route doing startsWith iteration 844 for ( ; !haystack.empty ; ++result ) 845 { 846 //We compare the first elements of the ranges here before 847 //forwarding to startsWith. This avoids making useless saves to 848 //haystack/needle if they aren't even going to be mutated anyways. 849 //It also cuts down on the amount of pops on haystack. 850 if (binaryFun!pred(haystack.front, needles[0].front)) 851 { 852 //Here, we need to save the needle before popping it. 853 //haystack we pop in all paths, so we do that, and then save. 854 haystack.popFront(); 855 if (startsWith!pred(haystack.save, needles[0].save.dropOne())) 856 return result; 857 } 858 else 859 { 860 haystack.popFront(); 861 } 862 } 863 } 864 return ptrdiff_t(-1); 865 } 866 else 867 { 868 static struct Result 869 { 870 ptrdiff_t steps, needle; // both -1 when nothing was found 871 alias steps this; // compatible with previous ptrdiff_t return type 872 ptrdiff_t opIndex(size_t idx) // faking a tuple 873 { 874 assert(idx < 2, "Type has only two members: pos and needle"); 875 return idx == 0 ? steps : needle; 876 } 877 } 878 Result result; 879 880 foreach (i, Ri; Rs) 881 { 882 static if (isForwardRange!Ri) 883 { 884 if (needles[i].empty) 885 { 886 result.needle = i; 887 return result; 888 } 889 } 890 } 891 Tuple!Rs t; 892 foreach (i, Ri; Rs) 893 { 894 static if (!isForwardRange!Ri) 895 { 896 t[i] = needles[i]; 897 } 898 } 899 for (; !haystack.empty ; ++result.steps, haystack.popFront()) 900 { 901 foreach (i, Ri; Rs) 902 { 903 static if (isForwardRange!Ri) 904 { 905 t[i] = needles[i].save; 906 } 907 } 908 if (auto needle = startsWith!pred(haystack.save, t.expand)) 909 { 910 result.needle = needle - 1; 911 return result; 912 } 913 } 914 915 // no match was found 916 result.needle = -1; 917 result.steps = -1; 918 return result; 919 } 920 } 921 922 /// ditto 923 ptrdiff_t countUntil(alias pred = "a == b", R, N)(R haystack, N needle) 924 if (isInputRange!R && 925 is(typeof(binaryFun!pred(haystack.front, needle)) : bool)) 926 { 927 bool pred2(ElementType!R a) { return binaryFun!pred(a, needle); } 928 return countUntil!pred2(haystack); 929 } 930 931 /// 932 @safe unittest 933 { 934 assert(countUntil("hello world", "world") == 6); 935 assert(countUntil("hello world", 'r') == 8); 936 assert(countUntil("hello world", "programming") == -1); 937 assert(countUntil("日本語", "本語") == 1); 938 assert(countUntil("日本語", '語') == 2); 939 assert(countUntil("日本語", "五") == -1); 940 assert(countUntil("日本語", '五') == -1); 941 942 const arr = [0, 7, 12, 22, 9]; 943 assert(countUntil(arr, [12, 22]) == 2); 944 assert(countUntil(arr, 9) == 4); 945 assert(countUntil!"a > b"(arr, 20) == 3); 946 } 947 948 /// Multiple needles 949 @safe unittest 950 { 951 auto res = "...hello".countUntil("ha", "he"); 952 assert(res.steps == 3); 953 assert(res.needle == 1); // the 2nd needle matched 954 955 // returns -1 if no needle was found 956 res = "hello".countUntil("ha", "hu"); 957 assert(res.steps == -1); 958 assert(res.needle == -1); 959 960 // `steps` can also be implicitly compared 961 const arr = [0, 7, 12, 22, 9]; 962 assert(countUntil(arr, 22, 12) == 2); // `12` found after 2 elements 963 assert(countUntil(arr, 5, 6) == -1); 964 } 965 966 @safe unittest 967 { 968 import std.algorithm.iteration : filter; 969 import std.internal.test.dummyrange; 970 971 assert(countUntil("日本語", "") == 0); 972 assert(countUntil("日本語"d, "") == 0); 973 974 assert(countUntil("", "") == 0); 975 assert(countUntil("".filter!"true"(), "") == 0); 976 977 auto rf = [0, 20, 12, 22, 9].filter!"true"(); 978 assert(rf.countUntil!"a > b"((int[]).init) == 0); 979 assert(rf.countUntil!"a > b"(20) == 3); 980 assert(rf.countUntil!"a > b"([20, 8]) == 3); 981 assert(rf.countUntil!"a > b"([20, 10]) == -1); 982 assert(rf.countUntil!"a > b"([20, 8, 0]) == -1); 983 984 auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]); 985 auto r2 = new ReferenceForwardRange!int([3, 4]); 986 auto r3 = new ReferenceForwardRange!int([3, 5]); 987 assert(r.save.countUntil(3) == 3); 988 assert(r.save.countUntil(r2) == 3); 989 assert(r.save.countUntil(7) == -1); 990 assert(r.save.countUntil(r3) == -1); 991 } 992 993 @safe unittest 994 { 995 assert(countUntil("hello world", "world", "asd") == 6); 996 assert(countUntil("hello world", "world", "ello") == 1); 997 assert(countUntil("hello world", "world", "") == 0); 998 assert(countUntil("hello world", "world", 'l') == 2); 999 } 1000 1001 @safe unittest 1002 { 1003 auto res = "...hello".countUntil("hella", "hello"); 1004 assert(res == 3); 1005 assert(res.steps == 3); 1006 assert(res.needle == 1); 1007 // test tuple emulation 1008 assert(res[0] == 3); 1009 assert(res[1] == 1); 1010 1011 // the first matching needle is chosen 1012 res = "...hello".countUntil("hell", "hello"); 1013 assert(res == 3); 1014 assert(res.needle == 0); 1015 1016 // no match 1017 auto noMatch = "hello world".countUntil("ha", "hu"); 1018 assert(noMatch == -1); 1019 assert(noMatch.steps == -1); 1020 assert(noMatch.needle == -1); 1021 // test tuple emulation 1022 assert(noMatch[0] == -1); 1023 assert(noMatch[1] == -1); 1024 } 1025 1026 // test infinite ranges 1027 @safe unittest 1028 { 1029 import std.algorithm.iteration : joiner; 1030 import std.range : iota, repeat; 1031 import std.stdio; 1032 assert(10.iota.repeat.joiner.countUntil(9) == 9); 1033 assert(10.iota.repeat.joiner.countUntil(1, 2) == 1); 1034 assert(10.iota.repeat.joiner.countUntil!(a => a >= 9) == 9); 1035 } 1036 1037 /++ 1038 Counts elements in the given 1039 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 1040 until the given predicate is true for one of the elements of `haystack`. 1041 1042 Params: 1043 pred = Unary predicate for determining when to stop counting. 1044 haystack = The 1045 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be 1046 counted. 1047 1048 Returns: 1049 - The number of elements which must be popped from the front of 1050 `haystack` before reaching an element for which 1051 $(LREF startsWith)`!pred(haystack)` is `true`. 1052 - If `startsWith!pred(haystack)` is not `true` for any element in 1053 `haystack`, then `-1` is returned. 1054 1055 Warning: Due to $(LINK2 https://tour.dlang.org/tour/en/gems/unicode, 1056 auto-decoding), the return value of this function may $(I not) correspond 1057 to the array index for strings. To find the index of an element matching 1058 the predicate in a string, use $(REF indexOf, std,string) instead. 1059 +/ 1060 ptrdiff_t countUntil(alias pred, R)(R haystack) 1061 if (isInputRange!R && 1062 is(typeof(unaryFun!pred(haystack.front)) : bool)) 1063 { 1064 typeof(return) i; 1065 static if (isRandomAccessRange!R) 1066 { 1067 //Optimized RA implementation. Since we want to count *and* iterate at 1068 //the same time, it is more efficient this way. 1069 static if (hasLength!R) 1070 { 1071 immutable len = cast(typeof(return)) haystack.length; 1072 for ( ; i < len ; ++i ) 1073 if (unaryFun!pred(haystack[i])) return i; 1074 } 1075 else //if (isInfinite!R) 1076 { 1077 for ( ; ; ++i ) 1078 if (unaryFun!pred(haystack[i])) return i; 1079 } 1080 } 1081 else static if (hasLength!R) 1082 { 1083 //For those odd ranges that have a length, but aren't RA. 1084 //It is faster to quick find, and then compare the lengths 1085 auto r2 = find!pred(haystack.save); 1086 if (!r2.empty) return cast(typeof(return)) (haystack.length - r2.length); 1087 } 1088 else //Everything else 1089 { 1090 alias T = ElementType!R; //For narrow strings forces dchar iteration 1091 foreach (T elem; haystack) 1092 { 1093 if (unaryFun!pred(elem)) return i; 1094 ++i; 1095 } 1096 } 1097 1098 // Because of https://issues.dlang.org/show_bug.cgi?id=8804 1099 // Avoids both "unreachable code" or "no return statement" 1100 static if (isInfinite!R) assert(false, R.stringof ~ " must not be an" 1101 ~ " inifite range"); 1102 else return -1; 1103 } 1104 1105 /// 1106 @safe unittest 1107 { 1108 import std.ascii : isDigit; 1109 import std.uni : isWhite; 1110 1111 assert(countUntil!(isWhite)("hello world") == 5); 1112 assert(countUntil!(isDigit)("hello world") == -1); 1113 assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3); 1114 } 1115 1116 @safe unittest 1117 { 1118 import std.internal.test.dummyrange; 1119 1120 // References 1121 { 1122 // input 1123 ReferenceInputRange!int r; 1124 r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]); 1125 assert(r.countUntil(3) == 3); 1126 r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]); 1127 assert(r.countUntil(7) == -1); 1128 } 1129 { 1130 // forward 1131 auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]); 1132 assert(r.save.countUntil([3, 4]) == 3); 1133 assert(r.save.countUntil(3) == 3); 1134 assert(r.save.countUntil([3, 7]) == -1); 1135 assert(r.save.countUntil(7) == -1); 1136 } 1137 { 1138 // infinite forward 1139 auto r = new ReferenceInfiniteForwardRange!int(0); 1140 assert(r.save.countUntil([3, 4]) == 3); 1141 assert(r.save.countUntil(3) == 3); 1142 } 1143 } 1144 1145 /** 1146 Checks if the given range ends with (one of) the given needle(s). 1147 The reciprocal of `startsWith`. 1148 1149 Params: 1150 pred = The predicate to use for comparing elements between the range and 1151 the needle(s). 1152 1153 doesThisEnd = The 1154 $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives) 1155 to check. 1156 1157 withOneOfThese = The needles to check against, which may be single 1158 elements, or bidirectional ranges of elements. 1159 1160 withThis = The single element to check. 1161 1162 Returns: 1163 0 if the needle(s) do not occur at the end of the given range; 1164 otherwise the position of the matching needle, that is, 1 if the range ends 1165 with `withOneOfThese[0]`, 2 if it ends with `withOneOfThese[1]`, and so 1166 on. 1167 1168 In the case when no needle parameters are given, return `true` iff back of 1169 `doesThisStart` fulfils predicate `pred`. 1170 */ 1171 uint endsWith(alias pred = "a == b", Range, Needles...)(Range doesThisEnd, Needles withOneOfThese) 1172 if (isBidirectionalRange!Range && Needles.length > 1 && 1173 allSatisfy!(canTestStartsWith!(pred, Range), Needles)) 1174 { 1175 alias haystack = doesThisEnd; 1176 alias needles = withOneOfThese; 1177 1178 // Make one pass looking for empty ranges in needles 1179 foreach (i, Unused; Needles) 1180 { 1181 // Empty range matches everything 1182 static if (!is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool)) 1183 { 1184 if (needles[i].empty) return i + 1; 1185 } 1186 } 1187 1188 for (; !haystack.empty; haystack.popBack()) 1189 { 1190 foreach (i, Unused; Needles) 1191 { 1192 static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool)) 1193 { 1194 // Single-element 1195 if (binaryFun!pred(haystack.back, needles[i])) 1196 { 1197 // found, but continue to account for one-element 1198 // range matches (consider endsWith("ab", "b", 1199 // 'b') should return 1, not 2). 1200 continue; 1201 } 1202 } 1203 else 1204 { 1205 if (binaryFun!pred(haystack.back, needles[i].back)) 1206 continue; 1207 } 1208 1209 // This code executed on failure to match 1210 // Out with this guy, check for the others 1211 uint result = endsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]); 1212 if (result > i) ++result; 1213 return result; 1214 } 1215 1216 // If execution reaches this point, then the back matches for all 1217 // needles ranges. What we need to do now is to lop off the back of 1218 // all ranges involved and recurse. 1219 foreach (i, Unused; Needles) 1220 { 1221 static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool)) 1222 { 1223 // Test has passed in the previous loop 1224 return i + 1; 1225 } 1226 else 1227 { 1228 needles[i].popBack(); 1229 if (needles[i].empty) return i + 1; 1230 } 1231 } 1232 } 1233 return 0; 1234 } 1235 1236 /// Ditto 1237 bool endsWith(alias pred = "a == b", R1, R2)(R1 doesThisEnd, R2 withThis) 1238 if (isBidirectionalRange!R1 && 1239 isBidirectionalRange!R2 && 1240 is(typeof(binaryFun!pred(doesThisEnd.back, withThis.back)) : bool)) 1241 { 1242 alias haystack = doesThisEnd; 1243 alias needle = withThis; 1244 1245 static if (is(typeof(pred) : string)) 1246 enum isDefaultPred = pred == "a == b"; 1247 else 1248 enum isDefaultPred = false; 1249 1250 static if (isDefaultPred && isArray!R1 && isArray!R2 && 1251 is(immutable ElementEncodingType!R1 == immutable ElementEncodingType!R2)) 1252 { 1253 if (haystack.length < needle.length) return false; 1254 1255 return haystack[$ - needle.length .. $] == needle; 1256 } 1257 else 1258 { 1259 import std.range : retro; 1260 return startsWith!pred(retro(doesThisEnd), retro(withThis)); 1261 } 1262 } 1263 1264 /// Ditto 1265 bool endsWith(alias pred = "a == b", R, E)(R doesThisEnd, E withThis) 1266 if (isBidirectionalRange!R && 1267 is(typeof(binaryFun!pred(doesThisEnd.back, withThis)) : bool)) 1268 { 1269 if (doesThisEnd.empty) 1270 return false; 1271 1272 static if (is(typeof(pred) : string)) 1273 enum isDefaultPred = pred == "a == b"; 1274 else 1275 enum isDefaultPred = false; 1276 1277 alias predFunc = binaryFun!pred; 1278 1279 // auto-decoding special case 1280 static if (isNarrowString!R) 1281 { 1282 // statically determine decoding is unnecessary to evaluate pred 1283 static if (isDefaultPred && isSomeChar!E && E.sizeof <= ElementEncodingType!R.sizeof) 1284 return doesThisEnd[$ - 1] == withThis; 1285 // specialize for ASCII as to not change previous behavior 1286 else 1287 { 1288 if (withThis <= 0x7F) 1289 return predFunc(doesThisEnd[$ - 1], withThis); 1290 else 1291 return predFunc(doesThisEnd.back, withThis); 1292 } 1293 } 1294 else 1295 { 1296 return predFunc(doesThisEnd.back, withThis); 1297 } 1298 } 1299 1300 /// Ditto 1301 bool endsWith(alias pred, R)(R doesThisEnd) 1302 if (isInputRange!R && 1303 ifTestable!(typeof(doesThisEnd.front), unaryFun!pred)) 1304 { 1305 return !doesThisEnd.empty && unaryFun!pred(doesThisEnd.back); 1306 } 1307 1308 /// 1309 @safe unittest 1310 { 1311 import std.ascii : isAlpha; 1312 assert("abc".endsWith!(a => a.isAlpha)); 1313 assert("abc".endsWith!isAlpha); 1314 1315 assert(!"ab1".endsWith!(a => a.isAlpha)); 1316 1317 assert(!"ab1".endsWith!isAlpha); 1318 assert(!"".endsWith!(a => a.isAlpha)); 1319 1320 import std.algorithm.comparison : among; 1321 assert("abc".endsWith!(a => a.among('c', 'd') != 0)); 1322 assert(!"abc".endsWith!(a => a.among('a', 'b') != 0)); 1323 1324 assert(endsWith("abc", "")); 1325 assert(!endsWith("abc", "b")); 1326 assert(endsWith("abc", "a", 'c') == 2); 1327 assert(endsWith("abc", "c", "a") == 1); 1328 assert(endsWith("abc", "c", "c") == 1); 1329 assert(endsWith("abc", "bc", "c") == 2); 1330 assert(endsWith("abc", "x", "c", "b") == 2); 1331 assert(endsWith("abc", "x", "aa", "bc") == 3); 1332 assert(endsWith("abc", "x", "aaa", "sab") == 0); 1333 assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3); 1334 } 1335 1336 @safe unittest 1337 { 1338 import std.algorithm.iteration : filterBidirectional; 1339 import std.conv : to; 1340 import std.meta : AliasSeq; 1341 1342 static foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) 1343 (){ // workaround slow optimizations for large functions 1344 // https://issues.dlang.org/show_bug.cgi?id=2396 1345 assert(!endsWith(to!S("abc"), 'a')); 1346 assert(endsWith(to!S("abc"), 'a', 'c') == 2); 1347 assert(!endsWith(to!S("abc"), 'x', 'n', 'b')); 1348 assert(endsWith(to!S("abc"), 'x', 'n', 'c') == 3); 1349 assert(endsWith(to!S("abc\uFF28"), 'a', '\uFF28', 'c') == 2); 1350 1351 static foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) 1352 { 1353 //Lots of strings 1354 assert(endsWith(to!S("abc"), to!T(""))); 1355 assert(!endsWith(to!S("abc"), to!T("a"))); 1356 assert(!endsWith(to!S("abc"), to!T("b"))); 1357 assert(endsWith(to!S("abc"), to!T("bc"), 'c') == 2); 1358 assert(endsWith(to!S("abc"), to!T("a"), "c") == 2); 1359 assert(endsWith(to!S("abc"), to!T("c"), "a") == 1); 1360 assert(endsWith(to!S("abc"), to!T("c"), "c") == 1); 1361 assert(endsWith(to!S("abc"), to!T("x"), 'c', "b") == 2); 1362 assert(endsWith(to!S("abc"), 'x', to!T("aa"), "bc") == 3); 1363 assert(endsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0); 1364 assert(endsWith(to!S("abc"), to!T("x"), "aaa", "c", "sab") == 3); 1365 assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co"))); 1366 assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2); 1367 1368 //Unicode 1369 assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co"))); 1370 assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2); 1371 assert(endsWith(to!S("日本語"), to!T("本語"))); 1372 assert(endsWith(to!S("日本語"), to!T("日本語"))); 1373 assert(!endsWith(to!S("本語"), to!T("日本語"))); 1374 1375 //Empty 1376 assert(endsWith(to!S(""), T.init)); 1377 assert(!endsWith(to!S(""), 'a')); 1378 assert(endsWith(to!S("a"), T.init)); 1379 assert(endsWith(to!S("a"), T.init, "") == 1); 1380 assert(endsWith(to!S("a"), T.init, 'a') == 1); 1381 assert(endsWith(to!S("a"), 'a', T.init) == 2); 1382 } 1383 }(); 1384 1385 static foreach (T; AliasSeq!(int, short)) 1386 {{ 1387 immutable arr = cast(T[])[0, 1, 2, 3, 4, 5]; 1388 1389 //RA range 1390 assert(endsWith(arr, cast(int[]) null)); 1391 assert(!endsWith(arr, 0)); 1392 assert(!endsWith(arr, 4)); 1393 assert(endsWith(arr, 5)); 1394 assert(endsWith(arr, 0, 4, 5) == 3); 1395 assert(endsWith(arr, [5])); 1396 assert(endsWith(arr, [4, 5])); 1397 assert(endsWith(arr, [4, 5], 7) == 1); 1398 assert(!endsWith(arr, [2, 4, 5])); 1399 assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2); 1400 1401 //Normal input range 1402 assert(!endsWith(filterBidirectional!"true"(arr), 4)); 1403 assert(endsWith(filterBidirectional!"true"(arr), 5)); 1404 assert(endsWith(filterBidirectional!"true"(arr), [5])); 1405 assert(endsWith(filterBidirectional!"true"(arr), [4, 5])); 1406 assert(endsWith(filterBidirectional!"true"(arr), [4, 5], 7) == 1); 1407 assert(!endsWith(filterBidirectional!"true"(arr), [2, 4, 5])); 1408 assert(endsWith(filterBidirectional!"true"(arr), [2, 4, 5], [3, 4, 5]) == 2); 1409 assert(endsWith(arr, filterBidirectional!"true"([4, 5]))); 1410 assert(endsWith(arr, filterBidirectional!"true"([4, 5]), 7) == 1); 1411 assert(!endsWith(arr, filterBidirectional!"true"([2, 4, 5]))); 1412 assert(endsWith(arr, [2, 4, 5], filterBidirectional!"true"([3, 4, 5])) == 2); 1413 1414 //Non-default pred 1415 assert(endsWith!("a%10 == b%10")(arr, [14, 15])); 1416 assert(!endsWith!("a%10 == b%10")(arr, [15, 14])); 1417 }} 1418 } 1419 1420 @safe pure unittest 1421 { 1422 //example from https://issues.dlang.org/show_bug.cgi?id=19727 1423 import std.path : asRelativePath; 1424 string[] ext = ["abc", "def", "ghi"]; 1425 string path = "/foo/file.def"; 1426 assert(ext.any!(e => path.asRelativePath("/foo").endsWith(e)) == true); 1427 assert(ext.any!(e => path.asRelativePath("/foo").startsWith(e)) == false); 1428 } 1429 1430 private enum bool hasConstEmptyMember(T) = is(typeof(((const T* a) => (*a).empty)(null)) : bool); 1431 1432 /** 1433 Iterates the passed range and selects the extreme element with `less`. 1434 If the extreme element occurs multiple time, the first occurrence will be 1435 returned. 1436 1437 Params: 1438 map = custom accessor for the comparison key 1439 selector = custom mapping for the extrema selection 1440 r = Range from which the extreme value will be selected 1441 seedElement = custom seed to use as initial element 1442 1443 Returns: 1444 The extreme value according to `map` and `selector` of the passed-in values. 1445 */ 1446 private auto extremum(alias map, alias selector = "a < b", Range)(Range r) 1447 if (isInputRange!Range && !isInfinite!Range && 1448 is(typeof(unaryFun!map(ElementType!(Range).init)))) 1449 in 1450 { 1451 assert(!r.empty, "r is an empty range"); 1452 } 1453 do 1454 { 1455 import std.typecons : Rebindable2; 1456 1457 alias Element = ElementType!Range; 1458 auto seed = Rebindable2!Element(r.front); 1459 r.popFront(); 1460 return extremum!(map, selector)(r, seed.get); 1461 } 1462 1463 private auto extremum(alias map, alias selector = "a < b", Range, 1464 RangeElementType = ElementType!Range) 1465 (Range r, RangeElementType seedElement) 1466 if (isInputRange!Range && !isInfinite!Range && 1467 !is(CommonType!(ElementType!Range, RangeElementType) == void) && 1468 is(typeof(unaryFun!map(ElementType!(Range).init)))) 1469 { 1470 import std.typecons : Rebindable2; 1471 1472 alias mapFun = unaryFun!map; 1473 alias selectorFun = binaryFun!selector; 1474 1475 alias Element = ElementType!Range; 1476 alias CommonElement = CommonType!(Element, RangeElementType); 1477 auto extremeElement = Rebindable2!CommonElement(seedElement); 1478 1479 // if we only have one statement in the loop, it can be optimized a lot better 1480 static if (__traits(isSame, map, a => a)) 1481 { 1482 // direct access via a random access range is faster 1483 static if (isRandomAccessRange!Range) 1484 { 1485 foreach (const i; 0 .. r.length) 1486 { 1487 if (selectorFun(r[i], extremeElement.get)) 1488 { 1489 extremeElement = r[i]; 1490 } 1491 } 1492 } 1493 else 1494 { 1495 while (!r.empty) 1496 { 1497 if (selectorFun(r.front, extremeElement.get)) 1498 { 1499 extremeElement = r.front; 1500 } 1501 r.popFront(); 1502 } 1503 } 1504 } 1505 else 1506 { 1507 alias MapType = Unqual!(typeof(mapFun(CommonElement.init))); 1508 MapType extremeElementMapped = mapFun(extremeElement.get); 1509 1510 // direct access via a random access range is faster 1511 static if (isRandomAccessRange!Range) 1512 { 1513 foreach (const i; 0 .. r.length) 1514 { 1515 MapType mapElement = mapFun(r[i]); 1516 if (selectorFun(mapElement, extremeElementMapped)) 1517 { 1518 extremeElement = r[i]; 1519 extremeElementMapped = mapElement; 1520 } 1521 } 1522 } 1523 else 1524 { 1525 while (!r.empty) 1526 { 1527 MapType mapElement = mapFun(r.front); 1528 if (selectorFun(mapElement, extremeElementMapped)) 1529 { 1530 extremeElement = r.front; 1531 extremeElementMapped = mapElement; 1532 } 1533 r.popFront(); 1534 } 1535 } 1536 } 1537 return extremeElement.get; 1538 } 1539 1540 private auto extremum(alias selector = "a < b", Range)(Range r) 1541 if (isInputRange!Range && !isInfinite!Range && 1542 !is(typeof(unaryFun!selector(ElementType!(Range).init)))) 1543 { 1544 return extremum!(a => a, selector)(r); 1545 } 1546 1547 // if we only have one statement in the loop it can be optimized a lot better 1548 private auto extremum(alias selector = "a < b", Range, 1549 RangeElementType = ElementType!Range) 1550 (Range r, RangeElementType seedElement) 1551 if (isInputRange!Range && !isInfinite!Range && 1552 !is(CommonType!(ElementType!Range, RangeElementType) == void) && 1553 !is(typeof(unaryFun!selector(ElementType!(Range).init)))) 1554 { 1555 return extremum!(a => a, selector)(r, seedElement); 1556 } 1557 1558 @safe pure unittest 1559 { 1560 // allows a custom map to select the extremum 1561 assert([[0, 4], [1, 2]].extremum!"a[0]" == [0, 4]); 1562 assert([[0, 4], [1, 2]].extremum!"a[1]" == [1, 2]); 1563 1564 // allows a custom selector for comparison 1565 assert([[0, 4], [1, 2]].extremum!("a[0]", "a > b") == [1, 2]); 1566 assert([[0, 4], [1, 2]].extremum!("a[1]", "a > b") == [0, 4]); 1567 1568 // use a custom comparator 1569 import std.math.operations : cmp; 1570 assert([-2., 0, 5].extremum!cmp == 5.0); 1571 assert([-2., 0, 2].extremum!`cmp(a, b) < 0` == -2.0); 1572 1573 // combine with map 1574 import std.range : enumerate; 1575 assert([-3., 0, 5].enumerate.extremum!(`a.value`, cmp) == tuple(2, 5.0)); 1576 assert([-2., 0, 2].enumerate.extremum!(`a.value`, `cmp(a, b) < 0`) == tuple(0, -2.0)); 1577 1578 // seed with a custom value 1579 int[] arr; 1580 assert(arr.extremum(1) == 1); 1581 } 1582 1583 @safe pure nothrow unittest 1584 { 1585 // 2d seeds 1586 int[][] arr2d; 1587 assert(arr2d.extremum([1]) == [1]); 1588 1589 // allow seeds of different types (implicit casting) 1590 assert(extremum([2, 3, 4], 1.5) == 1.5); 1591 } 1592 1593 @safe pure unittest 1594 { 1595 import std.range : enumerate, iota; 1596 1597 // forward ranges 1598 assert(iota(1, 5).extremum() == 1); 1599 assert(iota(2, 5).enumerate.extremum!"a.value" == tuple(0, 2)); 1600 1601 // should work with const 1602 const(int)[] immArr = [2, 1, 3]; 1603 assert(immArr.extremum == 1); 1604 1605 // should work with immutable 1606 immutable(int)[] immArr2 = [2, 1, 3]; 1607 assert(immArr2.extremum == 1); 1608 1609 // with strings 1610 assert(["b", "a", "c"].extremum == "a"); 1611 1612 // with all dummy ranges 1613 import std.internal.test.dummyrange; 1614 foreach (DummyType; AllDummyRanges) 1615 { 1616 DummyType d; 1617 assert(d.extremum == 1); 1618 assert(d.extremum!(a => a) == 1); 1619 assert(d.extremum!`a > b` == 10); 1620 assert(d.extremum!(a => a, `a > b`) == 10); 1621 } 1622 1623 // compiletime 1624 enum ctExtremum = iota(1, 5).extremum; 1625 assert(ctExtremum == 1); 1626 } 1627 1628 @nogc @safe nothrow pure unittest 1629 { 1630 static immutable arr = [7, 3, 4, 2, 1, 8]; 1631 assert(arr.extremum == 1); 1632 1633 static immutable arr2d = [[1, 9], [3, 1], [4, 2]]; 1634 assert(arr2d.extremum!"a[1]" == arr2d[1]); 1635 } 1636 1637 // https://issues.dlang.org/show_bug.cgi?id=17982 1638 @safe unittest 1639 { 1640 class B 1641 { 1642 int val; 1643 this(int val){ this.val = val; } 1644 } 1645 1646 const(B) doStuff(const(B)[] v) 1647 { 1648 return v.extremum!"a.val"; 1649 } 1650 assert(doStuff([new B(1), new B(0), new B(2)]).val == 0); 1651 1652 const(B)[] arr = [new B(0), new B(1)]; 1653 // can't compare directly - https://issues.dlang.org/show_bug.cgi?id=1824 1654 assert(arr.extremum!"a.val".val == 0); 1655 } 1656 1657 // https://issues.dlang.org/show_bug.cgi?id=22786 1658 @nogc @safe nothrow pure unittest 1659 { 1660 struct S 1661 { 1662 immutable int value; 1663 } 1664 1665 assert([S(5), S(6)].extremum!"a.value" == S(5)); 1666 } 1667 1668 // https://issues.dlang.org/show_bug.cgi?id=24027 1669 @safe nothrow unittest 1670 { 1671 class A 1672 { 1673 int a; 1674 this(int a) 1675 { 1676 this.a = a; 1677 } 1678 } 1679 1680 auto test = new A(5); 1681 A[] arr = [test]; 1682 assert(maxElement!"a.a"(arr) is test); 1683 } 1684 1685 // find 1686 /** 1687 Finds an element `e` of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 1688 where `pred(e)` is `true`. 1689 $(P 1690 $(PANEL 1691 $(UL 1692 $(LI `find` behaves similarly to `dropWhile` in other languages.) 1693 $(LI To _find the *last* matching element in a 1694 $(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`, 1695 call `find!pred(retro(haystack))`. See $(REF retro, std,range).) 1696 ))) 1697 1698 Complexity: 1699 `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`. 1700 1701 Params: 1702 1703 pred = The predicate to match an element. 1704 haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 1705 searched in. 1706 1707 Returns: 1708 `haystack` advanced such that the front element satisfies `pred`. 1709 If no such element exists, returns an empty `haystack`. 1710 */ 1711 InputRange find(alias pred, InputRange)(InputRange haystack) 1712 if (isInputRange!InputRange) 1713 { 1714 alias R = InputRange; 1715 alias predFun = unaryFun!pred; 1716 static if (isNarrowString!R) 1717 { 1718 import std.utf : decode; 1719 1720 immutable len = haystack.length; 1721 size_t i = 0, next = 0; 1722 while (next < len) 1723 { 1724 if (predFun(decode(haystack, next))) 1725 return haystack[i .. $]; 1726 i = next; 1727 } 1728 return haystack[$ .. $]; 1729 } 1730 else 1731 { 1732 //standard range 1733 for ( ; !haystack.empty; haystack.popFront() ) 1734 { 1735 if (predFun(haystack.front)) 1736 break; 1737 } 1738 return haystack; 1739 } 1740 } 1741 1742 /// 1743 @safe unittest 1744 { 1745 auto arr = [ 1, 2, 3, 4, 1 ]; 1746 assert(find!("a > 2")(arr) == [ 3, 4, 1 ]); 1747 1748 // with predicate alias 1749 bool pred(int e) => e + 1 > 1.5; 1750 assert(find!(pred)(arr) == arr); 1751 } 1752 1753 @safe pure unittest 1754 { 1755 int[] r = [ 1, 2, 3 ]; 1756 assert(find!(a=>a > 2)(r) == [3]); 1757 bool pred(int x) { return x + 1 > 1.5; } 1758 assert(find!(pred)(r) == r); 1759 1760 assert(find!(a=>a > 'v')("hello world") == "world"); 1761 assert(find!(a=>a%4 == 0)("日本語") == "本語"); 1762 } 1763 1764 /** 1765 Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). 1766 Elements of `haystack` are compared with `needle` by using predicate 1767 `pred` with `pred(haystack.front, needle)`. 1768 The predicate is passed to $(REF binaryFun, std, functional), and can either accept a 1769 string, or any callable that can be executed via `pred(element, element)`. 1770 1771 If `haystack` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives), 1772 `needle` can be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) too. 1773 In this case `startsWith!pred(haystack, needle)` is evaluated on each evaluation. 1774 1775 $(NOTE To find the first element $(I not) matching the needle, use predicate `"a != b"`.) 1776 1777 Complexity: 1778 `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`. 1779 There are specializations that improve performance by taking 1780 advantage of $(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) 1781 or $(REF_ALTTEXT random access, isRandomAccessRange, std,range,primitives) 1782 ranges (where possible). 1783 1784 Params: 1785 1786 pred = The predicate for comparing each element with the needle, defaulting to equality `"a == b"`. 1787 haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 1788 searched in. 1789 needle = The element searched for. 1790 1791 Returns: 1792 `haystack` advanced such that the front element is the one searched for; 1793 that is, until `binaryFun!pred(haystack.front, needle)` is `true`. If no 1794 such position exists, returns an empty `haystack`. 1795 1796 See_Also: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith) 1797 */ 1798 InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle) 1799 if (isInputRange!InputRange && 1800 is (typeof(binaryFun!pred(haystack.front, needle)) : bool) && 1801 !is (typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) 1802 { 1803 alias R = InputRange; 1804 alias E = Element; 1805 alias predFun = binaryFun!pred; 1806 static if (is(typeof(pred == "a == b"))) 1807 enum isDefaultPred = pred == "a == b"; 1808 else 1809 enum isDefaultPred = false; 1810 enum isIntegralNeedle = isSomeChar!E || isIntegral!E || isBoolean!E; 1811 1812 alias EType = ElementType!R; 1813 1814 // If the haystack is a SortedRange we can use binary search to find the needle. 1815 // Works only for the default find predicate and any SortedRange predicate. 1816 // https://issues.dlang.org/show_bug.cgi?id=8829 1817 import std.range : SortedRange; 1818 static if (is(InputRange : SortedRange!TT, TT) && isDefaultPred) 1819 { 1820 auto lb = haystack.lowerBound(needle); 1821 if (lb.length == haystack.length || haystack[lb.length] != needle) 1822 return haystack[$ .. $]; 1823 1824 return haystack[lb.length .. $]; 1825 } 1826 else static if (isNarrowString!R) 1827 { 1828 alias EEType = ElementEncodingType!R; 1829 alias UEEType = Unqual!EEType; 1830 1831 //These are two special cases which can search without decoding the UTF stream. 1832 static if (isDefaultPred && isIntegralNeedle) 1833 { 1834 import std.utf : canSearchInCodeUnits; 1835 1836 //This special case deals with UTF8 search, when the needle 1837 //is represented by a single code point. 1838 //Note: "needle <= 0x7F" properly handles sign via unsigned promotion 1839 static if (is(UEEType == char)) 1840 { 1841 if (!__ctfe && canSearchInCodeUnits!char(needle)) 1842 { 1843 static inout(R) trustedMemchr(ref return scope inout(R) haystack, 1844 ref const scope E needle) @trusted nothrow pure 1845 { 1846 import core.stdc.string : memchr; 1847 auto ptr = memchr(haystack.ptr, needle, haystack.length); 1848 return ptr ? 1849 haystack[cast(char*) ptr - haystack.ptr .. $] : 1850 haystack[$ .. $]; 1851 } 1852 return trustedMemchr(haystack, needle); 1853 } 1854 } 1855 1856 //Ditto, but for UTF16 1857 static if (is(UEEType == wchar)) 1858 { 1859 if (canSearchInCodeUnits!wchar(needle)) 1860 { 1861 foreach (i, ref EEType e; haystack) 1862 { 1863 if (e == needle) 1864 return haystack[i .. $]; 1865 } 1866 return haystack[$ .. $]; 1867 } 1868 } 1869 } 1870 1871 //Previous conditional optimizations did not succeed. Fallback to 1872 //unconditional implementations 1873 static if (isDefaultPred) 1874 { 1875 import std.utf : encode; 1876 1877 //In case of default pred, it is faster to do string/string search. 1878 UEEType[is(UEEType == char) ? 4 : 2] buf; 1879 1880 size_t len = encode(buf, needle); 1881 return find(haystack, buf[0 .. len]); 1882 } 1883 else 1884 { 1885 import std.utf : decode; 1886 1887 //Explicit pred: we must test each character by the book. 1888 //We choose a manual decoding approach, because it is faster than 1889 //the built-in foreach, or doing a front/popFront for-loop. 1890 immutable len = haystack.length; 1891 size_t i = 0, next = 0; 1892 while (next < len) 1893 { 1894 if (predFun(decode(haystack, next), needle)) 1895 return haystack[i .. $]; 1896 i = next; 1897 } 1898 return haystack[$ .. $]; 1899 } 1900 } 1901 else static if (isArray!R) 1902 { 1903 // https://issues.dlang.org/show_bug.cgi?id=10403 optimization 1904 static if (isDefaultPred && isIntegral!EType && EType.sizeof == 1 && isIntegralNeedle) 1905 { 1906 import std.algorithm.comparison : max, min; 1907 1908 R findHelper(return scope ref R haystack, ref E needle) @trusted nothrow pure 1909 { 1910 import core.stdc.string : memchr; 1911 1912 EType* ptr = null; 1913 //Note: we use "min/max" to handle sign mismatch. 1914 if (min(EType.min, needle) == EType.min && 1915 max(EType.max, needle) == EType.max) 1916 { 1917 ptr = cast(EType*) memchr(haystack.ptr, needle, 1918 haystack.length); 1919 } 1920 1921 return ptr ? 1922 haystack[ptr - haystack.ptr .. $] : 1923 haystack[$ .. $]; 1924 } 1925 1926 if (!__ctfe) 1927 return findHelper(haystack, needle); 1928 } 1929 1930 //Default implementation. 1931 foreach (i, ref e; haystack) 1932 if (predFun(e, needle)) 1933 return haystack[i .. $]; 1934 return haystack[$ .. $]; 1935 } 1936 else 1937 { 1938 //Everything else. Walk. 1939 for ( ; !haystack.empty; haystack.popFront() ) 1940 { 1941 if (predFun(haystack.front, needle)) 1942 break; 1943 } 1944 return haystack; 1945 } 1946 } 1947 1948 /// 1949 @safe unittest 1950 { 1951 import std.range.primitives; 1952 1953 auto arr = [1, 2, 4, 4, 4, 4, 5, 6, 9]; 1954 assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]); 1955 assert(arr.find(1) == arr); 1956 assert(arr.find(9) == [9]); 1957 assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]); 1958 assert(arr.find!((e, n) => e < n)(4) == arr); 1959 assert(arr.find(0).empty); 1960 assert(arr.find(10).empty); 1961 assert(arr.find(8).empty); 1962 1963 assert(find("hello, world", ',') == ", world"); 1964 } 1965 1966 /// Case-insensitive find of a string 1967 @safe unittest 1968 { 1969 import std.range.primitives; 1970 import std.uni : toLower; 1971 1972 string[] s = ["Hello", "world", "!"]; 1973 assert(s.find!((e, n) => toLower(e) == n)("hello") == s); 1974 } 1975 1976 @safe unittest 1977 { 1978 import std.algorithm.comparison : equal; 1979 import std.container : SList; 1980 1981 auto lst = SList!int(1, 2, 5, 7, 3); 1982 assert(lst.front == 1); 1983 auto r = find(lst[], 5); 1984 assert(equal(r, SList!int(5, 7, 3)[])); 1985 assert(find([1, 2, 3, 5], 4).empty); 1986 assert(equal(find!"a > b"("hello", 'k'), "llo")); 1987 } 1988 1989 @safe pure nothrow unittest 1990 { 1991 assert(!find ([1, 2, 3], 2).empty); 1992 assert(!find!((a,b)=>a == b)([1, 2, 3], 2).empty); 1993 assert(!find ([1, 2, 3], 2).empty); 1994 assert(!find!((a,b)=>a == b)([1, 2, 3], 2).empty); 1995 } 1996 1997 @safe pure unittest 1998 { 1999 import std.meta : AliasSeq; 2000 static foreach (R; AliasSeq!(string, wstring, dstring)) 2001 { 2002 static foreach (E; AliasSeq!(char, wchar, dchar)) 2003 { 2004 assert(find ("hello world", 'w') == "world"); 2005 assert(find!((a,b)=>a == b)("hello world", 'w') == "world"); 2006 assert(find ("日c語", 'c') == "c語"); 2007 assert(find!((a,b)=>a == b)("日c語", 'c') == "c語"); 2008 assert(find ("0123456789", 'A').empty); 2009 static if (E.sizeof >= 2) 2010 { 2011 assert(find ("日本語", '本') == "本語"); 2012 assert(find!((a,b)=>a == b)("日本語", '本') == "本語"); 2013 } 2014 } 2015 } 2016 } 2017 2018 @safe unittest 2019 { 2020 //CTFE 2021 static assert(find("abc", 'b') == "bc"); 2022 static assert(find("日b語", 'b') == "b語"); 2023 static assert(find("日本語", '本') == "本語"); 2024 static assert(find([1, 2, 3], 2) == [2, 3]); 2025 2026 static assert(find ([1, 2, 3], 2)); 2027 static assert(find!((a,b)=>a == b)([1, 2, 3], 2)); 2028 static assert(find ([1, 2, 3], 2)); 2029 static assert(find!((a,b)=>a == b)([1, 2, 3], 2)); 2030 } 2031 2032 @safe unittest 2033 { 2034 import std.exception : assertCTFEable; 2035 import std.meta : AliasSeq; 2036 2037 void dg() @safe pure nothrow 2038 { 2039 byte[] sarr = [1, 2, 3, 4]; 2040 ubyte[] uarr = [1, 2, 3, 4]; 2041 static foreach (arr; AliasSeq!(sarr, uarr)) 2042 { 2043 static foreach (T; AliasSeq!(byte, ubyte, int, uint)) 2044 { 2045 assert(find(arr, cast(T) 3) == arr[2 .. $]); 2046 assert(find(arr, cast(T) 9) == arr[$ .. $]); 2047 } 2048 assert(find(arr, 256) == arr[$ .. $]); 2049 } 2050 } 2051 dg(); 2052 assertCTFEable!dg; 2053 } 2054 2055 // https://issues.dlang.org/show_bug.cgi?id=11603 2056 @safe unittest 2057 { 2058 enum Foo : ubyte { A } 2059 assert([Foo.A].find(Foo.A).empty == false); 2060 2061 ubyte x = 0; 2062 assert([x].find(x).empty == false); 2063 } 2064 2065 /// ditto 2066 R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle) 2067 if (isForwardRange!R1 && isForwardRange!R2 2068 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) 2069 { 2070 static if (!isRandomAccessRange!R1) 2071 { 2072 static if (is(typeof(pred == "a == b")) && pred == "a == b" && isSomeString!R1 && isSomeString!R2 2073 && haystack[0].sizeof == needle[0].sizeof) 2074 { 2075 // return cast(R1) find(representation(haystack), representation(needle)); 2076 // Specialization for simple string search 2077 alias Representation = 2078 Select!(haystack[0].sizeof == 1, ubyte[], 2079 Select!(haystack[0].sizeof == 2, ushort[], uint[])); 2080 // Will use the array specialization 2081 static TO force(TO, T)(inout T r) @trusted { return cast(TO) r; } 2082 return force!R1(.find!(pred, Representation, Representation) 2083 (force!Representation(haystack), force!Representation(needle))); 2084 } 2085 else 2086 { 2087 return simpleMindedFind!pred(haystack, needle); 2088 } 2089 } 2090 else static if (!isBidirectionalRange!R2 || !hasSlicing!R1) 2091 { 2092 static if (!is(ElementType!R1 == ElementType!R2)) 2093 { 2094 return simpleMindedFind!pred(haystack, needle); 2095 } 2096 else 2097 { 2098 // Prepare the search with needle's first element 2099 if (needle.empty) 2100 return haystack; 2101 2102 haystack = .find!pred(haystack, needle.front); 2103 2104 static if (hasLength!R1 && hasLength!R2 && is(typeof(takeNone(haystack)) == R1)) 2105 { 2106 if (needle.length > haystack.length) 2107 return takeNone(haystack); 2108 } 2109 else 2110 { 2111 if (haystack.empty) 2112 return haystack; 2113 } 2114 2115 needle.popFront(); 2116 size_t matchLen = 1; 2117 2118 // Loop invariant: haystack[0 .. matchLen] matches everything in 2119 // the initial needle that was popped out of needle. 2120 for (;;) 2121 { 2122 // Extend matchLength as much as possible 2123 for (;;) 2124 { 2125 import std.range : takeNone; 2126 2127 if (needle.empty || haystack.empty) 2128 return haystack; 2129 2130 static if (hasLength!R1 && is(typeof(takeNone(haystack)) == R1)) 2131 { 2132 if (matchLen == haystack.length) 2133 return takeNone(haystack); 2134 } 2135 2136 if (!binaryFun!pred(haystack[matchLen], needle.front)) 2137 break; 2138 2139 ++matchLen; 2140 needle.popFront(); 2141 } 2142 2143 auto bestMatch = haystack[0 .. matchLen]; 2144 haystack.popFront(); 2145 haystack = .find!pred(haystack, bestMatch); 2146 } 2147 } 2148 } 2149 else // static if (hasSlicing!R1 && isBidirectionalRange!R2) 2150 { 2151 if (needle.empty) return haystack; 2152 2153 static if (hasLength!R2) 2154 { 2155 immutable needleLength = needle.length; 2156 } 2157 else 2158 { 2159 immutable needleLength = walkLength(needle.save); 2160 } 2161 if (needleLength > haystack.length) 2162 { 2163 return haystack[haystack.length .. haystack.length]; 2164 } 2165 // Optimization in case the ranges are both SortedRanges. 2166 // Binary search can be used to find the first occurence 2167 // of the first element of the needle in haystack. 2168 // When it is found O(walklength(needle)) steps are performed. 2169 // https://issues.dlang.org/show_bug.cgi?id=8829 enhancement 2170 import std.algorithm.comparison : mismatch; 2171 import std.range : SortedRange; 2172 static if (is(R1 == R2) 2173 && is(R1 : SortedRange!TT, TT) 2174 && pred == "a == b") 2175 { 2176 auto needleFirstElem = needle[0]; 2177 auto partitions = haystack.trisect(needleFirstElem); 2178 auto firstElemLen = partitions[1].length; 2179 size_t count = 0; 2180 2181 if (firstElemLen == 0) 2182 return haystack[$ .. $]; 2183 2184 while (needle.front() == needleFirstElem) 2185 { 2186 needle.popFront(); 2187 ++count; 2188 2189 if (count > firstElemLen) 2190 return haystack[$ .. $]; 2191 } 2192 2193 auto m = mismatch(partitions[2], needle); 2194 2195 if (m[1].empty) 2196 return haystack[partitions[0].length + partitions[1].length - count .. $]; 2197 } 2198 else static if (isRandomAccessRange!R2) 2199 { 2200 immutable lastIndex = needleLength - 1; 2201 auto last = needle[lastIndex]; 2202 size_t j = lastIndex, skip = 0; 2203 for (; j < haystack.length;) 2204 { 2205 if (!binaryFun!pred(haystack[j], last)) 2206 { 2207 ++j; 2208 continue; 2209 } 2210 immutable k = j - lastIndex; 2211 // last elements match 2212 for (size_t i = 0;; ++i) 2213 { 2214 if (i == lastIndex) 2215 return haystack[k .. haystack.length]; 2216 if (!binaryFun!pred(haystack[k + i], needle[i])) 2217 break; 2218 } 2219 if (skip == 0) 2220 { 2221 skip = 1; 2222 while (skip < needleLength && needle[needleLength - 1 - skip] != needle[needleLength - 1]) 2223 { 2224 ++skip; 2225 } 2226 } 2227 j += skip; 2228 } 2229 } 2230 else 2231 { 2232 // @@@BUG@@@ 2233 // auto needleBack = moveBack(needle); 2234 // Stage 1: find the step 2235 size_t step = 1; 2236 auto needleBack = needle.back; 2237 needle.popBack(); 2238 for (auto i = needle.save; !i.empty && i.back != needleBack; 2239 i.popBack(), ++step) 2240 { 2241 } 2242 // Stage 2: linear find 2243 size_t scout = needleLength - 1; 2244 for (;;) 2245 { 2246 if (scout >= haystack.length) 2247 break; 2248 if (!binaryFun!pred(haystack[scout], needleBack)) 2249 { 2250 ++scout; 2251 continue; 2252 } 2253 // Found a match with the last element in the needle 2254 auto cand = haystack[scout + 1 - needleLength .. haystack.length]; 2255 if (startsWith!pred(cand, needle)) 2256 { 2257 // found 2258 return cand; 2259 } 2260 scout += step; 2261 } 2262 } 2263 return haystack[haystack.length .. haystack.length]; 2264 } 2265 } 2266 2267 /// 2268 @safe unittest 2269 { 2270 import std.container : SList; 2271 import std.range.primitives : empty; 2272 import std.typecons : Tuple; 2273 2274 assert(find("hello, world", "World").empty); 2275 assert(find("hello, world", "wo") == "world"); 2276 assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]); 2277 alias C = Tuple!(int, "x", int, "y"); 2278 auto a = [C(1,0), C(2,0), C(3,1), C(4,0)]; 2279 assert(a.find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); 2280 assert(a[1 .. $].find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); 2281 } 2282 2283 @safe unittest 2284 { 2285 import std.container : SList; 2286 alias C = Tuple!(int, "x", int, "y"); 2287 assert([C(1,0), C(2,0), C(3,1), C(4,0)].find!"a.x == b"(SList!int(2, 3)[]) == [C(2,0), C(3,1), C(4,0)]); 2288 } 2289 2290 // https://issues.dlang.org/show_bug.cgi?id=12470 2291 @safe unittest 2292 { 2293 import std.array : replace; 2294 inout(char)[] sanitize(inout(char)[] p) 2295 { 2296 return p.replace("\0", " "); 2297 } 2298 assert(sanitize("O\x00o") == "O o"); 2299 } 2300 2301 @safe unittest 2302 { 2303 import std.algorithm.comparison : equal; 2304 import std.container : SList; 2305 2306 auto lst = SList!int(1, 2, 5, 7, 3); 2307 static assert(isForwardRange!(int[])); 2308 static assert(isForwardRange!(typeof(lst[]))); 2309 auto r = find(lst[], [2, 5]); 2310 assert(equal(r, SList!int(2, 5, 7, 3)[])); 2311 } 2312 2313 @safe unittest 2314 { 2315 import std.range : assumeSorted; 2316 2317 auto r1 = assumeSorted([1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 8, 8, 10]); 2318 auto r2 = assumeSorted([3, 3, 4, 5, 6, 7, 8, 8]); 2319 auto r3 = assumeSorted([3, 4, 5, 6, 7, 8]); 2320 auto r4 = assumeSorted([4, 5, 6]); 2321 auto r5 = assumeSorted([12, 13]); 2322 auto r6 = assumeSorted([8, 8, 10, 11]); 2323 auto r7 = assumeSorted([3, 3, 3, 3, 3, 3, 3]); 2324 2325 assert(find(r1, r2) == assumeSorted([3, 3, 4, 5, 6, 7, 8, 8, 8, 10])); 2326 assert(find(r1, r3) == assumeSorted([3, 4, 5, 6, 7, 8, 8, 8, 10])); 2327 assert(find(r1, r4) == assumeSorted([4, 5, 6, 7, 8, 8, 8, 10])); 2328 assert(find(r1, r5).empty()); 2329 assert(find(r1, r6).empty()); 2330 assert(find(r1, r7).empty()); 2331 } 2332 2333 @safe unittest 2334 { 2335 import std.algorithm.comparison : equal; 2336 // @@@BUG@@@ removing static below makes unittest fail 2337 static struct BiRange 2338 { 2339 int[] payload; 2340 @property bool empty() { return payload.empty; } 2341 @property BiRange save() { return this; } 2342 @property ref int front() { return payload[0]; } 2343 @property ref int back() { return payload[$ - 1]; } 2344 void popFront() { return payload.popFront(); } 2345 void popBack() { return payload.popBack(); } 2346 } 2347 auto r = BiRange([1, 2, 3, 10, 11, 4]); 2348 assert(equal(find(r, [10, 11]), [10, 11, 4])); 2349 } 2350 2351 @safe unittest 2352 { 2353 import std.container : SList; 2354 2355 assert(find([ 1, 2, 3 ], SList!int(2, 3)[]) == [ 2, 3 ]); 2356 assert(find([ 1, 2, 1, 2, 3, 3 ], SList!int(2, 3)[]) == [ 2, 3, 3 ]); 2357 } 2358 2359 // https://issues.dlang.org/show_bug.cgi?id=8334 2360 @safe unittest 2361 { 2362 import std.algorithm.iteration : filter; 2363 import std.range; 2364 2365 auto haystack = [1, 2, 3, 4, 1, 9, 12, 42]; 2366 auto needle = [12, 42, 27]; 2367 2368 //different overload of find, but it's the base case. 2369 assert(find(haystack, needle).empty); 2370 2371 assert(find(haystack, takeExactly(filter!"true"(needle), 3)).empty); 2372 assert(find(haystack, filter!"true"(needle)).empty); 2373 } 2374 2375 // https://issues.dlang.org/show_bug.cgi?id=11013 2376 @safe unittest 2377 { 2378 assert(find!"a == a"("abc","abc") == "abc"); 2379 } 2380 2381 // Internally used by some find() overloads above 2382 private R1 simpleMindedFind(alias pred, R1, R2)(R1 haystack, scope R2 needle) 2383 { 2384 enum estimateNeedleLength = hasLength!R1 && !hasLength!R2; 2385 2386 static if (hasLength!R1) 2387 { 2388 static if (!hasLength!R2) 2389 size_t estimatedNeedleLength = 0; 2390 else 2391 immutable size_t estimatedNeedleLength = needle.length; 2392 } 2393 2394 bool haystackTooShort() 2395 { 2396 static if (estimateNeedleLength) 2397 { 2398 return haystack.length < estimatedNeedleLength; 2399 } 2400 else 2401 { 2402 return haystack.empty; 2403 } 2404 } 2405 2406 searching: 2407 for (;; haystack.popFront()) 2408 { 2409 if (haystackTooShort()) 2410 { 2411 // Failed search 2412 static if (hasLength!R1) 2413 { 2414 static if (is(typeof(haystack[haystack.length .. 2415 haystack.length]) : R1)) 2416 return haystack[haystack.length .. haystack.length]; 2417 else 2418 return R1.init; 2419 } 2420 else 2421 { 2422 assert(haystack.empty, "Haystack must be empty by now"); 2423 return haystack; 2424 } 2425 } 2426 static if (estimateNeedleLength) 2427 size_t matchLength = 0; 2428 for (auto h = haystack.save, n = needle.save; 2429 !n.empty; 2430 h.popFront(), n.popFront()) 2431 { 2432 if (h.empty || !binaryFun!pred(h.front, n.front)) 2433 { 2434 // Failed searching n in h 2435 static if (estimateNeedleLength) 2436 { 2437 if (estimatedNeedleLength < matchLength) 2438 estimatedNeedleLength = matchLength; 2439 } 2440 continue searching; 2441 } 2442 static if (estimateNeedleLength) 2443 ++matchLength; 2444 } 2445 break; 2446 } 2447 return haystack; 2448 } 2449 2450 @safe unittest 2451 { 2452 // Test simpleMindedFind for the case where both haystack and needle have 2453 // length. 2454 struct CustomString 2455 { 2456 @safe: 2457 string _impl; 2458 2459 // This is what triggers https://issues.dlang.org/show_bug.cgi?id=7992. 2460 @property size_t length() const { return _impl.length; } 2461 @property void length(size_t len) { _impl.length = len; } 2462 2463 // This is for conformance to the forward range API (we deliberately 2464 // make it non-random access so that we will end up in 2465 // simpleMindedFind). 2466 @property bool empty() const { return _impl.empty; } 2467 @property dchar front() const { return _impl.front; } 2468 void popFront() { _impl.popFront(); } 2469 @property CustomString save() { return this; } 2470 } 2471 2472 // If https://issues.dlang.org/show_bug.cgi?id=7992 occurs, this will throw an exception from calling 2473 // popFront() on an empty range. 2474 auto r = find(CustomString("a"), CustomString("b")); 2475 assert(r.empty); 2476 } 2477 2478 /** 2479 Finds two or more `needles` into a `haystack`. The predicate $(D 2480 pred) is used throughout to compare elements. By default, elements are 2481 compared for equality. 2482 2483 Params: 2484 2485 pred = The predicate to use for comparing elements. 2486 2487 haystack = The target of the search. Must be an input range. 2488 If any of `needles` is a range with elements comparable to 2489 elements in `haystack`, then `haystack` must be a 2490 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) 2491 such that the search can backtrack. 2492 2493 needles = One or more items to search for. Each of `needles` must 2494 be either comparable to one element in `haystack`, or be itself a 2495 forward range with elements comparable with elements in 2496 `haystack`. 2497 2498 Returns: 2499 2500 A tuple containing `haystack` positioned to match one of the 2501 needles and also the 1-based index of the matching element in $(D 2502 needles) (0 if none of `needles` matched, 1 if `needles[0]` 2503 matched, 2 if `needles[1]` matched...). The first needle to be found 2504 will be the one that matches. If multiple needles are found at the 2505 same spot in the range, then the shortest one is the one which matches 2506 (if multiple needles of the same length are found at the same spot (e.g 2507 `"a"` and `'a'`), then the left-most of them in the argument list 2508 matches). 2509 2510 The relationship between `haystack` and `needles` simply means 2511 that one can e.g. search for individual `int`s or arrays of $(D 2512 int)s in an array of `int`s. In addition, if elements are 2513 individually comparable, searches of heterogeneous types are allowed 2514 as well: a `double[]` can be searched for an `int` or a $(D 2515 short[]), and conversely a `long` can be searched for a `float` 2516 or a `double[]`. This makes for efficient searches without the need 2517 to coerce one side of the comparison into the other's side type. 2518 2519 The complexity of the search is $(BIGOH haystack.length * 2520 max(needles.length)). (For needles that are individual items, length 2521 is considered to be 1.) The strategy used in searching several 2522 subranges at once maximizes cache usage by moving in `haystack` as 2523 few times as possible. 2524 */ 2525 Tuple!(Range, size_t) find(alias pred = "a == b", Range, Needles...) 2526 (Range haystack, Needles needles) 2527 if (Needles.length > 1 && is(typeof(startsWith!pred(haystack, needles)))) 2528 { 2529 for (;; haystack.popFront()) 2530 { 2531 size_t r = startsWith!pred(haystack, needles); 2532 if (r || haystack.empty) 2533 { 2534 return tuple(haystack, r); 2535 } 2536 } 2537 } 2538 2539 /// 2540 @safe unittest 2541 { 2542 import std.typecons : tuple; 2543 int[] a = [ 1, 4, 2, 3 ]; 2544 assert(find(a, 4) == [ 4, 2, 3 ]); 2545 assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]); 2546 assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2)); 2547 // Mixed types allowed if comparable 2548 assert(find(a, 5, [ 1.2, 3.5 ], 2.0) == tuple([ 2, 3 ], 3)); 2549 } 2550 2551 @safe unittest 2552 { 2553 auto s1 = "Mary has a little lamb"; 2554 assert(find(s1, "has a", "has an") == tuple("has a little lamb", 1)); 2555 assert(find(s1, 't', "has a", "has an") == tuple("has a little lamb", 2)); 2556 assert(find(s1, 't', "has a", 'y', "has an") == tuple("y has a little lamb", 3)); 2557 assert(find("abc", "bc").length == 2); 2558 } 2559 2560 @safe unittest 2561 { 2562 import std.algorithm.internal : rndstuff; 2563 import std.meta : AliasSeq; 2564 import std.uni : toUpper; 2565 2566 int[] a = [ 1, 2, 3 ]; 2567 assert(find(a, 5).empty); 2568 assert(find(a, 2) == [2, 3]); 2569 2570 foreach (T; AliasSeq!(int, double)) 2571 { 2572 auto b = rndstuff!(T)(); 2573 if (!b.length) continue; 2574 b[$ / 2] = 200; 2575 b[$ / 4] = 200; 2576 assert(find(b, 200).length == b.length - b.length / 4); 2577 } 2578 2579 // Case-insensitive find of a string 2580 string[] s = [ "Hello", "world", "!" ]; 2581 assert(find!("toUpper(a) == toUpper(b)")(s, "hello").length == 3); 2582 2583 static bool f(string a, string b) { return toUpper(a) == toUpper(b); } 2584 assert(find!(f)(s, "hello").length == 3); 2585 } 2586 2587 @safe unittest 2588 { 2589 import std.algorithm.comparison : equal; 2590 import std.algorithm.internal : rndstuff; 2591 import std.meta : AliasSeq; 2592 import std.range : retro; 2593 2594 int[] a = [ 1, 2, 3, 2, 6 ]; 2595 assert(find(retro(a), 5).empty); 2596 assert(equal(find(retro(a), 2), [ 2, 3, 2, 1 ][])); 2597 2598 foreach (T; AliasSeq!(int, double)) 2599 { 2600 auto b = rndstuff!(T)(); 2601 if (!b.length) continue; 2602 b[$ / 2] = 200; 2603 b[$ / 4] = 200; 2604 assert(find(retro(b), 200).length == 2605 b.length - (b.length - 1) / 2); 2606 } 2607 } 2608 2609 @safe unittest 2610 { 2611 import std.algorithm.comparison : equal; 2612 import std.internal.test.dummyrange; 2613 2614 int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; 2615 int[] b = [ 1, 2, 3 ]; 2616 assert(find(a, b) == [ 1, 2, 3, 4, 5 ]); 2617 assert(find(b, a).empty); 2618 2619 foreach (DummyType; AllDummyRanges) 2620 { 2621 DummyType d; 2622 auto findRes = find(d, 5); 2623 assert(equal(findRes, [5,6,7,8,9,10])); 2624 } 2625 } 2626 2627 /** 2628 * Finds `needle` in `haystack` efficiently using the 2629 * $(LINK2 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm, 2630 * Boyer-Moore) method. 2631 * 2632 * Params: 2633 * haystack = A random-access range with length and slicing. 2634 * needle = A $(LREF BoyerMooreFinder). 2635 * 2636 * Returns: 2637 * `haystack` advanced such that `needle` is a prefix of it (if no 2638 * such position exists, returns `haystack` advanced to termination). 2639 */ 2640 RandomAccessRange find(RandomAccessRange, alias pred, InputRange)( 2641 RandomAccessRange haystack, scope BoyerMooreFinder!(pred, InputRange) needle) 2642 { 2643 return needle.beFound(haystack); 2644 } 2645 2646 @safe unittest 2647 { 2648 string h = "/homes/aalexand/d/dmd/bin/../lib/libphobos.a(dmain2.o)"~ 2649 "(.gnu.linkonce.tmain+0x74): In function `main' undefined reference"~ 2650 " to `_Dmain':"; 2651 string[] ns = ["libphobos", "function", " undefined", "`", ":"]; 2652 foreach (n ; ns) 2653 { 2654 auto p = find(h, boyerMooreFinder(n)); 2655 assert(!p.empty); 2656 } 2657 } 2658 2659 /// 2660 @safe unittest 2661 { 2662 import std.range.primitives : empty; 2663 int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; 2664 int[] b = [ 1, 2, 3 ]; 2665 2666 assert(find(a, boyerMooreFinder(b)) == [ 1, 2, 3, 4, 5 ]); 2667 assert(find(b, boyerMooreFinder(a)).empty); 2668 } 2669 2670 @safe unittest 2671 { 2672 auto bm = boyerMooreFinder("for"); 2673 auto match = find("Moor", bm); 2674 assert(match.empty); 2675 } 2676 2677 // canFind 2678 /++ 2679 Convenience function. Like find, but only returns whether or not the search 2680 was successful. 2681 2682 For more information about `pred` see $(LREF find). 2683 2684 See_Also: 2685 $(REF among, std,algorithm,comparison) for checking a value against multiple arguments. 2686 +/ 2687 template canFind(alias pred="a == b") 2688 { 2689 /++ 2690 Returns `true` if and only if `pred(e)` is true for any value `e` in the 2691 input range `range`. 2692 Performs (at most) $(BIGOH haystack.length) evaluations of `pred`. 2693 +/ 2694 bool canFind(Range)(Range haystack) 2695 if (is(typeof(find!pred(haystack)))) 2696 { 2697 return any!pred(haystack); 2698 } 2699 2700 /++ 2701 Returns `true` if and only if `needle` can be found in $(D 2702 range). Performs $(BIGOH haystack.length) evaluations of `pred`. 2703 +/ 2704 bool canFind(Range, Element)(Range haystack, scope Element needle) 2705 if (is(typeof(find!pred(haystack, needle)))) 2706 { 2707 return !find!pred(haystack, needle).empty; 2708 } 2709 2710 /++ 2711 Returns the 1-based index of the first needle found in `haystack`. If no 2712 needle is found, then `0` is returned. 2713 2714 So, if used directly in the condition of an `if` statement or loop, the result 2715 will be `true` if one of the needles is found and `false` if none are 2716 found, whereas if the result is used elsewhere, it can either be cast to 2717 `bool` for the same effect or used to get which needle was found first 2718 without having to deal with the tuple that $(LREF find) returns for the 2719 same operation. 2720 +/ 2721 size_t canFind(Range, Needles...)(Range haystack, scope Needles needles) 2722 if (Needles.length > 1 && 2723 is(typeof(find!pred(haystack, needles)))) 2724 { 2725 return find!pred(haystack, needles)[1]; 2726 } 2727 } 2728 2729 /// 2730 @safe unittest 2731 { 2732 const arr = [0, 1, 2, 3]; 2733 assert(canFind(arr, 2)); 2734 assert(!canFind(arr, 4)); 2735 2736 // find one of several needles 2737 assert(arr.canFind(3, 2)); 2738 assert(arr.canFind(3, 2) == 2); // second needle found 2739 assert(arr.canFind([1, 3], 2) == 2); 2740 2741 assert(canFind(arr, [1, 2], [2, 3])); 2742 assert(canFind(arr, [1, 2], [2, 3]) == 1); 2743 assert(canFind(arr, [1, 7], [2, 3])); 2744 assert(canFind(arr, [1, 7], [2, 3]) == 2); 2745 assert(!canFind(arr, [1, 3], [2, 4])); 2746 assert(canFind(arr, [1, 3], [2, 4]) == 0); 2747 } 2748 2749 /** 2750 * Example using a custom predicate. 2751 * Note that the needle appears as the second argument of the predicate. 2752 */ 2753 @safe unittest 2754 { 2755 auto words = [ 2756 "apple", 2757 "beeswax", 2758 "cardboard" 2759 ]; 2760 assert(!canFind(words, "bees")); 2761 assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees")); 2762 } 2763 2764 /// Search for multiple items in an array of items (search for needles in an array of haystacks) 2765 @safe unittest 2766 { 2767 string s1 = "aaa111aaa"; 2768 string s2 = "aaa222aaa"; 2769 string s3 = "aaa333aaa"; 2770 string s4 = "aaa444aaa"; 2771 const hay = [s1, s2, s3, s4]; 2772 assert(hay.canFind!(e => e.canFind("111", "222"))); 2773 } 2774 2775 @safe unittest 2776 { 2777 import std.algorithm.internal : rndstuff; 2778 2779 auto a = rndstuff!(int)(); 2780 if (a.length) 2781 { 2782 auto b = a[a.length / 2]; 2783 assert(canFind(a, b)); 2784 } 2785 } 2786 2787 @safe unittest 2788 { 2789 import std.algorithm.comparison : equal; 2790 assert(equal!(canFind!"a < b")([[1, 2, 3], [7, 8, 9]], [2, 8])); 2791 } 2792 2793 // findAdjacent 2794 /** 2795 Advances `r` until it finds the first two adjacent elements `a`, 2796 `b` that satisfy `pred(a, b)`. Performs $(BIGOH r.length) 2797 evaluations of `pred`. 2798 2799 For more information about `pred` see $(LREF find). 2800 2801 Params: 2802 pred = The predicate to satisfy. 2803 r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to 2804 search in. 2805 2806 Returns: 2807 `r` advanced to the first occurrence of two adjacent elements that satisfy 2808 the given predicate. If there are no such two elements, returns `r` advanced 2809 until empty. 2810 2811 See_Also: 2812 $(LINK2 http://en.cppreference.com/w/cpp/algorithm/adjacent_find, STL's `adjacent_find`) 2813 */ 2814 Range findAdjacent(alias pred = "a == b", Range)(Range r) 2815 if (isForwardRange!(Range)) 2816 { 2817 auto ahead = r.save; 2818 if (!ahead.empty) 2819 { 2820 for (ahead.popFront(); !ahead.empty; r.popFront(), ahead.popFront()) 2821 { 2822 if (binaryFun!(pred)(r.front, ahead.front)) return r; 2823 } 2824 } 2825 static if (!isInfinite!Range) 2826 return ahead; 2827 assert(0); 2828 } 2829 2830 /// 2831 @safe unittest 2832 { 2833 int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ]; 2834 auto r = findAdjacent(a); 2835 assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]); 2836 auto p = findAdjacent!("a < b")(a); 2837 assert(p == [ 7, 8, 9 ]); 2838 2839 } 2840 2841 @safe unittest 2842 { 2843 import std.algorithm.comparison : equal; 2844 import std.internal.test.dummyrange; 2845 import std.range; 2846 2847 int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ]; 2848 auto p = findAdjacent(a); 2849 assert(p == [10, 10, 9, 8, 8, 7, 8, 9 ]); 2850 p = findAdjacent!("a < b")(a); 2851 assert(p == [7, 8, 9]); 2852 // empty 2853 a = []; 2854 p = findAdjacent(a); 2855 assert(p.empty); 2856 // not found 2857 a = [ 1, 2, 3, 4, 5 ]; 2858 p = findAdjacent(a); 2859 assert(p.empty); 2860 p = findAdjacent!"a > b"(a); 2861 assert(p.empty); 2862 ReferenceForwardRange!int rfr = new ReferenceForwardRange!int([1, 2, 3, 2, 2, 3]); 2863 assert(equal(findAdjacent(rfr), [2, 2, 3])); 2864 2865 // https://issues.dlang.org/show_bug.cgi?id=9350 2866 assert(!repeat(1).findAdjacent().empty); 2867 } 2868 2869 // findAmong 2870 /** 2871 Searches the given range for an element that matches one of the given choices. 2872 2873 Advances `seq` by calling `seq.popFront` until either 2874 `find!(pred)(choices, seq.front)` is `true`, or `seq` becomes empty. 2875 Performs $(BIGOH seq.length * choices.length) evaluations of `pred`. 2876 2877 For more information about `pred` see $(LREF find). 2878 2879 Params: 2880 pred = The predicate to use for determining a match. 2881 seq = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to 2882 search. 2883 choices = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) 2884 of possible choices. 2885 2886 Returns: 2887 `seq` advanced to the first matching element, or until empty if there are no 2888 matching elements. 2889 2890 See_Also: $(LREF find), $(REF among, std,algorithm,comparison) 2891 */ 2892 InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)( 2893 InputRange seq, ForwardRange choices) 2894 if (isInputRange!InputRange && isForwardRange!ForwardRange) 2895 { 2896 for (; !seq.empty && find!pred(choices.save, seq.front).empty; seq.popFront()) 2897 { 2898 } 2899 return seq; 2900 } 2901 2902 /// 2903 @safe unittest 2904 { 2905 int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; 2906 int[] b = [ 3, 1, 2 ]; 2907 assert(findAmong(a, b) == a[2 .. $]); 2908 } 2909 2910 @safe unittest 2911 { 2912 int[] a = [ -1, 0, 2, 1, 2, 3, 4, 5 ]; 2913 int[] b = [ 1, 2, 3 ]; 2914 assert(findAmong(a, b) == [2, 1, 2, 3, 4, 5 ]); 2915 assert(findAmong(b, [ 4, 6, 7 ][]).empty); 2916 assert(findAmong!("a == b")(a, b).length == a.length - 2); 2917 assert(findAmong!("a == b")(b, [ 4, 6, 7 ][]).empty); 2918 } 2919 2920 // https://issues.dlang.org/show_bug.cgi?id=19765 2921 @system unittest 2922 { 2923 import std.range.interfaces : inputRangeObject; 2924 auto choices = inputRangeObject("b"); 2925 auto f = "foobar".findAmong(choices); 2926 assert(f == "bar"); 2927 } 2928 2929 // findSkip 2930 /** 2931 * Finds `needle` in `haystack` and positions `haystack` 2932 * right after the first occurrence of `needle`. 2933 * 2934 * If no needle is provided, the `haystack` is advanced as long as `pred` 2935 * evaluates to `true`. 2936 * Similarly, the haystack is positioned so as `pred` evaluates to `false` for 2937 * `haystack.front`. 2938 * 2939 * For more information about `pred` see $(LREF find). 2940 2941 * Params: 2942 * haystack = The 2943 * $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search 2944 * in. 2945 * needle = The 2946 * $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search 2947 * for. 2948 * pred = Custom predicate for comparison of haystack and needle 2949 * 2950 * Returns: `true` if the needle was found, in which case `haystack` is 2951 * positioned after the end of the first occurrence of `needle`; otherwise 2952 * `false`, leaving `haystack` untouched. If no needle is provided, it returns 2953 * the number of times `pred(haystack.front)` returned true. 2954 * 2955 * See_Also: $(LREF find) 2956 */ 2957 bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle) 2958 if (isForwardRange!R1 && isForwardRange!R2 2959 && is(typeof(binaryFun!pred(haystack.front, needle.front)))) 2960 { 2961 auto parts = findSplit!pred(haystack, needle); 2962 if (parts[1].empty) return false; 2963 // found 2964 haystack = parts[2]; 2965 return true; 2966 } 2967 2968 /// 2969 @safe unittest 2970 { 2971 import std.range.primitives : empty; 2972 // Needle is found; s is replaced by the substring following the first 2973 // occurrence of the needle. 2974 string s = "abcdef"; 2975 assert(findSkip(s, "cd") && s == "ef"); 2976 2977 // Needle is not found; s is left untouched. 2978 s = "abcdef"; 2979 assert(!findSkip(s, "cxd") && s == "abcdef"); 2980 2981 // If the needle occurs at the end of the range, the range is left empty. 2982 s = "abcdef"; 2983 assert(findSkip(s, "def") && s.empty); 2984 } 2985 2986 // https://issues.dlang.org/show_bug.cgi?id=19020 2987 @safe unittest 2988 { 2989 static struct WrapperRange 2990 { 2991 string _r; 2992 @property auto empty() { return _r.empty(); } 2993 @property auto front() { return _r.front(); } 2994 auto popFront() { return _r.popFront(); } 2995 @property auto save() { return WrapperRange(_r.save); } 2996 } 2997 auto tmp = WrapperRange("there is a bug here: *"); 2998 assert(!tmp.findSkip("*/")); 2999 assert(tmp._r == "there is a bug here: *"); 3000 } 3001 3002 /// ditto 3003 size_t findSkip(alias pred, R1)(ref R1 haystack) 3004 if (isForwardRange!R1 && ifTestable!(typeof(haystack.front), unaryFun!pred)) 3005 { 3006 size_t result; 3007 while (!haystack.empty && unaryFun!pred(haystack.front)) 3008 { 3009 result++; 3010 haystack.popFront; 3011 } 3012 return result; 3013 } 3014 3015 /// 3016 @safe unittest 3017 { 3018 import std.ascii : isWhite; 3019 string s = " abc"; 3020 assert(findSkip!isWhite(s) && s == "abc"); 3021 assert(!findSkip!isWhite(s) && s == "abc"); 3022 3023 s = " "; 3024 assert(findSkip!isWhite(s) == 2); 3025 } 3026 3027 @safe unittest 3028 { 3029 import std.ascii : isWhite; 3030 3031 auto s = " "; 3032 assert(findSkip!isWhite(s) == 2); 3033 } 3034 3035 private struct FindSplitResult(ubyte emptyRangeIndex, Types...) 3036 { 3037 this(Types vals) 3038 { 3039 asTuple = typeof(asTuple)(vals); 3040 } 3041 void opAssign(typeof(asTuple) rhs) 3042 { 3043 asTuple = rhs; 3044 } 3045 Tuple!Types asTuple; 3046 alias asTuple this; 3047 3048 static if (hasConstEmptyMember!(typeof(asTuple[emptyRangeIndex]))) 3049 { 3050 bool opCast(T : bool)() const => !asTuple[emptyRangeIndex].empty; 3051 } 3052 else 3053 { 3054 bool opCast(T : bool)() => !asTuple[emptyRangeIndex].empty; 3055 } 3056 } 3057 3058 /** 3059 These functions find the first occurrence of `needle` in `haystack` and then 3060 split `haystack` as follows. 3061 3062 $(PANEL 3063 `findSplit` returns a tuple `result` containing $(I three) ranges. 3064 $(UL 3065 $(LI `result[0]` is the portion of `haystack` before `needle`) 3066 $(LI `result[1]` is the portion of 3067 `haystack` that matches `needle`) 3068 $(LI `result[2]` is the portion of `haystack` 3069 after the match.) 3070 ) 3071 If `needle` was not found, `result[0]` comprehends `haystack` 3072 entirely and `result[1]` and `result[2]` are empty. 3073 3074 `findSplitBefore` returns a tuple `result` containing two ranges. 3075 $(UL 3076 $(LI `result[0]` is the portion of `haystack` before `needle`) 3077 $(LI `result[1]` is the balance of `haystack` starting with the match.) 3078 ) 3079 If `needle` was not found, `result[0]` 3080 comprehends `haystack` entirely and `result[1]` is empty. 3081 3082 `findSplitAfter` returns a tuple `result` containing two ranges. 3083 $(UL 3084 $(LI `result[0]` is the portion of `haystack` up to and including the 3085 match) 3086 $(LI `result[1]` is the balance of `haystack` starting 3087 after the match.) 3088 ) 3089 If `needle` was not found, `result[0]` is empty 3090 and `result[1]` is `haystack`. 3091 ) 3092 $(P 3093 In all cases, the concatenation of the returned ranges spans the 3094 entire `haystack`. 3095 3096 If `haystack` is a random-access range, all three components of the tuple have 3097 the same type as `haystack`. Otherwise, `haystack` must be a 3098 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and 3099 the type of `result[0]` (and `result[1]` for `findSplit`) is the same as 3100 the result of $(REF takeExactly, std,range). 3101 3102 For more information about `pred` see $(LREF find). 3103 ) 3104 Params: 3105 pred = Predicate to compare 2 elements. 3106 haystack = The forward range to search. 3107 needle = The forward range to look for. 3108 3109 Returns: 3110 3111 A sub-type of $(REF Tuple, std, typecons) of the split portions of `haystack` (see above for 3112 details). This sub-type of `Tuple` defines `opCast!bool`, which 3113 returns `true` when the separating `needle` was found and `false` otherwise. 3114 3115 See_Also: $(LREF find) 3116 */ 3117 auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 3118 if (isForwardRange!R1 && isForwardRange!R2) 3119 { 3120 static if (isSomeString!R1 && isSomeString!R2 3121 || (isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && hasLength!R2)) 3122 { 3123 auto balance = find!pred(haystack, needle); 3124 immutable pos1 = haystack.length - balance.length; 3125 immutable pos2 = balance.empty ? pos1 : pos1 + needle.length; 3126 alias Slice = typeof(haystack[0 .. pos1]); 3127 return FindSplitResult!(1, Slice, Slice, Slice)( 3128 haystack[0 .. pos1], haystack[pos1 .. pos2], haystack[pos2 .. haystack.length]); 3129 } 3130 else 3131 { 3132 import std.range : takeExactly; 3133 auto original = haystack.save; 3134 auto h = haystack.save; 3135 auto n = needle.save; 3136 size_t pos1, pos2; 3137 while (!n.empty && !h.empty) 3138 { 3139 if (binaryFun!pred(h.front, n.front)) 3140 { 3141 h.popFront(); 3142 n.popFront(); 3143 ++pos2; 3144 } 3145 else 3146 { 3147 haystack.popFront(); 3148 n = needle.save; 3149 h = haystack.save; 3150 pos2 = ++pos1; 3151 } 3152 } 3153 if (!n.empty) // incomplete match at the end of haystack 3154 { 3155 pos1 = pos2; 3156 } 3157 return FindSplitResult!(1, 3158 typeof(takeExactly(original, pos1)), 3159 typeof(takeExactly(original, pos1)), typeof(h))( 3160 takeExactly(original, pos1), 3161 takeExactly(haystack, pos2 - pos1), h); 3162 } 3163 } 3164 3165 /// Ditto 3166 auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 3167 if (isForwardRange!R1 && isForwardRange!R2) 3168 { 3169 static if (isSomeString!R1 && isSomeString!R2 3170 || (isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2)) 3171 { 3172 auto balance = find!pred(haystack, needle); 3173 immutable pos = haystack.length - balance.length; 3174 return FindSplitResult!(1, 3175 typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))( 3176 haystack[0 .. pos], haystack[pos .. haystack.length]); 3177 } 3178 else 3179 { 3180 import std.range : takeExactly; 3181 auto original = haystack.save; 3182 auto h = haystack.save; 3183 auto n = needle.save; 3184 size_t pos1, pos2; 3185 while (!n.empty && !h.empty) 3186 { 3187 if (binaryFun!pred(h.front, n.front)) 3188 { 3189 h.popFront(); 3190 n.popFront(); 3191 ++pos2; 3192 } 3193 else 3194 { 3195 haystack.popFront(); 3196 n = needle.save; 3197 h = haystack.save; 3198 pos2 = ++pos1; 3199 } 3200 } 3201 if (!n.empty) // incomplete match at the end of haystack 3202 { 3203 pos1 = pos2; 3204 haystack = h; 3205 } 3206 return FindSplitResult!(1, 3207 typeof(takeExactly(original, pos1)), typeof(haystack))( 3208 takeExactly(original, pos1), haystack); 3209 } 3210 } 3211 3212 /// Ditto 3213 auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 3214 if (isForwardRange!R1 && isForwardRange!R2) 3215 { 3216 static if (isSomeString!R1 && isSomeString!R2 3217 || isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2) 3218 { 3219 auto balance = find!pred(haystack, needle); 3220 immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length; 3221 return FindSplitResult!(0, 3222 typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))( 3223 haystack[0 .. pos], haystack[pos .. haystack.length]); 3224 } 3225 else 3226 { 3227 import std.range : takeExactly; 3228 alias Res = FindSplitResult!(0, typeof(takeExactly(haystack, 0)), typeof(haystack)); 3229 auto original = haystack.save; 3230 auto h = haystack.save; 3231 auto n = needle.save; 3232 size_t pos1, pos2; 3233 while (!n.empty) 3234 { 3235 if (h.empty) 3236 { 3237 // Failed search 3238 return Res(takeExactly(original, 0), original); 3239 } 3240 if (binaryFun!pred(h.front, n.front)) 3241 { 3242 h.popFront(); 3243 n.popFront(); 3244 ++pos2; 3245 } 3246 else 3247 { 3248 haystack.popFront(); 3249 n = needle.save; 3250 h = haystack.save; 3251 pos2 = ++pos1; 3252 } 3253 } 3254 return Res(takeExactly(original, pos2), h); 3255 } 3256 } 3257 3258 /// Returning a subtype of $(REF Tuple, std,typecons) enables 3259 /// the following convenient idiom: 3260 @safe pure nothrow unittest 3261 { 3262 // findSplit returns a triplet 3263 if (auto split = "dlang-rocks".findSplit("-")) 3264 { 3265 assert(split[0] == "dlang"); 3266 assert(split[1] == "-"); 3267 assert(split[2] == "rocks"); 3268 } 3269 else assert(0); 3270 3271 // findSplitBefore returns 2 ranges 3272 if (const split = [2, 3, 2, 3, 4, 1].findSplitBefore!"a > b"([2, 2])) 3273 { 3274 assert(split[0] == [2, 3, 2]); 3275 // [3, 4] each greater than [2, 2] 3276 assert(split[1] == [3, 4, 1]); 3277 } 3278 else assert(0); 3279 } 3280 3281 /// 3282 @safe pure nothrow unittest 3283 { 3284 import std.range.primitives : empty; 3285 3286 auto a = "Carl Sagan Memorial Station"; 3287 auto r = findSplit(a, "Velikovsky"); 3288 import std.typecons : isTuple; 3289 static assert(isTuple!(typeof(r.asTuple))); 3290 static assert(isTuple!(typeof(r))); 3291 assert(!r); 3292 assert(r[0] == a); 3293 assert(r[1].empty); 3294 assert(r[2].empty); 3295 r = findSplit(a, " "); 3296 assert(r[0] == "Carl"); 3297 assert(r[1] == " "); 3298 assert(r[2] == "Sagan Memorial Station"); 3299 if (const r1 = findSplitBefore(a, "Sagan")) 3300 { 3301 assert(r1); 3302 assert(r1[0] == "Carl "); 3303 assert(r1[1] == "Sagan Memorial Station"); 3304 } 3305 if (const r2 = findSplitAfter(a, "Sagan")) 3306 { 3307 assert(r2); 3308 assert(r2[0] == "Carl Sagan"); 3309 assert(r2[1] == " Memorial Station"); 3310 } 3311 } 3312 3313 /// Use $(REF only, std,range) to find single elements: 3314 @safe pure nothrow unittest 3315 { 3316 import std.range : only; 3317 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); 3318 } 3319 3320 @safe pure nothrow unittest 3321 { 3322 import std.range.primitives : empty; 3323 3324 immutable a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 3325 auto r = findSplit(a, [9, 1]); 3326 assert(!r); 3327 assert(r[0] == a); 3328 assert(r[1].empty); 3329 assert(r[2].empty); 3330 r = findSplit(a, [3]); 3331 assert(r); 3332 assert(r[0] == a[0 .. 2]); 3333 assert(r[1] == a[2 .. 3]); 3334 assert(r[2] == a[3 .. $]); 3335 3336 { 3337 const r1 = findSplitBefore(a, [9, 1]); 3338 assert(!r1); 3339 assert(r1[0] == a); 3340 assert(r1[1].empty); 3341 } 3342 3343 if (immutable r1 = findSplitBefore(a, [3, 4])) 3344 { 3345 assert(r1); 3346 assert(r1[0] == a[0 .. 2]); 3347 assert(r1[1] == a[2 .. $]); 3348 } 3349 else assert(0); 3350 3351 { 3352 const r2 = findSplitAfter(a, [9, 1]); 3353 assert(!r2); 3354 assert(r2[0].empty); 3355 assert(r2[1] == a); 3356 } 3357 3358 if (immutable r3 = findSplitAfter(a, [3, 4])) 3359 { 3360 assert(r3); 3361 assert(r3[0] == a[0 .. 4]); 3362 assert(r3[1] == a[4 .. $]); 3363 } 3364 else assert(0); 3365 } 3366 3367 @safe pure nothrow unittest 3368 { 3369 import std.algorithm.comparison : equal; 3370 import std.algorithm.iteration : filter; 3371 3372 auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 3373 auto fwd = filter!"a > 0"(a); 3374 auto r = findSplit(fwd, [9, 1]); 3375 assert(!r); 3376 assert(equal(r[0], a)); 3377 assert(r[1].empty); 3378 assert(r[2].empty); 3379 r = findSplit(fwd, [3]); 3380 assert(r); 3381 assert(equal(r[0], a[0 .. 2])); 3382 assert(equal(r[1], a[2 .. 3])); 3383 assert(equal(r[2], a[3 .. $])); 3384 r = findSplit(fwd, [8, 9]); 3385 assert(!r); 3386 assert(equal(r[0], a)); 3387 assert(r[1].empty); 3388 assert(r[2].empty); 3389 3390 // auto variable `r2` cannot be `const` because `fwd.front` is mutable 3391 { 3392 auto r1 = findSplitBefore(fwd, [9, 1]); 3393 assert(!r1); 3394 assert(equal(r1[0], a)); 3395 assert(r1[1].empty); 3396 } 3397 3398 if (auto r1 = findSplitBefore(fwd, [3, 4])) 3399 { 3400 assert(r1); 3401 assert(equal(r1[0], a[0 .. 2])); 3402 assert(equal(r1[1], a[2 .. $])); 3403 } 3404 else assert(0); 3405 3406 { 3407 auto r1 = findSplitBefore(fwd, [8, 9]); 3408 assert(!r1); 3409 assert(equal(r1[0], a)); 3410 assert(r1[1].empty); 3411 } 3412 3413 { 3414 auto r2 = findSplitAfter(fwd, [9, 1]); 3415 assert(!r2); 3416 assert(r2[0].empty); 3417 assert(equal(r2[1], a)); 3418 } 3419 3420 if (auto r2 = findSplitAfter(fwd, [3, 4])) 3421 { 3422 assert(r2); 3423 assert(equal(r2[0], a[0 .. 4])); 3424 assert(equal(r2[1], a[4 .. $])); 3425 } 3426 else assert(0); 3427 3428 { 3429 auto r2 = findSplitAfter(fwd, [8, 9]); 3430 assert(!r2); 3431 assert(r2[0].empty); 3432 assert(equal(r2[1], a)); 3433 } 3434 } 3435 3436 @safe pure nothrow @nogc unittest 3437 { 3438 auto str = "sep,one,sep,two"; 3439 3440 auto split = str.findSplitAfter(","); 3441 assert(split[0] == "sep,"); 3442 3443 split = split[1].findSplitAfter(","); 3444 assert(split[0] == "one,"); 3445 3446 split = split[1].findSplitBefore(","); 3447 assert(split[0] == "sep"); 3448 } 3449 3450 @safe pure nothrow @nogc unittest 3451 { 3452 auto str = "sep,one,sep,two"; 3453 3454 auto split = str.findSplitBefore(",two"); 3455 assert(split[0] == "sep,one,sep"); 3456 assert(split[1] == ",two"); 3457 3458 split = split[0].findSplitBefore(",sep"); 3459 assert(split[0] == "sep,one"); 3460 assert(split[1] == ",sep"); 3461 3462 split = split[0].findSplitAfter(","); 3463 assert(split[0] == "sep,"); 3464 assert(split[1] == "one"); 3465 } 3466 3467 // https://issues.dlang.org/show_bug.cgi?id=11013 3468 @safe pure unittest 3469 { 3470 auto var = "abc"; 3471 auto split = var.findSplitBefore!q{a == a}(var); 3472 assert(split[0] == ""); 3473 assert(split[1] == "abc"); 3474 } 3475 3476 // minCount 3477 /** 3478 3479 Computes the minimum (respectively maximum) of `range` along with its number of 3480 occurrences. Formally, the minimum is a value `x` in `range` such that $(D 3481 pred(a, x)) is `false` for all values `a` in `range`. Conversely, the maximum is 3482 a value `x` in `range` such that `pred(x, a)` is `false` for all values `a` 3483 in `range` (note the swapped arguments to `pred`). 3484 3485 These functions may be used for computing arbitrary extrema by choosing `pred` 3486 appropriately. For corrrect functioning, `pred` must be a strict partial order, 3487 i.e. transitive (if `pred(a, b) && pred(b, c)` then `pred(a, c)`) and 3488 irreflexive (`pred(a, a)` is `false`). The $(LUCKY trichotomy property of 3489 inequality) is not required: these algorithms consider elements `a` and `b` equal 3490 (for the purpose of counting) if `pred` puts them in the same equivalence class, 3491 i.e. `!pred(a, b) && !pred(b, a)`. 3492 3493 Params: 3494 pred = The ordering predicate to use to determine the extremum (minimum 3495 or maximum). 3496 range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to count. 3497 3498 Returns: The minimum, respectively maximum element of a range together with the 3499 number it occurs in the range. 3500 3501 Limitations: If at least one of the arguments is NaN, the result is 3502 an unspecified value. See $(REF maxElement, std,algorithm,searching) 3503 for examples on how to cope with NaNs. 3504 3505 Throws: `Exception` if `range.empty`. 3506 3507 See_Also: $(REF min, std,algorithm,comparison), $(LREF minIndex), $(LREF minElement), $(LREF minPos) 3508 */ 3509 Tuple!(ElementType!Range, size_t) 3510 minCount(alias pred = "a < b", Range)(Range range) 3511 if (isInputRange!Range && !isInfinite!Range && 3512 is(typeof(binaryFun!pred(range.front, range.front)))) 3513 { 3514 import std.algorithm.internal : algoFormat; 3515 import std.exception : enforce; 3516 3517 alias T = ElementType!Range; 3518 alias UT = Unqual!T; 3519 alias RetType = Tuple!(T, size_t); 3520 3521 static assert(is(typeof(RetType(range.front, 1))), 3522 algoFormat("Error: Cannot call minCount on a %s, because it is not possible "~ 3523 "to copy the result value (a %s) into a Tuple.", Range.stringof, T.stringof)); 3524 3525 enforce(!range.empty, "Can't count elements from an empty range"); 3526 size_t occurrences = 1; 3527 3528 static if (isForwardRange!Range) 3529 { 3530 Range least = range.save; 3531 for (range.popFront(); !range.empty; range.popFront()) 3532 { 3533 if (binaryFun!pred(least.front, range.front)) 3534 { 3535 assert(!binaryFun!pred(range.front, least.front), 3536 "min/maxPos: predicate must be a strict partial order."); 3537 continue; 3538 } 3539 if (binaryFun!pred(range.front, least.front)) 3540 { 3541 // change the min 3542 least = range.save; 3543 occurrences = 1; 3544 } 3545 else 3546 ++occurrences; 3547 } 3548 return RetType(least.front, occurrences); 3549 } 3550 else static if (isAssignable!(UT, T) || (!hasElaborateAssign!UT && isAssignable!UT)) 3551 { 3552 UT v = UT.init; 3553 static if (isAssignable!(UT, T)) v = range.front; 3554 else v = cast(UT) range.front; 3555 3556 for (range.popFront(); !range.empty; range.popFront()) 3557 { 3558 if (binaryFun!pred(*cast(T*)&v, range.front)) continue; 3559 if (binaryFun!pred(range.front, *cast(T*)&v)) 3560 { 3561 // change the min 3562 static if (isAssignable!(UT, T)) v = range.front; 3563 else v = cast(UT) range.front; //Safe because !hasElaborateAssign!UT 3564 occurrences = 1; 3565 } 3566 else 3567 ++occurrences; 3568 } 3569 return RetType(*cast(T*)&v, occurrences); 3570 } 3571 else static if (hasLvalueElements!Range) 3572 { 3573 import std.algorithm.internal : addressOf; 3574 T* p = addressOf(range.front); 3575 for (range.popFront(); !range.empty; range.popFront()) 3576 { 3577 if (binaryFun!pred(*p, range.front)) continue; 3578 if (binaryFun!pred(range.front, *p)) 3579 { 3580 // change the min 3581 p = addressOf(range.front); 3582 occurrences = 1; 3583 } 3584 else 3585 ++occurrences; 3586 } 3587 return RetType(*p, occurrences); 3588 } 3589 else 3590 static assert(false, 3591 algoFormat("Sorry, can't find the minCount of a %s: Don't know how "~ 3592 "to keep track of the smallest %s element.", Range.stringof, T.stringof)); 3593 } 3594 3595 /// Ditto 3596 Tuple!(ElementType!Range, size_t) 3597 maxCount(alias pred = "a < b", Range)(Range range) 3598 if (isInputRange!Range && !isInfinite!Range && 3599 is(typeof(binaryFun!pred(range.front, range.front)))) 3600 { 3601 return range.minCount!((a, b) => binaryFun!pred(b, a)); 3602 } 3603 3604 /// 3605 @safe unittest 3606 { 3607 import std.conv : text; 3608 import std.typecons : tuple; 3609 3610 int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; 3611 // Minimum is 1 and occurs 3 times 3612 assert(a.minCount == tuple(1, 3)); 3613 // Maximum is 4 and occurs 2 times 3614 assert(a.maxCount == tuple(4, 2)); 3615 } 3616 3617 @system unittest 3618 { 3619 import std.conv : text; 3620 import std.exception : assertThrown; 3621 import std.internal.test.dummyrange; 3622 3623 int[][] b = [ [4], [2, 4], [4], [4] ]; 3624 auto c = minCount!("a[0] < b[0]")(b); 3625 assert(c == tuple([2, 4], 1), text(c[0])); 3626 3627 //Test empty range 3628 assertThrown(minCount(b[$..$])); 3629 3630 //test with reference ranges. Test both input and forward. 3631 assert(minCount(new ReferenceInputRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2)); 3632 assert(minCount(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2)); 3633 } 3634 3635 @system unittest 3636 { 3637 import std.conv : text; 3638 import std.meta : AliasSeq; 3639 3640 static struct R(T) //input range 3641 { 3642 T[] arr; 3643 alias arr this; 3644 } 3645 3646 immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; 3647 R!(immutable int) b = R!(immutable int)(a); 3648 3649 assert(minCount(a) == tuple(1, 3)); 3650 assert(minCount(b) == tuple(1, 3)); 3651 assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(a) == tuple(4, 2)); 3652 assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(b) == tuple(4, 2)); 3653 3654 immutable(int[])[] c = [ [4], [2, 4], [4], [4] ]; 3655 assert(minCount!("a[0] < b[0]")(c) == tuple([2, 4], 1), text(c[0])); 3656 3657 static struct S1 3658 { 3659 int i; 3660 } 3661 alias IS1 = immutable(S1); 3662 static assert( isAssignable!S1); 3663 static assert( isAssignable!(S1, IS1)); 3664 3665 static struct S2 3666 { 3667 int* p; 3668 this(ref immutable int i) immutable {p = &i;} 3669 this(ref int i) {p = &i;} 3670 @property ref inout(int) i() inout {return *p;} 3671 bool opEquals(const S2 other) const {return i == other.i;} 3672 } 3673 alias IS2 = immutable(S2); 3674 static assert( isAssignable!S2); 3675 static assert(!isAssignable!(S2, IS2)); 3676 static assert(!hasElaborateAssign!S2); 3677 3678 static struct S3 3679 { 3680 int i; 3681 void opAssign(ref S3 other) @disable; 3682 } 3683 static assert(!isAssignable!S3); 3684 3685 static foreach (Type; AliasSeq!(S1, IS1, S2, IS2, S3)) 3686 {{ 3687 static if (is(Type == immutable)) alias V = immutable int; 3688 else alias V = int; 3689 V one = 1, two = 2; 3690 auto r1 = [Type(two), Type(one), Type(one)]; 3691 auto r2 = R!Type(r1); 3692 assert(minCount!"a.i < b.i"(r1) == tuple(Type(one), 2)); 3693 assert(minCount!"a.i < b.i"(r2) == tuple(Type(one), 2)); 3694 assert(one == 1 && two == 2); 3695 }} 3696 } 3697 3698 /** 3699 Iterates the passed range and returns the minimal element. 3700 A custom mapping function can be passed to `map`. 3701 In other languages this is sometimes called `argmin`. 3702 3703 Complexity: O(n) 3704 Exactly `n - 1` comparisons are needed. 3705 3706 Params: 3707 map = custom accessor for the comparison key 3708 r = range from which the minimal element will be selected 3709 seed = custom seed to use as initial element 3710 3711 Precondition: If a seed is not given, `r` must not be empty. 3712 3713 Returns: The minimal element of the passed-in range. 3714 3715 Note: 3716 If at least one of the arguments is NaN, the result is an unspecified value. 3717 3718 If you want to ignore NaNs, you can use $(REF filter, std,algorithm,iteration) 3719 and $(REF isNaN, std,math) to remove them, before applying minElement. 3720 Add a suitable seed, to avoid error messages if all elements are NaNs: 3721 3722 --- 3723 <range>.filter!(a=>!a.isNaN).minElement(<seed>); 3724 --- 3725 3726 If you want to get NaN as a result if a NaN is present in the range, 3727 you can use $(REF fold, std,algorithm,iteration) and $(REF isNaN, std,math): 3728 3729 --- 3730 <range>.fold!((a,b)=>a.isNaN || b.isNaN ? real.nan : a < b ? a : b); 3731 --- 3732 3733 See_Also: 3734 3735 $(LREF extrema), $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount), 3736 $(LREF minIndex), $(LREF minPos) 3737 */ 3738 auto minElement(alias map = (a => a), Range)(Range r) 3739 if (isInputRange!Range && !isInfinite!Range) 3740 { 3741 return extremum!map(r); 3742 } 3743 3744 /// ditto 3745 auto minElement(alias map = (a => a), Range, RangeElementType = ElementType!Range) 3746 (Range r, RangeElementType seed) 3747 if (isInputRange!Range && !isInfinite!Range && 3748 !is(CommonType!(ElementType!Range, RangeElementType) == void)) 3749 { 3750 return extremum!map(r, seed); 3751 } 3752 3753 /// 3754 @safe pure unittest 3755 { 3756 import std.range : enumerate; 3757 import std.typecons : tuple; 3758 3759 assert([2, 7, 1, 3].minElement == 1); 3760 3761 // allows to get the index of an element too 3762 assert([5, 3, 7, 9].enumerate.minElement!"a.value" == tuple(1, 3)); 3763 3764 // any custom accessor can be passed 3765 assert([[0, 4], [1, 2]].minElement!"a[1]" == [1, 2]); 3766 3767 // can be seeded 3768 int[] arr; 3769 assert(arr.minElement(1) == 1); 3770 } 3771 3772 @safe pure unittest 3773 { 3774 import std.range : enumerate, iota; 3775 // supports mapping 3776 assert([3, 4, 5, 1, 2].enumerate.minElement!"a.value" == tuple(3, 1)); 3777 assert([5, 2, 4].enumerate.minElement!"a.value" == tuple(1, 2)); 3778 3779 // forward ranges 3780 assert(iota(1, 5).minElement() == 1); 3781 assert(iota(2, 5).enumerate.minElement!"a.value" == tuple(0, 2)); 3782 3783 // should work with const 3784 const(int)[] immArr = [2, 1, 3]; 3785 assert(immArr.minElement == 1); 3786 3787 // should work with immutable 3788 immutable(int)[] immArr2 = [2, 1, 3]; 3789 assert(immArr2.minElement == 1); 3790 3791 // with strings 3792 assert(["b", "a", "c"].minElement == "a"); 3793 3794 // with all dummy ranges 3795 import std.internal.test.dummyrange; 3796 foreach (DummyType; AllDummyRanges) 3797 { 3798 DummyType d; 3799 assert(d.minElement == 1); 3800 assert(d.minElement!(a => a) == 1); 3801 assert(d.minElement!(a => -a) == 10); 3802 } 3803 3804 // with empty, but seeded ranges 3805 int[] arr; 3806 assert(arr.minElement(42) == 42); 3807 assert(arr.minElement!(a => a)(42) == 42); 3808 } 3809 3810 @nogc @safe nothrow pure unittest 3811 { 3812 static immutable arr = [7, 3, 4, 2, 1, 8]; 3813 assert(arr.minElement == 1); 3814 3815 static immutable arr2d = [[1, 9], [3, 1], [4, 2]]; 3816 assert(arr2d.minElement!"a[1]" == arr2d[1]); 3817 } 3818 3819 // https://issues.dlang.org/show_bug.cgi?id=17982 3820 @safe unittest 3821 { 3822 struct A 3823 { 3824 int val; 3825 } 3826 3827 const(A)[] v = [A(0)]; 3828 assert(v.minElement!"a.val" == A(0)); 3829 } 3830 3831 // https://issues.dlang.org/show_bug.cgi?id=17982 3832 @safe unittest 3833 { 3834 class B 3835 { 3836 int val; 3837 this(int val){ this.val = val; } 3838 } 3839 3840 const(B) doStuff(const(B)[] v) 3841 { 3842 return v.minElement!"a.val"; 3843 } 3844 assert(doStuff([new B(1), new B(0), new B(2)]).val == 0); 3845 3846 const(B)[] arr = [new B(0), new B(1)]; 3847 // can't compare directly - https://issues.dlang.org/show_bug.cgi?id=1824 3848 assert(arr.minElement!"a.val".val == 0); 3849 } 3850 3851 // https://issues.dlang.org/show_bug.cgi?id=24827 3852 @safe unittest 3853 { 3854 static struct S 3855 { 3856 int i; 3857 bool destroyed; 3858 3859 this(int i) @safe 3860 { 3861 this.i = i; 3862 } 3863 3864 ~this() @safe 3865 { 3866 destroyed = true; 3867 } 3868 3869 bool opEquals()(auto ref S rhs) 3870 { 3871 return this.i == rhs.i; 3872 } 3873 3874 int opCmp()(auto ref S rhs) 3875 { 3876 if (this.i < rhs.i) 3877 return -1; 3878 3879 return this.i == rhs.i ? 0 : 1; 3880 } 3881 3882 @safe invariant 3883 { 3884 assert(!destroyed); 3885 } 3886 } 3887 3888 auto arr = [S(19), S(2), S(145), S(7)]; 3889 assert(minElement(arr) == S(2)); 3890 } 3891 3892 /** 3893 Iterates the passed range and returns the maximal element. 3894 A custom mapping function can be passed to `map`. 3895 In other languages this is sometimes called `argmax`. 3896 3897 Complexity: O(n) 3898 Exactly `n - 1` comparisons are needed. 3899 3900 Params: 3901 map = custom accessor for the comparison key 3902 r = range from which the maximum element will be selected 3903 seed = custom seed to use as initial element 3904 3905 Precondition: If a seed is not given, `r` must not be empty. 3906 3907 Returns: The maximal element of the passed-in range. 3908 3909 Note: 3910 If at least one of the arguments is NaN, the result is an unspecified value. 3911 See $(REF minElement, std,algorithm,searching) for examples on how to cope 3912 with NaNs. 3913 3914 See_Also: 3915 3916 $(LREF extrema), $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount), 3917 $(LREF maxIndex), $(LREF maxPos) 3918 */ 3919 auto maxElement(alias map = (a => a), Range)(Range r) 3920 if (isInputRange!Range && !isInfinite!Range) 3921 { 3922 return extremum!(map, "a > b")(r); 3923 } 3924 3925 /// ditto 3926 auto maxElement(alias map = (a => a), Range, RangeElementType = ElementType!Range) 3927 (Range r, RangeElementType seed) 3928 if (isInputRange!Range && !isInfinite!Range && 3929 !is(CommonType!(ElementType!Range, RangeElementType) == void)) 3930 { 3931 return extremum!(map, "a > b")(r, seed); 3932 } 3933 3934 /// 3935 @safe pure unittest 3936 { 3937 import std.range : enumerate; 3938 import std.typecons : tuple; 3939 assert([2, 1, 4, 3].maxElement == 4); 3940 3941 // allows to get the index of an element too 3942 assert([2, 1, 4, 3].enumerate.maxElement!"a.value" == tuple(2, 4)); 3943 3944 // any custom accessor can be passed 3945 assert([[0, 4], [1, 2]].maxElement!"a[1]" == [0, 4]); 3946 3947 // can be seeded 3948 int[] arr; 3949 assert(arr.minElement(1) == 1); 3950 } 3951 3952 @safe pure unittest 3953 { 3954 import std.range : enumerate, iota; 3955 3956 // supports mapping 3957 assert([3, 4, 5, 1, 2].enumerate.maxElement!"a.value" == tuple(2, 5)); 3958 assert([5, 2, 4].enumerate.maxElement!"a.value" == tuple(0, 5)); 3959 3960 // forward ranges 3961 assert(iota(1, 5).maxElement() == 4); 3962 assert(iota(2, 5).enumerate.maxElement!"a.value" == tuple(2, 4)); 3963 assert(iota(4, 14).enumerate.maxElement!"a.value" == tuple(9, 13)); 3964 3965 // should work with const 3966 const(int)[] immArr = [2, 3, 1]; 3967 assert(immArr.maxElement == 3); 3968 3969 // should work with immutable 3970 immutable(int)[] immArr2 = [2, 3, 1]; 3971 assert(immArr2.maxElement == 3); 3972 3973 // with strings 3974 assert(["a", "c", "b"].maxElement == "c"); 3975 3976 // with all dummy ranges 3977 import std.internal.test.dummyrange; 3978 foreach (DummyType; AllDummyRanges) 3979 { 3980 DummyType d; 3981 assert(d.maxElement == 10); 3982 assert(d.maxElement!(a => a) == 10); 3983 assert(d.maxElement!(a => -a) == 1); 3984 } 3985 3986 // with empty, but seeded ranges 3987 int[] arr; 3988 assert(arr.maxElement(42) == 42); 3989 assert(arr.maxElement!(a => a)(42) == 42); 3990 3991 } 3992 3993 @nogc @safe nothrow pure unittest 3994 { 3995 static immutable arr = [7, 3, 8, 2, 1, 4]; 3996 assert(arr.maxElement == 8); 3997 3998 static immutable arr2d = [[1, 3], [3, 9], [4, 2]]; 3999 assert(arr2d.maxElement!"a[1]" == arr2d[1]); 4000 } 4001 4002 // https://issues.dlang.org/show_bug.cgi?id=17982 4003 @safe unittest 4004 { 4005 class B 4006 { 4007 int val; 4008 this(int val){ this.val = val; } 4009 } 4010 4011 const(B) doStuff(const(B)[] v) 4012 { 4013 return v.maxElement!"a.val"; 4014 } 4015 assert(doStuff([new B(1), new B(0), new B(2)]).val == 2); 4016 4017 const(B)[] arr = [new B(0), new B(1)]; 4018 // can't compare directly - https://issues.dlang.org/show_bug.cgi?id=1824 4019 assert(arr.maxElement!"a.val".val == 1); 4020 } 4021 4022 // https://issues.dlang.org/show_bug.cgi?id=23993 4023 @safe unittest 4024 { 4025 import std.bigint : BigInt; 4026 4027 assert([BigInt(2), BigInt(3)].maxElement == BigInt(3)); 4028 } 4029 4030 // https://issues.dlang.org/show_bug.cgi?id=24596 4031 @safe unittest 4032 { 4033 static class A { 4034 int i; 4035 int getI() @safe => i; 4036 this(int i) @safe { this.i = i; } 4037 } 4038 auto arr = [new A(2), new A(3)]; 4039 4040 arr.maxElement!(a => a.getI); 4041 4042 assert(arr[0].getI == 2); 4043 } 4044 4045 // https://issues.dlang.org/show_bug.cgi?id=24827 4046 @safe unittest 4047 { 4048 static struct S 4049 { 4050 int i; 4051 bool destroyed; 4052 4053 this(int i) @safe 4054 { 4055 this.i = i; 4056 } 4057 4058 ~this() @safe 4059 { 4060 destroyed = true; 4061 } 4062 4063 bool opEquals()(auto ref S rhs) 4064 { 4065 return this.i == rhs.i; 4066 } 4067 4068 int opCmp()(auto ref S rhs) 4069 { 4070 if (this.i < rhs.i) 4071 return -1; 4072 4073 return this.i == rhs.i ? 0 : 1; 4074 } 4075 4076 @safe invariant 4077 { 4078 assert(!destroyed); 4079 } 4080 } 4081 4082 auto arr = [S(19), S(2), S(145), S(7)]; 4083 assert(maxElement(arr) == S(145)); 4084 } 4085 4086 /** Returns an array of the minimum and maximum element in `r`. 4087 * Performs `< 3n/2` comparisons, unlike the naive `< 2n`. 4088 * Params: 4089 * r = The range to traverse. 4090 */ 4091 // TODO alias map = a => a 4092 ElementType!Range[2] extrema(Range)(Range r) 4093 if (isInputRange!Range && !isInfinite!Range) 4094 in (!r.empty) 4095 { 4096 static if (isRandomAccessRange!Range && hasLength!Range) 4097 { 4098 if (r.length == 1) 4099 return [r[0], r[0]]; 4100 4101 typeof(return) result; 4102 size_t i; 4103 if (r.length & 1) // odd 4104 { 4105 result = [r[0], r[0]]; 4106 i = 1; 4107 } 4108 else 4109 { 4110 result = (r[0] < r[1]) ? [r[0], r[1]] : [r[1], r[0]]; 4111 i = 2; 4112 } 4113 // iterate pairs 4114 const imax = r.length; 4115 for (; i != imax; i += 2) 4116 { 4117 // save work 4118 if (r[i] < r[i+1]) 4119 { 4120 if (r[i] < result[0]) 4121 result[0] = r[i]; 4122 if (r[i+1] > result[1]) 4123 result[1] = r[i+1]; 4124 } 4125 else 4126 { 4127 if (r[i+1] < result[0]) 4128 result[0] = r[i+1]; 4129 if (r[i] > result[1]) 4130 result[1] = r[i]; 4131 } 4132 } 4133 return result; 4134 } 4135 else 4136 { 4137 auto first = r.front; 4138 r.popFront; 4139 if (r.empty) 4140 return [first, first]; 4141 4142 typeof(return) result = (first < r.front) ? [first, r.front] : [r.front, first]; 4143 // iterate pairs 4144 while (true) 4145 { 4146 r.popFront; 4147 if (r.empty) 4148 return result; 4149 first = r.front; 4150 r.popFront; 4151 if (r.empty) 4152 { 4153 if (first < result[0]) 4154 result[0] = first; 4155 else if (first > result[1]) 4156 result[1] = first; 4157 return result; 4158 } 4159 // save work 4160 if (first < r.front) 4161 { 4162 if (first < result[0]) 4163 result[0] = first; 4164 if (r.front > result[1]) 4165 result[1] = r.front; 4166 } 4167 else 4168 { 4169 if (r.front < result[0]) 4170 result[0] = r.front; 4171 if (first > result[1]) 4172 result[1] = first; 4173 } 4174 } 4175 } 4176 } 4177 4178 /// 4179 @safe unittest 4180 { 4181 assert(extrema([5,2,9,4,1]) == [1, 9]); 4182 } 4183 4184 @safe unittest 4185 { 4186 assert(extrema([8,3,7,4,9]) == [3, 9]); 4187 assert(extrema([1,5,3,2]) == [1, 5]); 4188 assert(extrema([2,3,3,2]) == [2, 3]); 4189 4190 import std.range; 4191 assert(iota(2, 5).extrema == [2, 4]); 4192 assert(iota(3, 7).retro.extrema == [3, 6]); 4193 4194 import std.internal.test.dummyrange; 4195 foreach (DummyType; AllDummyRanges) 4196 { 4197 DummyType d; 4198 assert(d.extrema == [1, 10]); 4199 } 4200 4201 version (StdRandomTests) 4202 foreach (i; 0 .. 1000) 4203 { 4204 import std.random; 4205 auto arr = generate!(() => uniform(0, 100)).takeExactly(uniform(1, 10)).array; 4206 auto result = arr.extrema; 4207 assert(result[0] == arr.minElement); 4208 assert(result[1] == arr.maxElement); 4209 } 4210 } 4211 4212 // minPos 4213 /** 4214 Computes a subrange of `range` starting at the first occurrence of `range`'s 4215 minimum (respectively maximum) and with the same ending as `range`, or the 4216 empty range if `range` itself is empty. 4217 4218 Formally, the minimum is a value `x` in `range` such that `pred(a, x)` is 4219 `false` for all values `a` in `range`. Conversely, the maximum is a value `x` in 4220 `range` such that `pred(x, a)` is `false` for all values `a` in `range` (note 4221 the swapped arguments to `pred`). 4222 4223 These functions may be used for computing arbitrary extrema by choosing `pred` 4224 appropriately. For corrrect functioning, `pred` must be a strict partial order, 4225 i.e. transitive (if `pred(a, b) && pred(b, c)` then `pred(a, c)`) and 4226 irreflexive (`pred(a, a)` is `false`). 4227 4228 Params: 4229 pred = The ordering predicate to use to determine the extremum (minimum or 4230 maximum) element. 4231 range = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search. 4232 4233 Returns: The position of the minimum (respectively maximum) element of forward 4234 range `range`, i.e. a subrange of `range` starting at the position of its 4235 smallest (respectively largest) element and with the same ending as `range`. 4236 4237 Limitations: If at least one of the arguments is NaN, the result is 4238 an unspecified value. See $(REF maxElement, std,algorithm,searching) 4239 for examples on how to cope with NaNs. 4240 4241 See_Also: 4242 $(REF max, std,algorithm,comparison), $(LREF minCount), $(LREF minIndex), $(LREF minElement) 4243 */ 4244 Range minPos(alias pred = "a < b", Range)(Range range) 4245 if (isForwardRange!Range && !isInfinite!Range && 4246 is(typeof(binaryFun!pred(range.front, range.front)))) 4247 { 4248 static if (hasSlicing!Range && isRandomAccessRange!Range && hasLength!Range) 4249 { 4250 // Prefer index-based access 4251 size_t pos = 0; 4252 foreach (i; 1 .. range.length) 4253 { 4254 if (binaryFun!pred(range[i], range[pos])) 4255 { 4256 pos = i; 4257 } 4258 } 4259 return range[pos .. range.length]; 4260 } 4261 else 4262 { 4263 auto result = range.save; 4264 if (range.empty) return result; 4265 for (range.popFront(); !range.empty; range.popFront()) 4266 { 4267 // Note: Unlike minCount, we do not care to find equivalence, so a 4268 // single pred call is enough. 4269 if (binaryFun!pred(range.front, result.front)) 4270 { 4271 // change the min 4272 result = range.save; 4273 } 4274 } 4275 return result; 4276 } 4277 } 4278 4279 /// Ditto 4280 Range maxPos(alias pred = "a < b", Range)(Range range) 4281 if (isForwardRange!Range && !isInfinite!Range && 4282 is(typeof(binaryFun!pred(range.front, range.front)))) 4283 { 4284 return range.minPos!((a, b) => binaryFun!pred(b, a)); 4285 } 4286 4287 /// 4288 @safe unittest 4289 { 4290 int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; 4291 // Minimum is 1 and first occurs in position 3 4292 assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]); 4293 // Maximum is 4 and first occurs in position 2 4294 assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]); 4295 } 4296 4297 @safe unittest 4298 { 4299 import std.algorithm.comparison : equal; 4300 import std.internal.test.dummyrange; 4301 4302 int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; 4303 //Test that an empty range works 4304 int[] b = a[$..$]; 4305 assert(equal(minPos(b), b)); 4306 4307 //test with reference range. 4308 assert( equal( minPos(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])), [0, 2, 0] ) ); 4309 } 4310 4311 @system unittest 4312 { 4313 //Rvalue range 4314 import std.algorithm.comparison : equal; 4315 import std.container : Array; 4316 4317 assert(Array!int(2, 3, 4, 1, 2, 4, 1, 1, 2) 4318 [] 4319 .minPos() 4320 .equal([ 1, 2, 4, 1, 1, 2 ])); 4321 } 4322 4323 @safe unittest 4324 { 4325 //BUG 9299 4326 immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; 4327 // Minimum is 1 and first occurs in position 3 4328 assert(minPos(a) == [ 1, 2, 4, 1, 1, 2 ]); 4329 // Maximum is 4 and first occurs in position 5 4330 assert(minPos!("a > b")(a) == [ 4, 1, 2, 4, 1, 1, 2 ]); 4331 4332 immutable(int[])[] b = [ [4], [2, 4], [4], [4] ]; 4333 assert(minPos!("a[0] < b[0]")(b) == [ [2, 4], [4], [4] ]); 4334 } 4335 4336 /** 4337 Computes the index of the first occurrence of `range`'s minimum element. 4338 4339 Params: 4340 pred = The ordering predicate to use to determine the minimum element. 4341 range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 4342 to search. 4343 4344 Complexity: $(BIGOH range.length) 4345 Exactly `range.length - 1` comparisons are needed. 4346 4347 Returns: 4348 The index of the first encounter of the minimum element in `range`. If the 4349 `range` is empty, -1 is returned. 4350 4351 Limitations: 4352 If at least one of the arguments is NaN, the result is 4353 an unspecified value. See $(REF maxElement, std,algorithm,searching) 4354 for examples on how to cope with NaNs. 4355 4356 See_Also: 4357 $(LREF maxIndex), $(REF min, std,algorithm,comparison), $(LREF minCount), $(LREF minElement), $(LREF minPos) 4358 */ 4359 ptrdiff_t minIndex(alias pred = "a < b", Range)(Range range) 4360 if (isInputRange!Range && !isInfinite!Range && 4361 is(typeof(binaryFun!pred(range.front, range.front)))) 4362 { 4363 if (range.empty) return -1; 4364 4365 ptrdiff_t minPos = 0; 4366 4367 static if (isRandomAccessRange!Range && hasLength!Range) 4368 { 4369 foreach (i; 1 .. range.length) 4370 { 4371 if (binaryFun!pred(range[i], range[minPos])) 4372 { 4373 minPos = i; 4374 } 4375 } 4376 } 4377 else 4378 { 4379 ptrdiff_t curPos = 0; 4380 Unqual!(typeof(range.front)) min = range.front; 4381 for (range.popFront(); !range.empty; range.popFront()) 4382 { 4383 ++curPos; 4384 if (binaryFun!pred(range.front, min)) 4385 { 4386 min = range.front; 4387 minPos = curPos; 4388 } 4389 } 4390 } 4391 return minPos; 4392 } 4393 4394 /// 4395 @safe pure nothrow unittest 4396 { 4397 int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2]; 4398 4399 // Minimum is 1 and first occurs in position 3 4400 assert(a.minIndex == 3); 4401 // Get maximum index with minIndex 4402 assert(a.minIndex!"a > b" == 2); 4403 4404 // Range is empty, so return value is -1 4405 int[] b; 4406 assert(b.minIndex == -1); 4407 4408 // Works with more custom types 4409 struct Dog { int age; } 4410 Dog[] dogs = [Dog(10), Dog(5), Dog(15)]; 4411 assert(dogs.minIndex!"a.age < b.age" == 1); 4412 } 4413 4414 @safe pure unittest 4415 { 4416 // should work with const 4417 const(int)[] immArr = [2, 1, 3]; 4418 assert(immArr.minIndex == 1); 4419 4420 // Works for const ranges too 4421 const int[] c = [2, 5, 4, 1, 2, 3]; 4422 assert(c.minIndex == 3); 4423 4424 // should work with immutable 4425 immutable(int)[] immArr2 = [2, 1, 3]; 4426 assert(immArr2.minIndex == 1); 4427 4428 // with strings 4429 assert(["b", "a", "c"].minIndex == 1); 4430 4431 // infinite range 4432 import std.range : cycle; 4433 static assert(!__traits(compiles, cycle([1]).minIndex)); 4434 4435 // with all dummy ranges 4436 import std.internal.test.dummyrange : AllDummyRanges; 4437 foreach (DummyType; AllDummyRanges) 4438 { 4439 static if (isForwardRange!DummyType && !isInfinite!DummyType) 4440 { 4441 DummyType d; 4442 d.arr = [5, 3, 7, 2, 1, 4]; 4443 assert(d.minIndex == 4); 4444 4445 d.arr = []; 4446 assert(d.minIndex == -1); 4447 } 4448 } 4449 } 4450 4451 @nogc @safe nothrow pure unittest 4452 { 4453 static immutable arr = [7, 3, 8, 2, 1, 4]; 4454 assert(arr.minIndex == 4); 4455 4456 static immutable arr2d = [[1, 3], [3, 9], [4, 2]]; 4457 assert(arr2d.minIndex!"a[1] < b[1]" == 2); 4458 } 4459 4460 @safe nothrow pure unittest 4461 { 4462 // InputRange test 4463 4464 static struct InRange 4465 { 4466 @property int front() 4467 { 4468 return arr[index]; 4469 } 4470 4471 bool empty() const 4472 { 4473 return arr.length == index; 4474 } 4475 4476 void popFront() 4477 { 4478 index++; 4479 } 4480 4481 int[] arr; 4482 size_t index = 0; 4483 } 4484 4485 static assert(isInputRange!InRange); 4486 4487 auto arr1 = InRange([5, 2, 3, 4, 5, 3, 6]); 4488 auto arr2 = InRange([7, 3, 8, 2, 1, 4]); 4489 4490 assert(arr1.minIndex == 1); 4491 assert(arr2.minIndex == 4); 4492 } 4493 4494 /** 4495 Computes the index of the first occurrence of `range`'s maximum element. 4496 4497 Complexity: $(BIGOH range) 4498 Exactly `range.length - 1` comparisons are needed. 4499 4500 Params: 4501 pred = The ordering predicate to use to determine the maximum element. 4502 range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to search. 4503 4504 Returns: 4505 The index of the first encounter of the maximum in `range`. If the 4506 `range` is empty, -1 is returned. 4507 4508 Limitations: 4509 If at least one of the arguments is NaN, the result is 4510 an unspecified value. See $(REF maxElement, std,algorithm,searching) 4511 for examples on how to cope with NaNs. 4512 4513 See_Also: 4514 $(LREF minIndex), $(REF max, std,algorithm,comparison), $(LREF maxCount), $(LREF maxElement), $(LREF maxPos) 4515 */ 4516 ptrdiff_t maxIndex(alias pred = "a < b", Range)(Range range) 4517 if (isInputRange!Range && !isInfinite!Range && 4518 is(typeof(binaryFun!pred(range.front, range.front)))) 4519 { 4520 return range.minIndex!((a, b) => binaryFun!pred(b, a)); 4521 } 4522 4523 /// 4524 @safe pure nothrow unittest 4525 { 4526 // Maximum is 4 and first occurs in position 2 4527 int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2]; 4528 assert(a.maxIndex == 2); 4529 4530 // Empty range 4531 int[] b; 4532 assert(b.maxIndex == -1); 4533 4534 // Works with more custom types 4535 struct Dog { int age; } 4536 Dog[] dogs = [Dog(10), Dog(15), Dog(5)]; 4537 assert(dogs.maxIndex!"a.age < b.age" == 1); 4538 } 4539 4540 @safe pure unittest 4541 { 4542 // should work with const 4543 const(int)[] immArr = [5, 1, 3]; 4544 assert(immArr.maxIndex == 0); 4545 4546 // Works for const ranges too 4547 const int[] c = [2, 5, 4, 1, 2, 3]; 4548 assert(c.maxIndex == 1); 4549 4550 4551 // should work with immutable 4552 immutable(int)[] immArr2 = [2, 1, 3]; 4553 assert(immArr2.maxIndex == 2); 4554 4555 // with strings 4556 assert(["b", "a", "c"].maxIndex == 2); 4557 4558 // infinite range 4559 import std.range : cycle; 4560 static assert(!__traits(compiles, cycle([1]).maxIndex)); 4561 4562 // with all dummy ranges 4563 import std.internal.test.dummyrange : AllDummyRanges; 4564 foreach (DummyType; AllDummyRanges) 4565 { 4566 static if (isForwardRange!DummyType && !isInfinite!DummyType) 4567 { 4568 DummyType d; 4569 4570 d.arr = [5, 3, 7, 2, 1, 4]; 4571 assert(d.maxIndex == 2); 4572 4573 d.arr = []; 4574 assert(d.maxIndex == -1); 4575 } 4576 } 4577 } 4578 4579 @nogc @safe nothrow pure unittest 4580 { 4581 static immutable arr = [7, 3, 8, 2, 1, 4]; 4582 assert(arr.maxIndex == 2); 4583 4584 static immutable arr2d = [[1, 3], [3, 9], [4, 2]]; 4585 assert(arr2d.maxIndex!"a[1] < b[1]" == 1); 4586 } 4587 4588 /** 4589 Skip over the initial portion of the first given range (`haystack`) that matches 4590 any of the additionally given ranges (`needles`) fully, or 4591 if no second range is given skip over the elements that fulfill pred. 4592 Do nothing if there is no match. 4593 4594 Params: 4595 pred = The predicate that determines whether elements from each respective 4596 range match. Defaults to equality `"a == b"`. 4597 */ 4598 template skipOver(alias pred = (a, b) => a == b) 4599 { 4600 enum bool isPredComparable(T) = ifTestable!(T, binaryFun!pred); 4601 4602 /** 4603 Params: 4604 haystack = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to 4605 move forward. 4606 needles = The $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) 4607 representing the prefix of `r1` to skip over. 4608 es = The element to match. 4609 4610 Returns: 4611 `true` if the prefix of `haystack` matches any range of `needles` fully 4612 or `pred` evaluates to true, and `haystack` has been advanced to the point past this segment; 4613 otherwise false, and `haystack` is left in its original position. 4614 4615 Note: 4616 By definition, empty ranges are matched fully and if `needles` contains an empty range, 4617 `skipOver` will return `true`. 4618 */ 4619 bool skipOver(Haystack, Needles...)(ref Haystack haystack, Needles needles) 4620 if (is(typeof(binaryFun!pred(haystack.front, needles[0].front))) && 4621 isForwardRange!Haystack && 4622 allSatisfy!(isInputRange, Needles) && 4623 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Needles))) == void)) 4624 { 4625 static if (__traits(isSame, pred, (a, b) => a == b) 4626 && is(typeof(haystack[0 .. $] == needles[0]) : bool) 4627 && is(typeof(haystack = haystack[0 .. $])) 4628 && hasLength!Haystack && allSatisfy!(hasLength, Needles)) 4629 { 4630 ptrdiff_t longestMatch = -1; 4631 static foreach (r2; needles) 4632 { 4633 if (r2.length <= haystack.length && longestMatch < ptrdiff_t(r2.length) 4634 && (haystack[0 .. r2.length] == r2 || r2.length == 0)) 4635 longestMatch = r2.length; 4636 } 4637 if (longestMatch >= 0) 4638 { 4639 if (longestMatch > 0) 4640 haystack = haystack[longestMatch .. $]; 4641 4642 return true; 4643 } 4644 return false; 4645 } 4646 else 4647 { 4648 import std.algorithm.comparison : min; 4649 auto r = haystack.save; 4650 4651 static if (hasLength!Haystack && allSatisfy!(hasLength, Needles)) 4652 { 4653 import std.algorithm.iteration : map; 4654 import std.algorithm.searching : minElement; 4655 import std.range : only; 4656 // Shortcut opportunity! 4657 if (needles.only.map!(a => a.length).minElement > haystack.length) 4658 return false; 4659 } 4660 4661 // compatibility: return true if any range was empty 4662 bool hasEmptyRanges; 4663 static foreach (i, r2; needles) 4664 { 4665 if (r2.empty) 4666 hasEmptyRanges = true; 4667 } 4668 4669 bool hasNeedleMatch; 4670 size_t inactiveNeedlesLen; 4671 bool[Needles.length] inactiveNeedles; 4672 for (; !r.empty; r.popFront) 4673 { 4674 static foreach (i, r2; needles) 4675 { 4676 if (!r2.empty && !inactiveNeedles[i]) 4677 { 4678 if (binaryFun!pred(r.front, r2.front)) 4679 { 4680 r2.popFront; 4681 if (r2.empty) 4682 { 4683 // we skipped over a new match 4684 hasNeedleMatch = true; 4685 inactiveNeedlesLen++; 4686 // skip over haystack 4687 haystack = r; 4688 } 4689 } 4690 else 4691 { 4692 inactiveNeedles[i] = true; 4693 inactiveNeedlesLen++; 4694 } 4695 } 4696 } 4697 4698 // are we done? 4699 if (inactiveNeedlesLen == needles.length) 4700 break; 4701 } 4702 4703 if (hasNeedleMatch) 4704 haystack.popFront; 4705 4706 return hasNeedleMatch || hasEmptyRanges; 4707 } 4708 } 4709 4710 /// Ditto 4711 bool skipOver(R)(ref R r1) 4712 if (isForwardRange!R && 4713 ifTestable!(typeof(r1.front), unaryFun!pred)) 4714 { 4715 if (r1.empty || !unaryFun!pred(r1.front)) 4716 return false; 4717 4718 do 4719 r1.popFront(); 4720 while (!r1.empty && unaryFun!pred(r1.front)); 4721 return true; 4722 } 4723 4724 /// Ditto 4725 bool skipOver(R, Es...)(ref R r, Es es) 4726 if (isInputRange!R && is(typeof(binaryFun!pred(r.front, es[0])))) 4727 { 4728 if (r.empty) 4729 return false; 4730 4731 static foreach (e; es) 4732 { 4733 if (binaryFun!pred(r.front, e)) 4734 { 4735 r.popFront(); 4736 return true; 4737 } 4738 } 4739 return false; 4740 } 4741 } 4742 4743 /// 4744 @safe unittest 4745 { 4746 import std.algorithm.comparison : equal; 4747 4748 auto s1 = "Hello world"; 4749 assert(!skipOver(s1, "Ha")); 4750 assert(s1 == "Hello world"); 4751 assert(skipOver(s1, "Hell") && s1 == "o world", s1); 4752 4753 string[] r1 = ["abc", "def", "hij"]; 4754 dstring[] r2 = ["abc"d]; 4755 assert(!skipOver!((a, b) => a.equal(b))(r1, ["def"d]), r1[0]); 4756 assert(r1 == ["abc", "def", "hij"]); 4757 assert(skipOver!((a, b) => a.equal(b))(r1, r2)); 4758 assert(r1 == ["def", "hij"]); 4759 } 4760 4761 /// 4762 @safe unittest 4763 { 4764 import std.ascii : isWhite; 4765 import std.range.primitives : empty; 4766 4767 auto s2 = "\t\tvalue"; 4768 auto s3 = ""; 4769 auto s4 = "\t\t\t"; 4770 assert(s2.skipOver!isWhite && s2 == "value"); 4771 assert(!s3.skipOver!isWhite); 4772 assert(s4.skipOver!isWhite && s3.empty); 4773 } 4774 4775 /// Variadic skipOver 4776 @safe unittest 4777 { 4778 auto s = "Hello world"; 4779 assert(!skipOver(s, "hello", "HellO")); 4780 assert(s == "Hello world"); 4781 4782 // the range is skipped over the longest matching needle is skipped 4783 assert(skipOver(s, "foo", "hell", "Hello ")); 4784 assert(s == "world"); 4785 } 4786 4787 /// 4788 @safe unittest 4789 { 4790 import std.algorithm.comparison : equal; 4791 4792 auto s1 = "Hello world"; 4793 assert(!skipOver(s1, 'a')); 4794 assert(s1 == "Hello world"); 4795 assert(skipOver(s1, 'H') && s1 == "ello world"); 4796 4797 string[] r = ["abc", "def", "hij"]; 4798 dstring e = "abc"d; 4799 assert(!skipOver!((a, b) => a.equal(b))(r, "def"d)); 4800 assert(r == ["abc", "def", "hij"]); 4801 assert(skipOver!((a, b) => a.equal(b))(r, e)); 4802 assert(r == ["def", "hij"]); 4803 4804 auto s2 = ""; 4805 assert(!s2.skipOver('a')); 4806 } 4807 4808 /// Partial instantiation 4809 @safe unittest 4810 { 4811 import std.ascii : isWhite; 4812 import std.range.primitives : empty; 4813 4814 alias whitespaceSkiper = skipOver!isWhite; 4815 4816 auto s2 = "\t\tvalue"; 4817 auto s3 = ""; 4818 auto s4 = "\t\t\t"; 4819 assert(whitespaceSkiper(s2) && s2 == "value"); 4820 assert(!whitespaceSkiper(s2)); 4821 assert(whitespaceSkiper(s4) && s3.empty); 4822 } 4823 4824 // variadic skipOver 4825 @safe unittest 4826 { 4827 auto s = "DLang.rocks"; 4828 assert(!s.skipOver("dlang", "DLF", "DLang ")); 4829 assert(s == "DLang.rocks"); 4830 4831 assert(s.skipOver("dlang", "DLANG", "DLF", "D", "DL", "DLanpp")); 4832 assert(s == "ang.rocks"); 4833 s = "DLang.rocks"; 4834 4835 assert(s.skipOver("DLang", "DLANG", "DLF", "D", "DL", "DLang ")); 4836 assert(s == ".rocks"); 4837 s = "DLang.rocks"; 4838 4839 assert(s.skipOver("dlang", "DLANG", "DLF", "D", "DL", "DLang.")); 4840 assert(s == "rocks"); 4841 } 4842 4843 // variadic with custom pred 4844 @safe unittest 4845 { 4846 import std.ascii : toLower; 4847 4848 auto s = "DLang.rocks"; 4849 assert(!s.skipOver("dlang", "DLF", "DLang ")); 4850 assert(s == "DLang.rocks"); 4851 4852 assert(s.skipOver!((a, b) => a.toLower == b.toLower)("dlang", "DLF", "DLang ")); 4853 assert(s == ".rocks"); 4854 } 4855 4856 // variadic skipOver with mixed needles 4857 @safe unittest 4858 { 4859 auto s = "DLang.rocks"; 4860 assert(!s.skipOver("dlang"d, "DLF", "DLang "w)); 4861 assert(s == "DLang.rocks"); 4862 4863 assert(s.skipOver("dlang", "DLANG"d, "DLF"w, "D"d, "DL", "DLanp")); 4864 assert(s == "ang.rocks"); 4865 s = "DLang.rocks"; 4866 4867 assert(s.skipOver("DLang", "DLANG"w, "DLF"d, "D"d, "DL", "DLang ")); 4868 assert(s == ".rocks"); 4869 s = "DLang.rocks"; 4870 4871 assert(s.skipOver("dlang", "DLANG"w, "DLF", "D"d, "DL"w, "DLang."d)); 4872 assert(s == "rocks"); 4873 4874 import std.algorithm.iteration : filter; 4875 s = "DLang.rocks"; 4876 assert(s.skipOver("dlang", "DLang".filter!(a => true))); 4877 assert(s == ".rocks"); 4878 } 4879 4880 // variadic skipOver with auto-decoding 4881 @safe unittest 4882 { 4883 auto s = "☢☣☠.☺"; 4884 assert(s.skipOver("a", "☢", "☢☣☠")); 4885 assert(s == ".☺"); 4886 } 4887 4888 // skipOver with @nogc 4889 @safe @nogc pure nothrow unittest 4890 { 4891 static immutable s = [0, 1, 2]; 4892 immutable(int)[] s2 = s[]; 4893 4894 static immutable skip1 = [0, 2]; 4895 static immutable skip2 = [0, 1]; 4896 assert(s2.skipOver(skip1, skip2)); 4897 assert(s2 == s[2 .. $]); 4898 } 4899 4900 // variadic skipOver with single elements 4901 @safe unittest 4902 { 4903 auto s = "DLang.rocks"; 4904 assert(!s.skipOver('a', 'd', 'e')); 4905 assert(s == "DLang.rocks"); 4906 4907 assert(s.skipOver('a', 'D', 'd', 'D')); 4908 assert(s == "Lang.rocks"); 4909 s = "DLang.rocks"; 4910 4911 assert(s.skipOver(wchar('a'), dchar('D'), 'd')); 4912 assert(s == "Lang.rocks"); 4913 4914 dstring dstr = "+Foo"; 4915 assert(!dstr.skipOver('.', '-')); 4916 assert(dstr == "+Foo"); 4917 4918 assert(dstr.skipOver('+', '-')); 4919 assert(dstr == "Foo"); 4920 } 4921 4922 // skipOver with empty ranges must return true (compatibility) 4923 @safe unittest 4924 { 4925 auto s = "DLang.rocks"; 4926 assert(s.skipOver("")); 4927 assert(s.skipOver("", "")); 4928 assert(s.skipOver("", "foo")); 4929 4930 auto s2 = "DLang.rocks"d; 4931 assert(s2.skipOver("")); 4932 assert(s2.skipOver("", "")); 4933 assert(s2.skipOver("", "foo")); 4934 } 4935 4936 // dxml regression 4937 @safe unittest 4938 { 4939 import std.utf : byCodeUnit; 4940 import std.algorithm.comparison : equal; 4941 4942 bool stripStartsWith(Text)(ref Text text, string needle) 4943 { 4944 return text.skipOver(needle.byCodeUnit()); 4945 } 4946 auto text = "<xml></xml>"d.byCodeUnit; 4947 assert(stripStartsWith(text, "<xml>")); 4948 assert(text.equal("</xml>")); 4949 } 4950 4951 /** 4952 Checks whether the given 4953 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one 4954 of) the given needle(s) or, if no needles are given, 4955 if its front element fulfils predicate `pred`. 4956 4957 For more information about `pred` see $(LREF find). 4958 4959 Params: 4960 4961 pred = Predicate to use in comparing the elements of the haystack and the 4962 needle(s). Mandatory if no needles are given. 4963 4964 doesThisStart = The input range to check. 4965 4966 withOneOfThese = The needles against which the range is to be checked, 4967 which may be individual elements or input ranges of elements. 4968 4969 withThis = The single needle to check, which may be either a single element 4970 or an input range of elements. 4971 4972 Returns: 4973 4974 0 if the needle(s) do not occur at the beginning of the given range; 4975 otherwise the position of the matching needle, that is, 1 if the range starts 4976 with `withOneOfThese[0]`, 2 if it starts with `withOneOfThese[1]`, and so 4977 on. 4978 4979 In the case where `doesThisStart` starts with multiple of the ranges or 4980 elements in `withOneOfThese`, then the shortest one matches (if there are 4981 two which match which are of the same length (e.g. `"a"` and `'a'`), then 4982 the left-most of them in the argument 4983 list matches). 4984 4985 In the case when no needle parameters are given, return `true` iff front of 4986 `doesThisStart` fulfils predicate `pred`. 4987 */ 4988 uint startsWith(alias pred = (a, b) => a == b, Range, Needles...)(Range doesThisStart, Needles withOneOfThese) 4989 if (isInputRange!Range && Needles.length > 1 && 4990 allSatisfy!(canTestStartsWith!(pred, Range), Needles)) 4991 { 4992 template checkType(T) 4993 { 4994 enum checkType = is(immutable ElementEncodingType!Range == immutable T); 4995 } 4996 4997 // auto-decoding special case 4998 static if (__traits(isSame, binaryFun!pred, (a, b) => a == b) && 4999 isNarrowString!Range && allSatisfy!(checkType, Needles)) 5000 { 5001 import std.utf : byCodeUnit; 5002 auto haystack = doesThisStart.byCodeUnit; 5003 } 5004 else 5005 { 5006 alias haystack = doesThisStart; 5007 } 5008 alias needles = withOneOfThese; 5009 5010 // Make one pass looking for empty ranges in needles 5011 foreach (i, Unused; Needles) 5012 { 5013 // Empty range matches everything 5014 static if (!is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool)) 5015 { 5016 if (needles[i].empty) return i + 1; 5017 } 5018 } 5019 5020 for (; !haystack.empty; haystack.popFront()) 5021 { 5022 foreach (i, Unused; Needles) 5023 { 5024 static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool)) 5025 { 5026 // Single-element 5027 if (binaryFun!pred(haystack.front, needles[i])) 5028 { 5029 // found, but instead of returning, we just stop searching. 5030 // This is to account for one-element 5031 // range matches (consider startsWith("ab", "a", 5032 // 'a') should return 1, not 2). 5033 break; 5034 } 5035 } 5036 else 5037 { 5038 if (binaryFun!pred(haystack.front, needles[i].front)) 5039 { 5040 continue; 5041 } 5042 } 5043 5044 // This code executed on failure to match 5045 // Out with this guy, check for the others 5046 uint result = startsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]); 5047 if (result > i) ++result; 5048 return result; 5049 } 5050 5051 // If execution reaches this point, then the front matches for all 5052 // needle ranges, or a needle element has been matched. 5053 // What we need to do now is iterate, lopping off the front of 5054 // the range and checking if the result is empty, or finding an 5055 // element needle and returning. 5056 // If neither happens, we drop to the end and loop. 5057 foreach (i, Unused; Needles) 5058 { 5059 static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool)) 5060 { 5061 // Test has passed in the previous loop 5062 return i + 1; 5063 } 5064 else 5065 { 5066 needles[i].popFront(); 5067 if (needles[i].empty) return i + 1; 5068 } 5069 } 5070 } 5071 return 0; 5072 } 5073 5074 /// Ditto 5075 bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis) 5076 if (isInputRange!R1 && 5077 isInputRange!R2 && 5078 is(typeof(binaryFun!pred(doesThisStart.front, withThis.front)) : bool)) 5079 { 5080 alias haystack = doesThisStart; 5081 alias needle = withThis; 5082 5083 static if (is(typeof(pred) : string)) 5084 enum isDefaultPred = pred == "a == b"; 5085 else 5086 enum isDefaultPred = false; 5087 5088 // Note: Although narrow strings don't have a "true" length, for a narrow string to start with another 5089 // narrow string, it must have *at least* as many code units. 5090 static if ((hasLength!R1 && hasLength!R2) || 5091 ((hasLength!R1 || isNarrowString!R1) && (hasLength!R2 || isNarrowString!R2) 5092 && (ElementEncodingType!R1.sizeof <= ElementEncodingType!R2.sizeof))) 5093 { 5094 if (haystack.length < needle.length) 5095 return false; 5096 } 5097 5098 static if (isDefaultPred && isArray!R1 && isArray!R2 && 5099 is(immutable ElementEncodingType!R1 == immutable ElementEncodingType!R2)) 5100 { 5101 //Array slice comparison mode 5102 return haystack[0 .. needle.length] == needle; 5103 } 5104 else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2) 5105 { 5106 //RA dual indexing mode 5107 foreach (j; 0 .. needle.length) 5108 { 5109 if (!binaryFun!pred(haystack[j], needle[j])) 5110 // not found 5111 return false; 5112 } 5113 // found! 5114 return true; 5115 } 5116 else 5117 { 5118 //Standard input range mode 5119 if (needle.empty) return true; 5120 static if (hasLength!R1 && hasLength!R2) 5121 { 5122 //We have previously checked that haystack.length > needle.length, 5123 //So no need to check haystack.empty during iteration 5124 for ( ; ; haystack.popFront() ) 5125 { 5126 if (!binaryFun!pred(haystack.front, needle.front)) break; 5127 needle.popFront(); 5128 if (needle.empty) return true; 5129 } 5130 } 5131 else 5132 { 5133 for ( ; !haystack.empty ; haystack.popFront() ) 5134 { 5135 if (!binaryFun!pred(haystack.front, needle.front)) break; 5136 needle.popFront(); 5137 if (needle.empty) return true; 5138 } 5139 } 5140 return false; 5141 } 5142 } 5143 5144 /// Ditto 5145 bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis) 5146 if (isInputRange!R && 5147 is(typeof(binaryFun!pred(doesThisStart.front, withThis)) : bool)) 5148 { 5149 if (doesThisStart.empty) 5150 return false; 5151 5152 static if (is(typeof(pred) : string)) 5153 enum isDefaultPred = pred == "a == b"; 5154 else 5155 enum isDefaultPred = false; 5156 5157 alias predFunc = binaryFun!pred; 5158 5159 // auto-decoding special case 5160 static if (isNarrowString!R) 5161 { 5162 // statically determine decoding is unnecessary to evaluate pred 5163 static if (isDefaultPred && isSomeChar!E && E.sizeof <= ElementEncodingType!R.sizeof) 5164 return doesThisStart[0] == withThis; 5165 // specialize for ASCII as to not change previous behavior 5166 else 5167 { 5168 if (withThis <= 0x7F) 5169 return predFunc(doesThisStart[0], withThis); 5170 else 5171 return predFunc(doesThisStart.front, withThis); 5172 } 5173 } 5174 else 5175 { 5176 return predFunc(doesThisStart.front, withThis); 5177 } 5178 } 5179 5180 /// Ditto 5181 bool startsWith(alias pred, R)(R doesThisStart) 5182 if (isInputRange!R && 5183 ifTestable!(typeof(doesThisStart.front), unaryFun!pred)) 5184 { 5185 return !doesThisStart.empty && unaryFun!pred(doesThisStart.front); 5186 } 5187 5188 /// 5189 @safe unittest 5190 { 5191 import std.ascii : isAlpha; 5192 5193 assert("abc".startsWith!(a => a.isAlpha)); 5194 assert("abc".startsWith!isAlpha); 5195 assert(!"1ab".startsWith!(a => a.isAlpha)); 5196 assert(!"".startsWith!(a => a.isAlpha)); 5197 5198 import std.algorithm.comparison : among; 5199 assert("abc".startsWith!(a => a.among('a', 'b') != 0)); 5200 assert(!"abc".startsWith!(a => a.among('b', 'c') != 0)); 5201 5202 assert(startsWith("abc", "")); 5203 assert(startsWith("abc", "a")); 5204 assert(!startsWith("abc", "b")); 5205 assert(startsWith("abc", 'a', "b") == 1); 5206 assert(startsWith("abc", "b", "a") == 2); 5207 assert(startsWith("abc", "a", "a") == 1); 5208 assert(startsWith("abc", "ab", "a") == 2); 5209 assert(startsWith("abc", "x", "a", "b") == 2); 5210 assert(startsWith("abc", "x", "aa", "ab") == 3); 5211 assert(startsWith("abc", "x", "aaa", "sab") == 0); 5212 assert(startsWith("abc", "x", "aaa", "a", "sab") == 3); 5213 5214 import std.typecons : Tuple; 5215 alias C = Tuple!(int, "x", int, "y"); 5216 assert(startsWith!"a.x == b"([ C(1,1), C(1,2), C(2,2) ], [1, 1])); 5217 assert(startsWith!"a.x == b"([ C(1,1), C(2,1), C(2,2) ], [1, 1], [1, 2], [1, 3]) == 2); 5218 } 5219 5220 @safe unittest 5221 { 5222 import std.algorithm.iteration : filter; 5223 import std.conv : to; 5224 import std.meta : AliasSeq; 5225 import std.range; 5226 5227 static foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) 5228 (){ // workaround slow optimizations for large functions 5229 // https://issues.dlang.org/show_bug.cgi?id=2396 5230 assert(!startsWith(to!S("abc"), 'c')); 5231 assert(startsWith(to!S("abc"), 'a', 'c') == 1); 5232 assert(!startsWith(to!S("abc"), 'x', 'n', 'b')); 5233 assert(startsWith(to!S("abc"), 'x', 'n', 'a') == 3); 5234 assert(startsWith(to!S("\uFF28abc"), 'a', '\uFF28', 'c') == 2); 5235 5236 static foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) 5237 { 5238 //Lots of strings 5239 assert(startsWith(to!S("abc"), to!T(""))); 5240 assert(startsWith(to!S("ab"), to!T("a"))); 5241 assert(startsWith(to!S("abc"), to!T("a"))); 5242 assert(!startsWith(to!S("abc"), to!T("b"))); 5243 assert(!startsWith(to!S("abc"), to!T("b"), "bc", "abcd", "xyz")); 5244 assert(startsWith(to!S("abc"), to!T("ab"), 'a') == 2); 5245 assert(startsWith(to!S("abc"), to!T("a"), "b") == 1); 5246 assert(startsWith(to!S("abc"), to!T("b"), "a") == 2); 5247 assert(startsWith(to!S("abc"), to!T("a"), 'a') == 1); 5248 assert(startsWith(to!S("abc"), 'a', to!T("a")) == 1); 5249 assert(startsWith(to!S("abc"), to!T("x"), "a", "b") == 2); 5250 assert(startsWith(to!S("abc"), to!T("x"), "aa", "ab") == 3); 5251 assert(startsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0); 5252 assert(startsWith(to!S("abc"), 'a')); 5253 assert(!startsWith(to!S("abc"), to!T("sab"))); 5254 assert(startsWith(to!S("abc"), 'x', to!T("aaa"), 'a', "sab") == 3); 5255 5256 //Unicode 5257 assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("\uFF28el"))); 5258 assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("Hel"), to!T("\uFF28el")) == 2); 5259 assert(startsWith(to!S("日本語"), to!T("日本"))); 5260 assert(startsWith(to!S("日本語"), to!T("日本語"))); 5261 assert(!startsWith(to!S("日本"), to!T("日本語"))); 5262 5263 //Empty 5264 assert(startsWith(to!S(""), T.init)); 5265 assert(!startsWith(to!S(""), 'a')); 5266 assert(startsWith(to!S("a"), T.init)); 5267 assert(startsWith(to!S("a"), T.init, "") == 1); 5268 assert(startsWith(to!S("a"), T.init, 'a') == 1); 5269 assert(startsWith(to!S("a"), 'a', T.init) == 2); 5270 } 5271 }(); 5272 5273 //Length but no RA 5274 assert(!startsWith("abc".takeExactly(3), "abcd".takeExactly(4))); 5275 assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(3))); 5276 assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(1))); 5277 5278 static foreach (T; AliasSeq!(int, short)) 5279 {{ 5280 immutable arr = cast(T[])[0, 1, 2, 3, 4, 5]; 5281 5282 //RA range 5283 assert(startsWith(arr, cast(int[]) null)); 5284 assert(!startsWith(arr, 5)); 5285 assert(!startsWith(arr, 1)); 5286 assert(startsWith(arr, 0)); 5287 assert(startsWith(arr, 5, 0, 1) == 2); 5288 assert(startsWith(arr, [0])); 5289 assert(startsWith(arr, [0, 1])); 5290 assert(startsWith(arr, [0, 1], 7) == 1); 5291 assert(!startsWith(arr, [0, 1, 7])); 5292 assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2); 5293 5294 //Normal input range 5295 assert(!startsWith(filter!"true"(arr), 1)); 5296 assert(startsWith(filter!"true"(arr), 0)); 5297 assert(startsWith(filter!"true"(arr), [0])); 5298 assert(startsWith(filter!"true"(arr), [0, 1])); 5299 assert(startsWith(filter!"true"(arr), [0, 1], 7) == 1); 5300 assert(!startsWith(filter!"true"(arr), [0, 1, 7])); 5301 assert(startsWith(filter!"true"(arr), [0, 1, 7], [0, 1, 2]) == 2); 5302 assert(startsWith(arr, filter!"true"([0, 1]))); 5303 assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1); 5304 assert(!startsWith(arr, filter!"true"([0, 1, 7]))); 5305 assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2); 5306 5307 //Non-default pred 5308 assert(startsWith!("a%10 == b%10")(arr, [10, 11])); 5309 assert(!startsWith!("a%10 == b%10")(arr, [10, 12])); 5310 }} 5311 } 5312 5313 private template canTestStartsWith(alias pred, Haystack) 5314 { 5315 enum bool canTestStartsWith(Needle) = is(typeof( 5316 (ref Haystack h, ref Needle n) => startsWith!pred(h, n))); 5317 } 5318 5319 /* (Not yet documented.) 5320 Consume all elements from `r` that are equal to one of the elements 5321 `es`. 5322 */ 5323 private void skipAll(alias pred = "a == b", R, Es...)(ref R r, Es es) 5324 //if (is(typeof(binaryFun!pred(r1.front, es[0])))) 5325 { 5326 loop: 5327 for (; !r.empty; r.popFront()) 5328 { 5329 foreach (i, E; Es) 5330 { 5331 if (binaryFun!pred(r.front, es[i])) 5332 { 5333 continue loop; 5334 } 5335 } 5336 break; 5337 } 5338 } 5339 5340 @safe unittest 5341 { 5342 auto s1 = "Hello world"; 5343 skipAll(s1, 'H', 'e'); 5344 assert(s1 == "llo world"); 5345 } 5346 5347 /** 5348 Interval option specifier for `until` (below) and others. 5349 5350 If set to `OpenRight.yes`, then the interval is open to the right 5351 (last element is not included). 5352 5353 Otherwise if set to `OpenRight.no`, then the interval is closed to the right 5354 including the entire sentinel. 5355 */ 5356 alias OpenRight = Flag!"openRight"; 5357 5358 /** 5359 Lazily iterates `range` _until the element `e` for which 5360 `pred(e, sentinel)` is true. 5361 5362 This is similar to `takeWhile` in other languages. 5363 5364 Params: 5365 pred = Predicate to determine when to stop. 5366 range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 5367 to iterate over. 5368 sentinel = The element to stop at. 5369 openRight = Determines whether the element for which the given predicate is 5370 true should be included in the resulting range (`No.openRight`), or 5371 not (`Yes.openRight`). 5372 5373 Returns: 5374 An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) that 5375 iterates over the original range's elements, but ends when the specified 5376 predicate becomes true. If the original range is a 5377 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) or 5378 higher, this range will be a forward range. 5379 */ 5380 Until!(pred, Range, Sentinel) 5381 until(alias pred = "a == b", Range, Sentinel) 5382 (Range range, Sentinel sentinel, OpenRight openRight = Yes.openRight) 5383 if (!is(Sentinel == OpenRight)) 5384 { 5385 return typeof(return)(range, sentinel, openRight); 5386 } 5387 5388 /// Ditto 5389 Until!(pred, Range, void) 5390 until(alias pred, Range) 5391 (Range range, OpenRight openRight = Yes.openRight) 5392 { 5393 return typeof(return)(range, openRight); 5394 } 5395 5396 /// ditto 5397 struct Until(alias pred, Range, Sentinel) 5398 if (isInputRange!Range) 5399 { 5400 private Range _input; 5401 static if (!is(Sentinel == void)) 5402 private Sentinel _sentinel; 5403 private OpenRight _openRight; 5404 private bool _matchStarted; 5405 private bool _done; 5406 5407 static if (!is(Sentinel == void)) 5408 { 5409 /// 5410 this(Range input, Sentinel sentinel, 5411 OpenRight openRight = Yes.openRight) 5412 { 5413 _input = input; 5414 _sentinel = sentinel; 5415 _openRight = openRight; 5416 static if (isInputRange!Sentinel 5417 && is(immutable ElementEncodingType!Sentinel == immutable ElementEncodingType!Range)) 5418 { 5419 _matchStarted = predSatisfied(); 5420 _done = _input.empty || _sentinel.empty || openRight && _matchStarted; 5421 if (_matchStarted && !_done && !openRight) 5422 { 5423 _sentinel.popFront; 5424 } 5425 } 5426 else 5427 { 5428 _done = _input.empty || openRight && predSatisfied(); 5429 } 5430 } 5431 private this(Range input, Sentinel sentinel, OpenRight openRight, 5432 bool done) 5433 { 5434 _input = input; 5435 _sentinel = sentinel; 5436 _openRight = openRight; 5437 _done = done; 5438 } 5439 } 5440 else 5441 { 5442 /// 5443 this(Range input, OpenRight openRight = Yes.openRight) 5444 { 5445 _input = input; 5446 _openRight = openRight; 5447 _done = _input.empty || openRight && predSatisfied(); 5448 } 5449 private this(Range input, OpenRight openRight, bool done) 5450 { 5451 _input = input; 5452 _openRight = openRight; 5453 _done = done; 5454 } 5455 } 5456 5457 /// 5458 @property bool empty() 5459 { 5460 return _done; 5461 } 5462 5463 /// 5464 @property auto ref front() 5465 { 5466 assert(!empty, "Can not get the front of an empty Until"); 5467 return _input.front; 5468 } 5469 5470 private bool predSatisfied() 5471 { 5472 static if (is(Sentinel == void)) 5473 return cast(bool) unaryFun!pred(_input.front); 5474 else 5475 return cast(bool) startsWith!pred(_input, _sentinel); 5476 } 5477 5478 /// 5479 void popFront() 5480 { 5481 assert(!empty, "Can not popFront of an empty Until"); 5482 if (!_openRight) 5483 { 5484 static if (isInputRange!Sentinel 5485 && is(immutable ElementEncodingType!Sentinel == immutable ElementEncodingType!Range)) 5486 { 5487 _input.popFront(); 5488 _done = _input.empty || _sentinel.empty; 5489 if (!_done) 5490 { 5491 if (_matchStarted) 5492 { 5493 _sentinel.popFront; 5494 } 5495 else 5496 { 5497 _matchStarted = predSatisfied(); 5498 if (_matchStarted) 5499 { 5500 _sentinel.popFront; 5501 } 5502 } 5503 } 5504 } 5505 else 5506 { 5507 _done = predSatisfied(); 5508 _input.popFront(); 5509 _done = _done || _input.empty; 5510 } 5511 } 5512 else 5513 { 5514 _input.popFront(); 5515 _done = _input.empty || predSatisfied(); 5516 } 5517 } 5518 5519 static if (isForwardRange!Range) 5520 { 5521 /// 5522 @property Until save() 5523 { 5524 static if (is(Sentinel == void)) 5525 return Until(_input.save, _openRight, _done); 5526 else 5527 return Until(_input.save, _sentinel, _openRight, _done); 5528 } 5529 } 5530 } 5531 5532 /// 5533 @safe unittest 5534 { 5535 import std.algorithm.comparison : equal; 5536 import std.typecons : No; 5537 int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5]; 5538 assert(equal(a.until(7), [1, 2, 4])); 5539 assert(equal(a.until(7, No.openRight), [1, 2, 4, 7])); 5540 } 5541 5542 @safe unittest 5543 { 5544 import std.algorithm.comparison : equal; 5545 int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5]; 5546 5547 static assert(isForwardRange!(typeof(a.until(7)))); 5548 static assert(isForwardRange!(typeof(until!"a == 2"(a, No.openRight)))); 5549 5550 assert(equal(a.until(7), [1, 2, 4])); 5551 assert(equal(a.until([7, 2]), [1, 2, 4, 7])); 5552 assert(equal(a.until(7, No.openRight), [1, 2, 4, 7])); 5553 assert(equal(until!"a == 2"(a, No.openRight), [1, 2])); 5554 } 5555 5556 // https://issues.dlang.org/show_bug.cgi?id=13171 5557 @system unittest 5558 { 5559 import std.algorithm.comparison : equal; 5560 import std.range; 5561 auto a = [1, 2, 3, 4]; 5562 assert(equal(refRange(&a).until(3, No.openRight), [1, 2, 3])); 5563 assert(a == [4]); 5564 } 5565 5566 // https://issues.dlang.org/show_bug.cgi?id=10460 5567 @safe unittest 5568 { 5569 import std.algorithm.comparison : equal; 5570 auto a = [1, 2, 3, 4]; 5571 foreach (ref e; a.until(3)) 5572 e = 0; 5573 assert(equal(a, [0, 0, 3, 4])); 5574 } 5575 5576 // https://issues.dlang.org/show_bug.cgi?id=13124 5577 @safe unittest 5578 { 5579 import std.algorithm.comparison : among, equal; 5580 auto s = "hello how\nare you"; 5581 assert(equal(s.until!(c => c.among!('\n', '\r')), "hello how")); 5582 } 5583 5584 // https://issues.dlang.org/show_bug.cgi?id=18657 5585 pure @safe unittest 5586 { 5587 import std.algorithm.comparison : equal; 5588 import std.range : refRange; 5589 { 5590 string s = "foobar"; 5591 auto r = refRange(&s).until("bar"); 5592 assert(equal(r.save, "foo")); 5593 assert(equal(r.save, "foo")); 5594 } 5595 { 5596 string s = "foobar"; 5597 auto r = refRange(&s).until!(e => e == 'b'); 5598 assert(equal(r.save, "foo")); 5599 assert(equal(r.save, "foo")); 5600 } 5601 } 5602 5603 // https://issues.dlang.org/show_bug.cgi?id=14543 5604 pure @safe unittest 5605 { 5606 import std.algorithm.comparison : equal; 5607 import std.uni : toUpper; 5608 assert("one two three".until("two").equal("one ")); 5609 assert("one two three".until("two", OpenRight.no).equal("one two")); 5610 5611 assert("one two three".until("two", No.openRight).equal("one two")); 5612 assert("one two three".until("two", Yes.openRight).equal("one ")); 5613 5614 assert("one two three".until('t', Yes.openRight).equal("one ")); 5615 assert("one two three".until("", Yes.openRight).equal("")); 5616 assert("one two three".until("", No.openRight).equal("")); 5617 5618 assert("one two three".until("three", No.openRight).equal("one two three")); 5619 assert("one two three".until("three", Yes.openRight).equal("one two ")); 5620 5621 assert("one two three".until("one", No.openRight).equal("one")); 5622 assert("one two three".until("one", Yes.openRight).equal("")); 5623 5624 assert("one two three".until("o", No.openRight).equal("o")); 5625 assert("one two three".until("o", Yes.openRight).equal("")); 5626 5627 assert("one two three".until("", No.openRight).equal("")); 5628 assert("one two three".until("", Yes.openRight).equal("")); 5629 5630 assert("one two three".until!((a,b)=>a.toUpper == b)("TWO", No.openRight).equal("one two")); 5631 } 5632 5633 // https://issues.dlang.org/show_bug.cgi?id=24342 5634 pure @safe unittest 5635 { 5636 import std.algorithm.comparison : equal; 5637 assert(["A", "BC", "D"].until("BC", No.openRight).equal(["A", "BC"])); 5638 assert([[1], [2, 3], [4]].until([2, 3], No.openRight).equal([[1], [2, 3]])); 5639 }