Merge pull request #1024 from monarchdodra/countStarts

performance tweaks for countUntil
This commit is contained in:
Andrei Alexandrescu 2012-12-24 09:44:02 -08:00
commit 58fde7057f

View file

@ -4253,16 +4253,33 @@ ptrdiff_t countUntil(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
typeof(return) result; typeof(return) result;
static if (hasLength!R1) //Note: Narrow strings don't have length. static if (hasLength!R1) //Note: Narrow strings don't have length.
{ {
//Delegate to find. Find is very efficient //We delegate to find because find is very efficient.
//We save haystack, but we don't care for needle //We store the length of the haystack so we don't have to save it.
auto r2 = find!pred(haystack.save, needle); auto len = haystack.length;
if (!r2.empty) return cast(typeof(return)) (haystack.length - r2.length); auto r2 = find!pred(haystack, needle);
if (!r2.empty)
return cast(typeof(return)) (len - r2.length);
} }
else else
{ {
//Default case, slower route doing startsWith iteration //Default case, slower route doing startsWith iteration
for ( ; !haystack.empty ; ++result, haystack.popFront() ) for ( ; !haystack.empty ; ++result )
if (startsWith!pred(haystack.save, needle.save)) return result; {
//We compare the first elements of the ranges here before
//forwarding to startsWith. This avoids making useless saves to
//haystack/needle if they aren't even going to be mutated anyways.
//It also cuts down on the amount of pops on haystack.
if (haystack.front == needle.front)
{
//Here, we need to save the needle before popping it.
//haystack we pop in all paths, so we do that, and then save.
haystack.popFront();
if (startsWith!pred(haystack.save, needle.save.dropOne()))
return result;
}
else
haystack.popFront();
}
} }
//Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement" //Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement"
@ -4292,6 +4309,16 @@ unittest
assert(countUntil([0, 7, 12, 22, 9], 9) == 4); 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);
} }
unittest
{
auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]);
auto r2 = new ReferenceForwardRange!int([3, 4]);
auto r3 = new ReferenceForwardRange!int([3, 5]);
assert(r.save.countUntil(3) == 3);
assert(r.save.countUntil(r2) == 3);
assert(r.save.countUntil(7) == -1);
assert(r.save.countUntil(r3) == -1);
}
/++ /++
Returns the number of elements which must be popped from $(D haystack) Returns the number of elements which must be popped from $(D haystack)