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