Optimizations for startsWith and endsWith.

This commit is contained in:
jmdavis 2012-07-02 21:55:07 -07:00
parent 6203835e5d
commit 121a69a04b
2 changed files with 80 additions and 66 deletions

View file

@ -4152,12 +4152,15 @@ if (isInputRange!R1 &&
else else
enum isDefaultPred = false; enum isDefaultPred = false;
// Special case for two arrays static if (isDefaultPred && isArray!R1 && isArray!R2 &&
static if (isArray!R1 && isArray!R2 && is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2)))
((!isSomeString!R1 && !isSomeString!R2) || {
(isSomeString!R1 && isSomeString!R2 && if (haystack.length < needle.length) return false;
is(Unqual!(typeof(haystack[0])) == Unqual!(typeof(needle[0]))) &&
isDefaultPred))) return haystack[0 .. needle.length] == needle;
}
else static if (isArray!R1 && isArray!R2 &&
!isNarrowString!R1 && !isNarrowString!R2)
{ {
if (haystack.length < needle.length) return false; if (haystack.length < needle.length) return false;
@ -4205,8 +4208,7 @@ unittest
debug(std_algorithm) scope(success) debug(std_algorithm) scope(success)
writeln("unittest @", __FILE__, ":", __LINE__, " done."); writeln("unittest @", __FILE__, ":", __LINE__, " done.");
//foreach (S; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) foreach (S; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
foreach (S; TypeTuple!(char[], wstring))
{ {
assert(!startsWith(to!S("abc"), 'c')); assert(!startsWith(to!S("abc"), 'c'));
assert(startsWith(to!S("abc"), 'a', 'c') == 1); assert(startsWith(to!S("abc"), 'a', 'c') == 1);
@ -4214,8 +4216,7 @@ unittest
assert(startsWith(to!S("abc"), 'x', 'n', 'a') == 3); assert(startsWith(to!S("abc"), 'x', 'n', 'a') == 3);
assert(startsWith(to!S("\uFF28abc"), 'a', '\uFF28', 'c') == 2); assert(startsWith(to!S("\uFF28abc"), 'a', '\uFF28', 'c') == 2);
//foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
foreach (T; TypeTuple!(dchar[], string))
{ {
assert(startsWith(to!S("abc"), to!T(""))); assert(startsWith(to!S("abc"), to!T("")));
assert(startsWith(to!S("ab"), to!T("a"))); assert(startsWith(to!S("ab"), to!T("a")));
@ -4238,28 +4239,33 @@ unittest
} }
} }
assert(startsWith([0, 1, 2, 3, 4, 5], cast(int[])null)); foreach(T; TypeTuple!(int, short))
assert(!startsWith([0, 1, 2, 3, 4, 5], 5)); {
assert(!startsWith([0, 1, 2, 3, 4, 5], 1)); immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
assert(startsWith([0, 1, 2, 3, 4, 5], 0));
assert(startsWith([0, 1, 2, 3, 4, 5], 5, 0, 1) == 2);
assert(startsWith([0, 1, 2, 3, 4, 5], [0]));
assert(startsWith([0, 1, 2, 3, 4, 5], [0, 1]));
assert(startsWith([0, 1, 2, 3, 4, 5], [0, 1], 7) == 1);
assert(!startsWith([0, 1, 2, 3, 4, 5], [0, 1, 7]));
assert(startsWith([0, 1, 2, 3, 4, 5], [0, 1, 7], [0, 1, 2]) == 2);
assert(!startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), 1)); assert(startsWith(arr, cast(int[])null));
assert(startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), 0)); assert(!startsWith(arr, 5));
assert(startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), [0])); assert(!startsWith(arr, 1));
assert(startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), [0, 1])); assert(startsWith(arr, 0));
assert(startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), [0, 1], 7) == 1); assert(startsWith(arr, 5, 0, 1) == 2);
assert(!startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), [0, 1, 7])); assert(startsWith(arr, [0]));
assert(startsWith(filter!"true"([0, 1, 2, 3, 4, 5]), [0, 1, 7], [0, 1, 2]) == 2); assert(startsWith(arr, [0, 1]));
assert(startsWith([0, 1, 2, 3, 4, 5], filter!"true"([0, 1]))); assert(startsWith(arr, [0, 1], 7) == 1);
assert(startsWith([0, 1, 2, 3, 4, 5], filter!"true"([0, 1]), 7) == 1); assert(!startsWith(arr, [0, 1, 7]));
assert(!startsWith([0, 1, 2, 3, 4, 5], filter!"true"([0, 1, 7]))); assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2);
assert(startsWith([0, 1, 2, 3, 4, 5], [0, 1, 7], filter!"true"([0, 1, 2])) == 2);
assert(!startsWith(filter!"true"(arr), 1));
assert(startsWith(filter!"true"(arr), 0));
assert(startsWith(filter!"true"(arr), [0]));
assert(startsWith(filter!"true"(arr), [0, 1]));
assert(startsWith(filter!"true"(arr), [0, 1], 7) == 1);
assert(!startsWith(filter!"true"(arr), [0, 1, 7]));
assert(startsWith(filter!"true"(arr), [0, 1, 7], [0, 1, 2]) == 2);
assert(startsWith(arr, filter!"true"([0, 1])));
assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1);
assert(!startsWith(arr, filter!"true"([0, 1, 7])));
assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2);
}
} }
/** /**
@ -4451,18 +4457,21 @@ if (isInputRange!R1 &&
else else
enum isDefaultPred = false; enum isDefaultPred = false;
// Special case for two arrays static if (isDefaultPred && isArray!R1 && isArray!R2 &&
static if (isArray!R1 && isArray!R2 && is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2)))
((!isSomeString!R1 && !isSomeString!R2) || {
(isSomeString!R1 && isSomeString!R2 && if (haystack.length < needle.length) return false;
is(Unqual!(typeof(haystack[0])) == Unqual!(typeof(needle[0]))) &&
isDefaultPred))) return haystack[$ - needle.length .. $] == needle;
}
else static if (isArray!R1 && isArray!R2 &&
!isNarrowString!R1 && !isNarrowString!R2)
{ {
if (haystack.length < needle.length) return false; if (haystack.length < needle.length) return false;
immutable diff = haystack.length - needle.length; immutable diff = haystack.length - needle.length;
foreach (j; 0 .. needle.length) foreach (j; 0 .. needle.length)
{ {
if (!binaryFun!(pred)(needle[j], haystack[j + diff])) if (!binaryFun!pred(needle[j], haystack[j + diff]))
// not found // not found
return false; return false;
} }
@ -4523,8 +4532,7 @@ unittest
return Result(r); return Result(r);
} }
//foreach (S; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) foreach (S; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
foreach (S; TypeTuple!(char[], wstring))
{ {
assert(!endsWith(to!S("abc"), 'a')); assert(!endsWith(to!S("abc"), 'a'));
assert(endsWith(to!S("abc"), 'a', 'c') == 2); assert(endsWith(to!S("abc"), 'a', 'c') == 2);
@ -4532,8 +4540,7 @@ unittest
assert(endsWith(to!S("abc"), 'x', 'n', 'c') == 3); assert(endsWith(to!S("abc"), 'x', 'n', 'c') == 3);
assert(endsWith(to!S("abc\uFF28"), 'a', '\uFF28', 'c') == 2); assert(endsWith(to!S("abc\uFF28"), 'a', '\uFF28', 'c') == 2);
//foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
foreach (T; TypeTuple!(dchar[], string))
{ {
assert(endsWith(to!S("abc"), to!T(""))); assert(endsWith(to!S("abc"), to!T("")));
assert(!endsWith(to!S("abc"), to!T("a"))); assert(!endsWith(to!S("abc"), to!T("a")));
@ -4551,28 +4558,33 @@ unittest
} }
} }
assert(endsWith([0, 1, 2, 3, 4, 5], cast(int[])null)); foreach(T; TypeTuple!(int, short))
assert(!endsWith([0, 1, 2, 3, 4, 5], 0)); {
assert(!endsWith([0, 1, 2, 3, 4, 5], 4)); immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
assert(endsWith([0, 1, 2, 3, 4, 5], 5));
assert(endsWith([0, 1, 2, 3, 4, 5], 0, 4, 5) == 3);
assert(endsWith([0, 1, 2, 3, 4, 5], [5]));
assert(endsWith([0, 1, 2, 3, 4, 5], [4, 5]));
assert(endsWith([0, 1, 2, 3, 4, 5], [4, 5], 7) == 1);
assert(!endsWith([0, 1, 2, 3, 4, 5], [2, 4, 5]));
assert(endsWith([0, 1, 2, 3, 4, 5], [2, 4, 5], [3, 4, 5]) == 2);
assert(!endsWith(wrap([0, 1, 2, 3, 4, 5]), 4)); assert(endsWith(arr, cast(int[])null));
assert(endsWith(wrap([0, 1, 2, 3, 4, 5]), 5)); assert(!endsWith(arr, 0));
assert(endsWith(wrap([0, 1, 2, 3, 4, 5]), [5])); assert(!endsWith(arr, 4));
assert(endsWith(wrap([0, 1, 2, 3, 4, 5]), [4, 5])); assert(endsWith(arr, 5));
assert(endsWith(wrap([0, 1, 2, 3, 4, 5]), [4, 5], 7) == 1); assert(endsWith(arr, 0, 4, 5) == 3);
assert(!endsWith(wrap([0, 1, 2, 3, 4, 5]), [2, 4, 5])); assert(endsWith(arr, [5]));
assert(endsWith(wrap([0, 1, 2, 3, 4, 5]), [2, 4, 5], [3, 4, 5]) == 2); assert(endsWith(arr, [4, 5]));
assert(endsWith([0, 1, 2, 3, 4, 5], wrap([4, 5]))); assert(endsWith(arr, [4, 5], 7) == 1);
assert(endsWith([0, 1, 2, 3, 4, 5], wrap([4, 5]), 7) == 1); assert(!endsWith(arr, [2, 4, 5]));
assert(!endsWith([0, 1, 2, 3, 4, 5], wrap([2, 4, 5]))); assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2);
assert(endsWith([0, 1, 2, 3, 4, 5], [2, 4, 5], wrap([3, 4, 5])) == 2);
assert(!endsWith(wrap(arr), 4));
assert(endsWith(wrap(arr), 5));
assert(endsWith(wrap(arr), [5]));
assert(endsWith(wrap(arr), [4, 5]));
assert(endsWith(wrap(arr), [4, 5], 7) == 1);
assert(!endsWith(wrap(arr), [2, 4, 5]));
assert(endsWith(wrap(arr), [2, 4, 5], [3, 4, 5]) == 2);
assert(endsWith(arr, wrap([4, 5])));
assert(endsWith(arr, wrap([4, 5]), 7) == 1);
assert(!endsWith(arr, wrap([2, 4, 5])));
assert(endsWith(arr, [2, 4, 5], wrap([3, 4, 5])) == 2);
}
} }
/** /**

View file

@ -1684,6 +1684,8 @@ C[] chomp(C)(C[] str)
//Pops off the last character if it's lineSep or paraSep. //Pops off the last character if it's lineSep or paraSep.
static if(is(C : const char)) static if(is(C : const char))
{ {
//In UTF-8, lineSep and paraSep are [226, 128, 168], and
//[226, 128, 169] respectively, so their first two bytes are the same.
case 168: //Last byte of lineSep case 168: //Last byte of lineSep
case 169: //Last byte of paraSep case 169: //Last byte of paraSep
{ {
@ -1712,7 +1714,7 @@ C1[] chomp(C1, C2)(C1[] str, const(C2)[] delimiter)
static if(is(Unqual!C1 == Unqual!C2)) static if(is(Unqual!C1 == Unqual!C2))
{ {
if(str.length >= delimiter.length && str[$ - delimiter.length .. $] == delimiter) if(str.endsWith(delimiter))
return str[0 .. $ - delimiter.length]; return str[0 .. $ - delimiter.length];
} }
@ -1772,7 +1774,7 @@ unittest
{ {
// @@@ BUG IN COMPILER, MUST INSERT CAST // @@@ BUG IN COMPILER, MUST INSERT CAST
assert(chomp(cast(S)null, cast(T)null) is null); assert(chomp(cast(S)null, cast(T)null) is null);
assert(chomp("hello\n", cast(T)null) == "hello"); assert(chomp(to!S("hello\n"), cast(T)null) == "hello");
assert(chomp(to!S("hello"), to!T("o")) == "hell"); assert(chomp(to!S("hello"), to!T("o")) == "hell");
assert(chomp(to!S("hello"), to!T("p")) == "hello"); assert(chomp(to!S("hello"), to!T("p")) == "hello");
// @@@ BUG IN COMPILER, MUST INSERT CAST // @@@ BUG IN COMPILER, MUST INSERT CAST
@ -1803,7 +1805,7 @@ C1[] chompPrefix(C1, C2)(C1[] str, C2[] delimiter)
{ {
static if(is(Unqual!C1 == Unqual!C2)) static if(is(Unqual!C1 == Unqual!C2))
{ {
if(str.length >= delimiter.length && str[0 .. delimiter.length] == delimiter) if(str.startsWith(delimiter))
return str[delimiter.length .. $]; return str[delimiter.length .. $];
return str; return str;
} }