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