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