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