std.string: Refactor indexOf to a per-CaseSensitive template

Use the same code for case sensitive and insensitive search, but
refactor the case sensitivity parameter to a compile-time value under
the hood, so that each instantiation receives its own propagated
attributes.
This commit is contained in:
Vladimir Panteleev 2018-11-23 21:41:04 +00:00
parent a7485d9857
commit 606465af0b
No known key found for this signature in database
GPG key ID: 5004F0FAD051576D

View file

@ -756,6 +756,87 @@ if (isInputRange!Range && isSomeChar!(ElementType!Range))
return -1; return -1;
} }
private template _indexOfStr(CaseSensitive cs)
{
private ptrdiff_t _indexOfStr(Range, Char)(Range s, const(Char)[] sub)
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
isSomeChar!Char)
{
alias Char1 = Unqual!(ElementEncodingType!Range);
static if (isSomeString!Range)
{
import std.algorithm.searching : find;
const(Char1)[] balance;
static if (cs == Yes.caseSensitive)
{
balance = find(s, sub);
}
else
{
balance = find!
((a, b) => toLower(a) == toLower(b))
(s, sub);
}
return () @trusted { return balance.empty ? -1 : balance.ptr - s.ptr; } ();
}
else
{
if (s.empty)
return -1;
if (sub.empty)
return 0; // degenerate case
import std.utf : byDchar, codeLength;
auto subr = sub.byDchar; // decode sub[] by dchar's
dchar sub0 = subr.front; // cache first character of sub[]
subr.popFront();
// Special case for single character search
if (subr.empty)
return indexOf(s, sub0, cs);
static if (cs == No.caseSensitive)
sub0 = toLower(sub0);
/* Classic double nested loop search algorithm
*/
ptrdiff_t index = 0; // count code unit index into s
for (auto sbydchar = s.byDchar(); !sbydchar.empty; sbydchar.popFront())
{
dchar c2 = sbydchar.front;
static if (cs == No.caseSensitive)
c2 = toLower(c2);
if (c2 == sub0)
{
auto s2 = sbydchar.save; // why s must be a forward range
foreach (c; subr.save)
{
s2.popFront();
if (s2.empty)
return -1;
static if (cs == Yes.caseSensitive)
{
if (c != s2.front)
goto Lnext;
}
else
{
if (toLower(c) != toLower(s2.front))
goto Lnext;
}
}
return index;
}
Lnext:
index += codeLength!Char1(c2);
}
return -1;
}
}
}
/++ /++
Searches for substring in `s`. Searches for substring in `s`.
@ -787,72 +868,10 @@ ptrdiff_t indexOf(Range, Char)(Range s, const(Char)[] sub,
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
isSomeChar!Char) isSomeChar!Char)
{ {
alias Char1 = Unqual!(ElementEncodingType!Range);
static if (isSomeString!Range)
{
import std.algorithm.searching : find;
const(Char1)[] balance;
if (cs == Yes.caseSensitive) if (cs == Yes.caseSensitive)
{ return _indexOfStr!(Yes.caseSensitive)(s, sub);
balance = find(s, sub);
}
else else
{ return _indexOfStr!(No.caseSensitive)(s, sub);
balance = find!
((a, b) => toLower(a) == toLower(b))
(s, sub);
}
return () @trusted { return balance.empty ? -1 : balance.ptr - s.ptr; } ();
}
else
{
if (s.empty)
return -1;
if (sub.empty)
return 0; // degenerate case
import std.utf : byDchar, codeLength;
auto subr = sub.byDchar; // decode sub[] by dchar's
dchar sub0 = subr.front; // cache first character of sub[]
subr.popFront();
// Special case for single character search
if (subr.empty)
return indexOf(s, sub0, cs);
if (cs == No.caseSensitive)
sub0 = toLower(sub0);
/* Classic double nested loop search algorithm
*/
ptrdiff_t index = 0; // count code unit index into s
for (auto sbydchar = s.byDchar(); !sbydchar.empty; sbydchar.popFront())
{
dchar c2 = sbydchar.front;
if (cs == No.caseSensitive)
c2 = toLower(c2);
if (c2 == sub0)
{
auto s2 = sbydchar.save; // why s must be a forward range
foreach (c; subr.save)
{
s2.popFront();
if (s2.empty)
return -1;
if (cs == Yes.caseSensitive ? c != s2.front
: toLower(c) != toLower(s2.front)
)
goto Lnext;
}
return index;
}
Lnext:
index += codeLength!Char1(c2);
}
return -1;
}
} }
/// Ditto /// Ditto