Skip to content

Commit

Permalink
Fix Issue 18948 - toLower and toUpper should work with random access …
Browse files Browse the repository at this point in the history
…ranges
  • Loading branch information
JackStouffer committed Jun 5, 2018
1 parent 7ab0e8c commit fa5830c
Showing 1 changed file with 68 additions and 17 deletions.
85 changes: 68 additions & 17 deletions std/uni.d
Expand Up @@ -8997,20 +8997,24 @@ private alias UpperTriple = AliasSeq!(toUpperIndex, MAX_SIMPLE_UPPER, toUpperTab
private alias LowerTriple = AliasSeq!(toLowerIndex, MAX_SIMPLE_LOWER, toLowerTab);

// generic toUpper/toLower on whole string, creates new or returns as is
private S toCase(alias indexFn, uint maxIdx, alias tableFn, alias asciiConvert, S)(S s) @trusted pure
if (isSomeString!S)
private ElementEncodingType!S[] toCase(alias indexFn, uint maxIdx, alias tableFn, alias asciiConvert, S)(S s)
if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
{
import std.array : appender;
import std.array : appender, array;
import std.ascii : isASCII;
import std.utf : byDchar;

foreach (i, dchar cOuter; s)
auto r = s.byDchar;
for (size_t i; !r.empty; ++i, r.popFront())
{
auto cOuter = r.front;
ushort idx = indexFn(cOuter);
if (idx == ushort.max)
continue;
auto result = appender!S(s[0 .. i]);
auto result = appender!(ElementEncodingType!S[])();
result.put(s[0 .. i]);
result.reserve(s.length);
foreach (dchar c; s[i .. $])
foreach (dchar c; s[i .. $].byDchar)
{
if (c.isASCII)
{
Expand Down Expand Up @@ -9039,7 +9043,11 @@ if (isSomeString!S)
}
return result.data;
}
return s;

static if (isSomeString!S)
return s;
else
return s.array;
}

@safe unittest //12428
Expand Down Expand Up @@ -9783,16 +9791,28 @@ dchar toLower(dchar c)
}

/++
Returns a string which is identical to `s` except that all of its
Creates a new array which is identical to `s` except that all of its
characters are converted to lowercase (by preforming Unicode lowercase mapping).
If none of `s` characters were affected, then `s` itself is returned.
If none of `s` characters were affected, then `s` itself is returned if `s` is a
`string`-like type.
Params:
s = A $(REF_ALTTEXT random access range, isRandomAccessRange, std,range,primitives)
of characters
Returns:
An array with the same element type as `s`.
+/
S toLower(S)(S s) @trusted pure
if (isSomeString!S)
ElementEncodingType!S[] toLower(S)(S s)
if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
{
static import std.ascii;
return toCase!(LowerTriple, std.ascii.toLower)(s);

static if (isSomeString!S)
return () @trusted { return toCase!(LowerTriple, std.ascii.toLower)(s); } ();
else
return toCase!(LowerTriple, std.ascii.toLower)(s);
}

// overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/
{
Expand Down Expand Up @@ -9900,6 +9920,15 @@ if (isSomeString!S)
assert(toUpper(c) == '\u1F8F');
}

@safe pure unittest
{
import std.algorithm.comparison : cmp, equal;
import std.utf : byCodeUnit;
auto r1 = "FoL".byCodeUnit;
assert(r1.toLower.cmp("fol") == 0);
auto r2 = "A\u0460B\u0461d".byCodeUnit;
assert(r2.toLower.cmp("a\u0461b\u0461d") == 0);
}

/++
If `c` is a Unicode lowercase $(CHARACTER), then its uppercase equivalent
Expand Down Expand Up @@ -9965,16 +9994,28 @@ dchar toUpper(dchar c)
}

/++
Returns a string which is identical to `s` except that all of its
Allocates a new array which is identical to `s` except that all of its
characters are converted to uppercase (by preforming Unicode uppercase mapping).
If none of `s` characters were affected, then `s` itself is returned.
If none of `s` characters were affected, then `s` itself is returned if `s`
is a `string`-like type.
Params:
s = A $(REF_ALTTEXT random access range, isRandomAccessRange, std,range,primitives)
of characters
Returns:
An new array with the same element type as `s`.
+/
S toUpper(S)(S s) @trusted pure
if (isSomeString!S)
ElementEncodingType!S[] toUpper(S)(S s)
if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
{
static import std.ascii;
return toCase!(UpperTriple, std.ascii.toUpper)(s);

static if (isSomeString!S)
return () @trusted { return toCase!(UpperTriple, std.ascii.toUpper)(s); } ();
else
return toCase!(UpperTriple, std.ascii.toUpper)(s);
}

// overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/
{
Expand Down Expand Up @@ -10088,6 +10129,16 @@ if (isSomeString!S)
}}
}

// test random access ranges
@safe pure unittest
{
import std.algorithm.comparison : cmp;
import std.utf : byCodeUnit;
auto s1 = "FoL".byCodeUnit;
assert(s1.toUpper.cmp("FOL") == 0);
auto s2 = "a\u0460B\u0461d".byCodeUnit;
assert(s2.toUpper.cmp("A\u0460B\u0460D") == 0);
}

/++
Returns whether `c` is a Unicode alphabetic $(CHARACTER)
Expand Down

0 comments on commit fa5830c

Please sign in to comment.