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