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