Merge pull request #1166 from andralex/5507

Fix Issue 5507 - countUntil should take Ranges... instead of R2
This commit is contained in:
Alex Rønne Petersen 2013-02-24 16:50:06 -08:00
commit 54ddafa1a8

View file

@ -4399,11 +4399,11 @@ unittest
/++ /++
Returns the number of elements which must be popped from the front of Returns the number of elements which must be popped from the front of
$(D haystack) before reaching an element for which $(D haystack) before reaching an element for which
$(D startsWith!pred(haystack, needle)) is $(D true). If $(D startsWith!pred(haystack, needles)) is $(D true). If
$(D startsWith!pred(haystack, needle)) is not $(D true) for any element in $(D startsWith!pred(haystack, needles)) is not $(D true) for any element in
$(D haystack), then -1 is returned. $(D haystack), then $(D -1) is returned.
$(D needle) may be either an element or a range. $(D needles) may be either an element or a range.
Examples: Examples:
-------------------- --------------------
@ -4419,23 +4419,30 @@ assert(countUntil([0, 7, 12, 22, 9], 9) == 4);
assert(countUntil!"a > b"([0, 7, 12, 22, 9], 20) == 3); assert(countUntil!"a > b"([0, 7, 12, 22, 9], 20) == 3);
-------------------- --------------------
+/ +/
ptrdiff_t countUntil(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) ptrdiff_t countUntil(alias pred = "a == b", R, Rs...)(R haystack, Rs needles)
if (isForwardRange!R1 && isForwardRange!R2 && if (isForwardRange!R
is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) && Rs.length > 0
&& isForwardRange!(Rs[0]) == isInputRange!(Rs[0])
&& is(typeof(startsWith!pred(haystack, needles[0])))
&& (Rs.length == 1
|| is(typeof(countUntil!pred(haystack, needles[1 .. $])))))
{ {
typeof(return) result; typeof(return) result;
static if (hasLength!R1) //Note: Narrow strings don't have length.
static if (needles.length == 1)
{
static if (hasLength!R) //Note: Narrow strings don't have length.
{ {
//We delegate to find because find is very efficient. //We delegate to find because find is very efficient.
//We store the length of the haystack so we don't have to save it. //We store the length of the haystack so we don't have to save it.
auto len = haystack.length; auto len = haystack.length;
auto r2 = find!pred(haystack, needle); auto r2 = find!pred(haystack, needles[0]);
if (!r2.empty) if (!r2.empty)
return cast(typeof(return)) (len - r2.length); return cast(typeof(return)) (len - r2.length);
} }
else else
{ {
if (needle.empty) if (needles[0].empty)
return 0; return 0;
//Default case, slower route doing startsWith iteration //Default case, slower route doing startsWith iteration
@ -4445,21 +4452,55 @@ ptrdiff_t countUntil(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
//forwarding to startsWith. This avoids making useless saves to //forwarding to startsWith. This avoids making useless saves to
//haystack/needle if they aren't even going to be mutated anyways. //haystack/needle if they aren't even going to be mutated anyways.
//It also cuts down on the amount of pops on haystack. //It also cuts down on the amount of pops on haystack.
if (binaryFun!pred(haystack.front, needle.front)) if (binaryFun!pred(haystack.front, needles[0].front))
{ {
//Here, we need to save the needle before popping it. //Here, we need to save the needle before popping it.
//haystack we pop in all paths, so we do that, and then save. //haystack we pop in all paths, so we do that, and then save.
haystack.popFront(); haystack.popFront();
if (startsWith!pred(haystack.save, needle.save.dropOne())) if (startsWith!pred(haystack.save, needles[0].save.dropOne()))
return result; return result;
} }
else else
haystack.popFront(); haystack.popFront();
} }
} }
}
else
{
foreach (i, Ri; Rs)
{
static if (isForwardRange!Ri)
{
if (needles[i].empty)
return 0;
}
}
Tuple!Rs t;
foreach (i, Ri; Rs)
{
static if (!isForwardRange!Ri)
{
t[i] = needles[i];
}
}
for (; !haystack.empty ; ++result, haystack.popFront())
{
foreach (i, Ri; Rs)
{
static if (isForwardRange!Ri)
{
t[i] = needles[i].save;
}
}
if (startsWith!pred(haystack.save, t.expand))
{
return result;
}
}
}
//Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement" //Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement"
static if (isInfinite!R1) assert(0); static if (isInfinite!R) assert(0);
else return -1; else return -1;
} }
/// ditto /// ditto
@ -4509,6 +4550,14 @@ unittest
assert(r.save.countUntil(r3) == -1); assert(r.save.countUntil(r3) == -1);
} }
unittest
{
assert(countUntil("hello world", "world", "asd") == 6);
assert(countUntil("hello world", "world", "ello") == 1);
assert(countUntil("hello world", "world", "") == 0);
assert(countUntil("hello world", "world", 'l') == 2);
}
/++ /++
Returns the number of elements which must be popped from $(D haystack) Returns the number of elements which must be popped from $(D haystack)
before $(D pred(haystack.front)) is $(D true). before $(D pred(haystack.front)) is $(D true).