The OpenD Programming Language

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