Merge pull request #3288 from nordlow/struct-returned-findSplit

Struct Returned findSplit*() with implicit bool conversion
This commit is contained in:
Andrei Alexandrescu 2015-10-29 14:37:39 -04:00
commit b6a61d9e71
2 changed files with 117 additions and 37 deletions

View file

@ -2404,20 +2404,49 @@ Params:
needle = What to look for.
Returns:
A tuple of the split portions of `haystack` (see above for details).
A sub-type of Tuple!() of the split portions of `haystack` (see above for
details). This sub-type of Tuple!() has opCast defined for bool. This opCast
returns $(D true) when the separating $(D needle) was found (!result[1].empty)
and $(D false) otherwise. This enables the convenient idiom shown in the
following example.
Example:
---
if (const split = haystack.findSplit(needle))
{
doSomethingWithSplit(split);
}
---
*/
auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2)
{
static struct Result(S1, S2) if (isForwardRange!S1 &&
isForwardRange!S2)
{
this(S1 pre, S1 separator, S2 post)
{
asTuple = typeof(asTuple)(pre, separator, post);
}
Tuple!(S1, S1, S2) asTuple;
bool opCast(T : bool)()
{
return !asTuple[1].empty;
}
alias asTuple this;
}
static if (isSomeString!R1 && isSomeString!R2
|| isRandomAccessRange!R1 && hasLength!R2)
{
auto balance = find!pred(haystack, needle);
immutable pos1 = haystack.length - balance.length;
immutable pos2 = balance.empty ? pos1 : pos1 + needle.length;
return tuple(haystack[0 .. pos1],
haystack[pos1 .. pos2],
haystack[pos2 .. haystack.length]);
return Result!(typeof(haystack[0 .. pos1]),
typeof(haystack[pos2 .. haystack.length]))(haystack[0 .. pos1],
haystack[pos1 .. pos2],
haystack[pos2 .. haystack.length]);
}
else
{
@ -2442,9 +2471,10 @@ if (isForwardRange!R1 && isForwardRange!R2)
pos2 = ++pos1;
}
}
return tuple(takeExactly(original, pos1),
takeExactly(haystack, pos2 - pos1),
h);
return Result!(typeof(takeExactly(original, pos1)),
typeof(h))(takeExactly(original, pos1),
takeExactly(haystack, pos2 - pos1),
h);
}
}
@ -2452,12 +2482,29 @@ if (isForwardRange!R1 && isForwardRange!R2)
auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2)
{
static struct Result(S1, S2) if (isForwardRange!S1 &&
isForwardRange!S2)
{
this(S1 pre, S2 post)
{
asTuple = typeof(asTuple)(pre, post);
}
Tuple!(S1, S2) asTuple;
bool opCast(T : bool)()
{
return !asTuple[0].empty;
}
alias asTuple this;
}
static if (isSomeString!R1 && isSomeString!R2
|| isRandomAccessRange!R1 && hasLength!R2)
{
auto balance = find!pred(haystack, needle);
immutable pos = haystack.length - balance.length;
return tuple(haystack[0 .. pos], haystack[pos .. haystack.length]);
return Result!(typeof(haystack[0 .. pos]),
typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos],
haystack[pos .. haystack.length]);
}
else
{
@ -2481,7 +2528,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
++pos;
}
}
return tuple(takeExactly(original, pos), haystack);
return Result!(typeof(takeExactly(original, pos)),
typeof(haystack))(takeExactly(original, pos),
haystack);
}
}
@ -2489,12 +2538,29 @@ if (isForwardRange!R1 && isForwardRange!R2)
auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2)
{
static struct Result(S1, S2) if (isForwardRange!S1 &&
isForwardRange!S2)
{
this(S1 pre, S2 post)
{
asTuple = typeof(asTuple)(pre, post);
}
Tuple!(S1, S2) asTuple;
bool opCast(T : bool)()
{
return !asTuple[1].empty;
}
alias asTuple this;
}
static if (isSomeString!R1 && isSomeString!R2
|| isRandomAccessRange!R1 && hasLength!R2)
{
auto balance = find!pred(haystack, needle);
immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length;
return tuple(haystack[0 .. pos], haystack[pos .. haystack.length]);
return Result!(typeof(haystack[0 .. pos]),
typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos],
haystack[pos .. haystack.length]);
}
else
{
@ -2508,7 +2574,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
if (h.empty)
{
// Failed search
return tuple(takeExactly(original, 0), original);
return Result!(typeof(takeExactly(original, 0)),
typeof(original))(takeExactly(original, 0),
original);
}
if (binaryFun!pred(h.front, n.front))
{
@ -2524,7 +2592,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
pos2 = ++pos1;
}
}
return tuple(takeExactly(original, pos2), h);
return Result!(typeof(takeExactly(original, pos2)),
typeof(h))(takeExactly(original, pos2),
h);
}
}
@ -2533,6 +2603,10 @@ if (isForwardRange!R1 && isForwardRange!R2)
{
auto a = "Carl Sagan Memorial Station";
auto r = findSplit(a, "Velikovsky");
import std.typecons : isTuple;
static assert(isTuple!(typeof(r.asTuple)));
static assert(isTuple!(typeof(r)));
assert(!r);
assert(r[0] == a);
assert(r[1].empty);
assert(r[2].empty);
@ -2541,9 +2615,11 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(r[1] == " ");
assert(r[2] == "Sagan Memorial Station");
auto r1 = findSplitBefore(a, "Sagan");
assert(r1);
assert(r1[0] == "Carl ", r1[0]);
assert(r1[1] == "Sagan Memorial Station");
auto r2 = findSplitAfter(a, "Sagan");
assert(r2);
assert(r2[0] == "Carl Sagan");
assert(r2[1] == " Memorial Station");
}
@ -2552,27 +2628,33 @@ if (isForwardRange!R1 && isForwardRange!R2)
{
auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
auto r = findSplit(a, [9, 1]);
assert(!r);
assert(r[0] == a);
assert(r[1].empty);
assert(r[2].empty);
r = findSplit(a, [3]);
assert(r);
assert(r[0] == a[0 .. 2]);
assert(r[1] == a[2 .. 3]);
assert(r[2] == a[3 .. $]);
auto r1 = findSplitBefore(a, [9, 1]);
assert(r1);
assert(r1[0] == a);
assert(r1[1].empty);
r1 = findSplitBefore(a, [3, 4]);
assert(r1);
assert(r1[0] == a[0 .. 2]);
assert(r1[1] == a[2 .. $]);
r1 = findSplitAfter(a, [9, 1]);
assert(r1[0].empty);
assert(r1[1] == a);
r1 = findSplitAfter(a, [3, 4]);
assert(r1[0] == a[0 .. 4]);
assert(r1[1] == a[4 .. $]);
auto r2 = findSplitAfter(a, [9, 1]);
assert(r2);
assert(r2[0].empty);
assert(r2[1] == a);
r2 = findSplitAfter(a, [3, 4]);
assert(r2);
assert(r2[0] == a[0 .. 4]);
assert(r2[1] == a[4 .. $]);
}
@safe unittest
@ -2583,27 +2665,33 @@ if (isForwardRange!R1 && isForwardRange!R2)
auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
auto fwd = filter!"a > 0"(a);
auto r = findSplit(fwd, [9, 1]);
assert(!r);
assert(equal(r[0], a));
assert(r[1].empty);
assert(r[2].empty);
r = findSplit(fwd, [3]);
assert(r);
assert(equal(r[0], a[0 .. 2]));
assert(equal(r[1], a[2 .. 3]));
assert(equal(r[2], a[3 .. $]));
auto r1 = findSplitBefore(fwd, [9, 1]);
assert(r1);
assert(equal(r1[0], a));
assert(r1[1].empty);
r1 = findSplitBefore(fwd, [3, 4]);
assert(r1);
assert(equal(r1[0], a[0 .. 2]));
assert(equal(r1[1], a[2 .. $]));
r1 = findSplitAfter(fwd, [9, 1]);
assert(r1[0].empty);
assert(equal(r1[1], a));
r1 = findSplitAfter(fwd, [3, 4]);
assert(equal(r1[0], a[0 .. 4]));
assert(equal(r1[1], a[4 .. $]));
auto r2 = findSplitAfter(fwd, [9, 1]);
assert(r2);
assert(r2[0].empty);
assert(equal(r2[1], a));
r2 = findSplitAfter(fwd, [3, 4]);
assert(r2);
assert(equal(r2[0], a[0 .. 4]));
assert(equal(r2[1], a[4 .. $]));
}
/**
@ -3528,4 +3616,3 @@ unittest // Issue 13124
auto s = "hello how\nare you";
s.until!(c => c.among!('\n', '\r'));
}