Struct returned findSplits with bool conversion

This commit is contained in:
Per Nordlöw 2015-08-03 13:32:35 +02:00
parent 75fa251700
commit 100e7a485b
2 changed files with 117 additions and 37 deletions

View file

@ -2404,20 +2404,49 @@ Params:
needle = What to look for. needle = What to look for.
Returns: 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) auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2) 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 static if (isSomeString!R1 && isSomeString!R2
|| isRandomAccessRange!R1 && hasLength!R2) || isRandomAccessRange!R1 && hasLength!R2)
{ {
auto balance = find!pred(haystack, needle); auto balance = find!pred(haystack, needle);
immutable pos1 = haystack.length - balance.length; immutable pos1 = haystack.length - balance.length;
immutable pos2 = balance.empty ? pos1 : pos1 + needle.length; immutable pos2 = balance.empty ? pos1 : pos1 + needle.length;
return tuple(haystack[0 .. pos1], return Result!(typeof(haystack[0 .. pos1]),
haystack[pos1 .. pos2], typeof(haystack[pos2 .. haystack.length]))(haystack[0 .. pos1],
haystack[pos2 .. haystack.length]); haystack[pos1 .. pos2],
haystack[pos2 .. haystack.length]);
} }
else else
{ {
@ -2442,9 +2471,10 @@ if (isForwardRange!R1 && isForwardRange!R2)
pos2 = ++pos1; pos2 = ++pos1;
} }
} }
return tuple(takeExactly(original, pos1), return Result!(typeof(takeExactly(original, pos1)),
takeExactly(haystack, pos2 - pos1), typeof(h))(takeExactly(original, pos1),
h); 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) auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2) 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 static if (isSomeString!R1 && isSomeString!R2
|| isRandomAccessRange!R1 && hasLength!R2) || isRandomAccessRange!R1 && hasLength!R2)
{ {
auto balance = find!pred(haystack, needle); auto balance = find!pred(haystack, needle);
immutable pos = haystack.length - balance.length; 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 else
{ {
@ -2481,7 +2528,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
++pos; ++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) auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2) 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 static if (isSomeString!R1 && isSomeString!R2
|| isRandomAccessRange!R1 && hasLength!R2) || isRandomAccessRange!R1 && hasLength!R2)
{ {
auto balance = find!pred(haystack, needle); auto balance = find!pred(haystack, needle);
immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length; 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 else
{ {
@ -2508,7 +2574,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
if (h.empty) if (h.empty)
{ {
// Failed search // 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)) if (binaryFun!pred(h.front, n.front))
{ {
@ -2524,7 +2592,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
pos2 = ++pos1; 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 a = "Carl Sagan Memorial Station";
auto r = findSplit(a, "Velikovsky"); 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[0] == a);
assert(r[1].empty); assert(r[1].empty);
assert(r[2].empty); assert(r[2].empty);
@ -2541,9 +2615,11 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(r[1] == " "); assert(r[1] == " ");
assert(r[2] == "Sagan Memorial Station"); assert(r[2] == "Sagan Memorial Station");
auto r1 = findSplitBefore(a, "Sagan"); auto r1 = findSplitBefore(a, "Sagan");
assert(r1);
assert(r1[0] == "Carl ", r1[0]); assert(r1[0] == "Carl ", r1[0]);
assert(r1[1] == "Sagan Memorial Station"); assert(r1[1] == "Sagan Memorial Station");
auto r2 = findSplitAfter(a, "Sagan"); auto r2 = findSplitAfter(a, "Sagan");
assert(r2);
assert(r2[0] == "Carl Sagan"); assert(r2[0] == "Carl Sagan");
assert(r2[1] == " Memorial Station"); 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 a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
auto r = findSplit(a, [9, 1]); auto r = findSplit(a, [9, 1]);
assert(!r);
assert(r[0] == a); assert(r[0] == a);
assert(r[1].empty); assert(r[1].empty);
assert(r[2].empty); assert(r[2].empty);
r = findSplit(a, [3]); r = findSplit(a, [3]);
assert(r);
assert(r[0] == a[0 .. 2]); assert(r[0] == a[0 .. 2]);
assert(r[1] == a[2 .. 3]); assert(r[1] == a[2 .. 3]);
assert(r[2] == a[3 .. $]); assert(r[2] == a[3 .. $]);
auto r1 = findSplitBefore(a, [9, 1]); auto r1 = findSplitBefore(a, [9, 1]);
assert(r1);
assert(r1[0] == a); assert(r1[0] == a);
assert(r1[1].empty); assert(r1[1].empty);
r1 = findSplitBefore(a, [3, 4]); r1 = findSplitBefore(a, [3, 4]);
assert(r1);
assert(r1[0] == a[0 .. 2]); assert(r1[0] == a[0 .. 2]);
assert(r1[1] == a[2 .. $]); assert(r1[1] == a[2 .. $]);
r1 = findSplitAfter(a, [9, 1]); auto r2 = findSplitAfter(a, [9, 1]);
assert(r1[0].empty); assert(r2);
assert(r1[1] == a); assert(r2[0].empty);
r1 = findSplitAfter(a, [3, 4]); assert(r2[1] == a);
assert(r1[0] == a[0 .. 4]); r2 = findSplitAfter(a, [3, 4]);
assert(r1[1] == a[4 .. $]); assert(r2);
assert(r2[0] == a[0 .. 4]);
assert(r2[1] == a[4 .. $]);
} }
@safe unittest @safe unittest
@ -2583,27 +2665,33 @@ if (isForwardRange!R1 && isForwardRange!R2)
auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
auto fwd = filter!"a > 0"(a); auto fwd = filter!"a > 0"(a);
auto r = findSplit(fwd, [9, 1]); auto r = findSplit(fwd, [9, 1]);
assert(!r);
assert(equal(r[0], a)); assert(equal(r[0], a));
assert(r[1].empty); assert(r[1].empty);
assert(r[2].empty); assert(r[2].empty);
r = findSplit(fwd, [3]); r = findSplit(fwd, [3]);
assert(r);
assert(equal(r[0], a[0 .. 2])); assert(equal(r[0], a[0 .. 2]));
assert(equal(r[1], a[2 .. 3])); assert(equal(r[1], a[2 .. 3]));
assert(equal(r[2], a[3 .. $])); assert(equal(r[2], a[3 .. $]));
auto r1 = findSplitBefore(fwd, [9, 1]); auto r1 = findSplitBefore(fwd, [9, 1]);
assert(r1);
assert(equal(r1[0], a)); assert(equal(r1[0], a));
assert(r1[1].empty); assert(r1[1].empty);
r1 = findSplitBefore(fwd, [3, 4]); r1 = findSplitBefore(fwd, [3, 4]);
assert(r1);
assert(equal(r1[0], a[0 .. 2])); assert(equal(r1[0], a[0 .. 2]));
assert(equal(r1[1], a[2 .. $])); assert(equal(r1[1], a[2 .. $]));
r1 = findSplitAfter(fwd, [9, 1]); auto r2 = findSplitAfter(fwd, [9, 1]);
assert(r1[0].empty); assert(r2);
assert(equal(r1[1], a)); assert(r2[0].empty);
r1 = findSplitAfter(fwd, [3, 4]); assert(equal(r2[1], a));
assert(equal(r1[0], a[0 .. 4])); r2 = findSplitAfter(fwd, [3, 4]);
assert(equal(r1[1], a[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"; auto s = "hello how\nare you";
s.until!(c => c.among!('\n', '\r')); s.until!(c => c.among!('\n', '\r'));
} }

View file

@ -1376,17 +1376,11 @@ unittest
Returns: Returns:
true if `T` is a `Tuple` type, false otherwise. true if `T` is a `Tuple` type, false otherwise.
*/ */
template isTuple(T) enum isTuple(T) = __traits(compiles,
{ {
static if (is(Unqual!T Unused : Tuple!Specs, Specs...)) void f(Specs...)(Tuple!Specs tup) {}
{ f(T.init);
enum isTuple = true; } );
}
else
{
enum isTuple = false;
}
}
/// ///
unittest unittest
@ -6843,4 +6837,3 @@ unittest
int, float, RefFun1, RefFun2, int, float, RefFun1, RefFun2,
); );
} }