Merge pull request #6545 from JackStouffer/toCase-random-access

Issue 18948 - std.uni.toLower and std.uni.toUpper should work with random access ranges
merged-on-behalf-of: Jack Stouffer <jack@jackstouffer.com>
This commit is contained in:
The Dlang Bot 2018-06-05 17:40:33 +02:00 committed by GitHub
commit cc58e8a7bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -8996,20 +8996,24 @@ private alias UpperTriple = AliasSeq!(toUpperIndex, MAX_SIMPLE_UPPER, toUpperTab
private alias LowerTriple = AliasSeq!(toLowerIndex, MAX_SIMPLE_LOWER, toLowerTab); private alias LowerTriple = AliasSeq!(toLowerIndex, MAX_SIMPLE_LOWER, toLowerTab);
// generic toUpper/toLower on whole string, creates new or returns as is // 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 private ElementEncodingType!S[] toCase(alias indexFn, uint maxIdx, alias tableFn, alias asciiConvert, S)(S s)
if (isSomeString!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.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); ushort idx = indexFn(cOuter);
if (idx == ushort.max) if (idx == ushort.max)
continue; continue;
auto result = appender!S(s[0 .. i]); auto result = appender!(ElementEncodingType!S[])();
result.put(s[0 .. i]);
result.reserve(s.length); result.reserve(s.length);
foreach (dchar c; s[i .. $]) foreach (dchar c; s[i .. $].byDchar)
{ {
if (c.isASCII) if (c.isASCII)
{ {
@ -9038,7 +9042,11 @@ if (isSomeString!S)
} }
return result.data; return result.data;
} }
static if (isSomeString!S)
return s; return s;
else
return s.array;
} }
@safe unittest //12428 @safe unittest //12428
@ -9782,16 +9790,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). 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 ElementEncodingType!S[] toLower(S)(S s)
if (isSomeString!S) if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
{ {
static import std.ascii; static import std.ascii;
static if (isSomeString!S)
return () @trusted { return toCase!(LowerTriple, std.ascii.toLower)(s); } ();
else
return toCase!(LowerTriple, std.ascii.toLower)(s); return toCase!(LowerTriple, std.ascii.toLower)(s);
} }
// overloads for the most common cases to reduce compile time // overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/ @safe pure /*TODO nothrow*/
{ {
@ -9899,6 +9919,15 @@ if (isSomeString!S)
assert(toUpper(c) == '\u1F8F'); 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 If `c` is a Unicode lowercase $(CHARACTER), then its uppercase equivalent
@ -9964,16 +9993,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). 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 ElementEncodingType!S[] toUpper(S)(S s)
if (isSomeString!S) if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
{ {
static import std.ascii; static import std.ascii;
static if (isSomeString!S)
return () @trusted { return toCase!(UpperTriple, std.ascii.toUpper)(s); } ();
else
return toCase!(UpperTriple, std.ascii.toUpper)(s); return toCase!(UpperTriple, std.ascii.toUpper)(s);
} }
// overloads for the most common cases to reduce compile time // overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/ @safe pure /*TODO nothrow*/
{ {
@ -10087,6 +10128,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) Returns whether `c` is a Unicode alphabetic $(CHARACTER)