support for non RA with length in startWith

As suggested by Andrei.

Also: More unittests
This commit is contained in:
monarch dodra 2013-01-02 17:48:49 +01:00
parent d00be2ff1a
commit b39752d5c7

View file

@ -4662,11 +4662,11 @@ if (isInputRange!R1 &&
else else
enum isDefaultPred = false; enum isDefaultPred = false;
//Note: While narrow strings don't have a "true" length, for a narrow string to start with another
//narrow string *of the same type*, it must have *at least* as many code units.
static if ((hasLength!R1 && hasLength!R2) || static if ((hasLength!R1 && hasLength!R2) ||
(isNarrowString!R1 && isNarrowString!R2 && ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof)) (isNarrowString!R1 && isNarrowString!R2 && ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof))
{ {
//Note: While narrow strings don't have a "true" length, for a narrow string to start with another
//narrow string *of the same type*, it must have *at least* as many encoding elements.
if (haystack.length < needle.length) if (haystack.length < needle.length)
return false; return false;
} }
@ -4674,10 +4674,12 @@ if (isInputRange!R1 &&
static if (isDefaultPred && isArray!R1 && isArray!R2 && static if (isDefaultPred && isArray!R1 && isArray!R2 &&
is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2))) is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2)))
{ {
//Array slice comparison mode
return haystack[0 .. needle.length] == needle; return haystack[0 .. needle.length] == needle;
} }
else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2) else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2)
{ {
//RA dual indexing mode
foreach (j; 0 .. needle.length) foreach (j; 0 .. needle.length)
{ {
if (!binaryFun!pred(needle[j], haystack[j])) if (!binaryFun!pred(needle[j], haystack[j]))
@ -4689,14 +4691,27 @@ if (isInputRange!R1 &&
} }
else else
{ {
if (needle.empty) //Standard input range mode
return true; if (needle.empty) return true;
static if (hasLength!R1 && hasLength!R2)
for (; !haystack.empty; haystack.popFront())
{ {
if (!binaryFun!pred(haystack.front, needle.front)) break; //We have previously checked that haystack.length > needle.length,
needle.popFront(); //So no need to check haystack.empty during iteration
if (needle.empty) return true; for ( ; ; haystack.popFront() )
{
if (!binaryFun!pred(haystack.front, needle.front)) break;
needle.popFront();
if (needle.empty) return true;
}
}
else
{
for ( ; !haystack.empty ; haystack.popFront() )
{
if (!binaryFun!pred(haystack.front, needle.front)) break;
needle.popFront();
if (needle.empty) return true;
}
} }
return false; return false;
} }
@ -4727,6 +4742,7 @@ unittest
foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
{ {
//Lots of strings
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")));
assert(startsWith(to!S("abc"), to!T("a"))); assert(startsWith(to!S("abc"), to!T("a")));
@ -4743,18 +4759,34 @@ unittest
assert(startsWith(to!S("abc"), 'a')); assert(startsWith(to!S("abc"), 'a'));
assert(!startsWith(to!S("abc"), to!T("sab"))); assert(!startsWith(to!S("abc"), to!T("sab")));
assert(startsWith(to!S("abc"), 'x', to!T("aaa"), 'a', "sab") == 3); assert(startsWith(to!S("abc"), 'x', to!T("aaa"), 'a', "sab") == 3);
//Unicode
assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("\uFF28el"))); assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("\uFF28el")));
assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("Hel"), to!T("\uFF28el")) == 2); assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("Hel"), to!T("\uFF28el")) == 2);
assert(startsWith(to!S("日本語"), to!T("日本"))); assert(startsWith(to!S("日本語"), to!T("日本")));
assert(startsWith(to!S("日本語"), to!T("日本語"))); assert(startsWith(to!S("日本語"), to!T("日本語")));
assert(!startsWith(to!S("日本"), to!T("日本語"))); assert(!startsWith(to!S("日本"), to!T("日本語")));
//Empty
assert(startsWith(to!S(""), T.init));
assert(!startsWith(to!S(""), 'a'));
assert(startsWith(to!S("a"), T.init));
assert(startsWith(to!S("a"), T.init, "") == 1);
assert(startsWith(to!S("a"), T.init, 'a') == 1);
assert(startsWith(to!S("a"), 'a', T.init) == 2);
} }
} }
//Length but no RA
assert(!startsWith("abc".takeExactly(3), "abcd".takeExactly(4)));
assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(3)));
assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(1)));
foreach (T; TypeTuple!(int, short)) foreach (T; TypeTuple!(int, short))
{ {
immutable arr = cast(T[])[0, 1, 2, 3, 4, 5]; immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
//RA range
assert(startsWith(arr, cast(int[])null)); assert(startsWith(arr, cast(int[])null));
assert(!startsWith(arr, 5)); assert(!startsWith(arr, 5));
assert(!startsWith(arr, 1)); assert(!startsWith(arr, 1));
@ -4766,6 +4798,7 @@ unittest
assert(!startsWith(arr, [0, 1, 7])); assert(!startsWith(arr, [0, 1, 7]));
assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2); assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2);
//Normal input range
assert(!startsWith(filter!"true"(arr), 1)); assert(!startsWith(filter!"true"(arr), 1));
assert(startsWith(filter!"true"(arr), 0)); assert(startsWith(filter!"true"(arr), 0));
assert(startsWith(filter!"true"(arr), [0])); assert(startsWith(filter!"true"(arr), [0]));
@ -4777,6 +4810,10 @@ unittest
assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1); assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1);
assert(!startsWith(arr, filter!"true"([0, 1, 7]))); assert(!startsWith(arr, filter!"true"([0, 1, 7])));
assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2); assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2);
//Non-default pred
assert(startsWith!("a%10 == b%10")(arr, [10, 11]));
assert(!startsWith!("a%10 == b%10")(arr, [10, 12]));
} }
} }
@ -5004,6 +5041,7 @@ unittest
foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
{ {
//Lots of strings
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")));
assert(!endsWith(to!S("abc"), to!T("b"))); assert(!endsWith(to!S("abc"), to!T("b")));
@ -5017,9 +5055,21 @@ unittest
assert(endsWith(to!S("abc"), to!T("x"), "aaa", "c", "sab") == 3); assert(endsWith(to!S("abc"), to!T("x"), "aaa", "c", "sab") == 3);
assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co"))); assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")));
assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2); assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2);
//Unicode
assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")));
assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2);
assert(endsWith(to!S("日本語"), to!T("本語"))); assert(endsWith(to!S("日本語"), to!T("本語")));
assert(endsWith(to!S("日本語"), to!T("日本語"))); assert(endsWith(to!S("日本語"), to!T("日本語")));
assert(!endsWith(to!S("本語"), to!T("日本語"))); assert(!endsWith(to!S("本語"), to!T("日本語")));
//Empty
assert(endsWith(to!S(""), T.init));
assert(!endsWith(to!S(""), 'a'));
assert(endsWith(to!S("a"), T.init));
assert(endsWith(to!S("a"), T.init, "") == 1);
assert(endsWith(to!S("a"), T.init, 'a') == 1);
assert(endsWith(to!S("a"), 'a', T.init) == 2);
} }
} }
@ -5027,6 +5077,7 @@ unittest
{ {
immutable arr = cast(T[])[0, 1, 2, 3, 4, 5]; immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
//RA range
assert(endsWith(arr, cast(int[])null)); assert(endsWith(arr, cast(int[])null));
assert(!endsWith(arr, 0)); assert(!endsWith(arr, 0));
assert(!endsWith(arr, 4)); assert(!endsWith(arr, 4));
@ -5038,6 +5089,7 @@ unittest
assert(!endsWith(arr, [2, 4, 5])); assert(!endsWith(arr, [2, 4, 5]));
assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2); assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2);
//Normal input range
assert(!endsWith(filterBidirectional!"true"(arr), 4)); assert(!endsWith(filterBidirectional!"true"(arr), 4));
assert(endsWith(filterBidirectional!"true"(arr), 5)); assert(endsWith(filterBidirectional!"true"(arr), 5));
assert(endsWith(filterBidirectional!"true"(arr), [5])); assert(endsWith(filterBidirectional!"true"(arr), [5]));
@ -5050,6 +5102,7 @@ unittest
assert(!endsWith(arr, filterBidirectional!"true"([2, 4, 5]))); assert(!endsWith(arr, filterBidirectional!"true"([2, 4, 5])));
assert(endsWith(arr, [2, 4, 5], filterBidirectional!"true"([3, 4, 5])) == 2); assert(endsWith(arr, [2, 4, 5], filterBidirectional!"true"([3, 4, 5])) == 2);
//Non-default pred
assert(endsWith!("a%10 == b%10")(arr, [14, 15])); assert(endsWith!("a%10 == b%10")(arr, [14, 15]));
assert(!endsWith!("a%10 == b%10")(arr, [15, 14])); assert(!endsWith!("a%10 == b%10")(arr, [15, 14]));
} }