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