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