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
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) ||
(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)
return false;
}
@ -4674,10 +4674,12 @@ if (isInputRange!R1 &&
static if (isDefaultPred && isArray!R1 && isArray!R2 &&
is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2)))
{
//Array slice comparison mode
return haystack[0 .. needle.length] == needle;
}
else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2)
{
//RA dual indexing mode
foreach (j; 0 .. needle.length)
{
if (!binaryFun!pred(needle[j], haystack[j]))
@ -4689,14 +4691,27 @@ if (isInputRange!R1 &&
}
else
{
if (needle.empty)
return true;
for (; !haystack.empty; haystack.popFront())
//Standard input range mode
if (needle.empty) return true;
static if (hasLength!R1 && hasLength!R2)
{
if (!binaryFun!pred(haystack.front, needle.front)) break;
needle.popFront();
if (needle.empty) return true;
//We have previously checked that haystack.length > needle.length,
//So no need to check haystack.empty during iteration
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;
}
@ -4727,6 +4742,7 @@ unittest
foreach (T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring))
{
//Lots of strings
assert(startsWith(to!S("abc"), to!T("")));
assert(startsWith(to!S("ab"), 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"), to!T("sab")));
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("Hel"), to!T("\uFF28el")) == 2);
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))
{
immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
//RA range
assert(startsWith(arr, cast(int[])null));
assert(!startsWith(arr, 5));
assert(!startsWith(arr, 1));
@ -4766,6 +4798,7 @@ unittest
assert(!startsWith(arr, [0, 1, 7]));
assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2);
//Normal input range
assert(!startsWith(filter!"true"(arr), 1));
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])));
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))
{
//Lots of strings
assert(endsWith(to!S("abc"), to!T("")));
assert(!endsWith(to!S("abc"), to!T("a")));
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("\uFF28el\uFF4co"), to!T("l\uFF4co")));
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("日本語")));
//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];
//RA range
assert(endsWith(arr, cast(int[])null));
assert(!endsWith(arr, 0));
assert(!endsWith(arr, 4));
@ -5038,6 +5089,7 @@ unittest
assert(!endsWith(arr, [2, 4, 5]));
assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2);
//Normal input range
assert(!endsWith(filterBidirectional!"true"(arr), 4));
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, [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, [15, 14]));
}