mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 14:10:30 +03:00
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:
parent
a7485d9857
commit
606465af0b
1 changed files with 84 additions and 65 deletions
147
std/string.d
147
std/string.d
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue