Don't check UTF-8 correctness when inserting chars

- Fix bug when inserting char ranges that are not arrays
- Optimize insertion from the String own range
- Assume char and char ranges are correclty encoded (as it actually
should be) and don't throw an exception. This should make the most
common use cases nothrow (Fix #19). Dchars and Wchars are still encoded
because they should be converted to UTF-8 before inserting anyway.
This commit is contained in:
Eugen Wissner 2018-07-06 05:36:13 +02:00
parent a332d727af
commit 3df4eb6259

View File

@ -500,7 +500,7 @@ struct String
} }
} }
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String(0, 'K'); auto s = String(0, 'K');
assert(s.length == 0); assert(s.length == 0);
@ -580,16 +580,10 @@ struct String
* Params: * Params:
* chr = The character should be inserted. * chr = The character should be inserted.
* *
* Returns: The number of bytes inserted. * Returns: The number of bytes inserted (1).
*
* Throws: $(D_PSYMBOL UTFException).
*/ */
size_t insertBack(const char chr) @nogc pure @trusted size_t insertBack(char chr) @nogc nothrow pure @trusted
{ {
if ((chr & 0x80) != 0)
{
throw defaultAllocator.make!UTFException("Invalid UTF-8 character");
}
reserve(length + 1); reserve(length + 1);
*(data + length) = chr; *(data + length) = chr;
@ -653,8 +647,6 @@ struct String
* str = String should be inserted. * str = String should be inserted.
* *
* Returns: The number of bytes inserted. * Returns: The number of bytes inserted.
*
* Throws: $(D_PSYMBOL UTFException).
*/ */
size_t insertBack(R)(R str) @trusted size_t insertBack(R)(R str) @trusted
if (!isInfinite!R if (!isInfinite!R
@ -674,46 +666,18 @@ struct String
this.length_ = size; this.length_ = size;
return str.length; return str.length;
} }
else static if (isInstanceOf!(ByCodeUnit, R))
{
str.get.copy(this.data[length .. size]);
this.length_ = size;
return str.length;
}
else else
{ {
size_t insertedLength; size_t insertedLength;
while (!str.empty) foreach (c; str)
{ {
ubyte expectedLength; insertedLength += insertBack(c);
if ((str.front & 0x80) == 0x00)
{
expectedLength = 1;
}
else if ((str.front & 0xe0) == 0xc0)
{
expectedLength = 2;
}
else if ((str.front & 0xf0) == 0xe0)
{
expectedLength = 3;
}
else if ((str.front & 0xf8) == 0xf0)
{
expectedLength = 4;
}
else
{
throw defaultAllocator.make!UTFException("Invalid UTF-8 sequeunce");
}
size = length + expectedLength;
reserve(size);
for (; expectedLength > 0; --expectedLength)
{
if (str.empty)
{
throw defaultAllocator.make!UTFException("Invalid UTF-8 sequeunce");
}
*(data + length) = str.front;
str.popFront();
}
insertedLength += expectedLength;
this.length_ = size;
} }
return insertedLength; return insertedLength;
} }
@ -829,7 +793,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
String s; String s;
assert(s.capacity == 0); assert(s.capacity == 0);
@ -870,7 +834,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Die Alten lasen laut."); auto s = String("Die Alten lasen laut.");
assert(s.capacity == 21); assert(s.capacity == 21);
@ -895,7 +859,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("In allem Schreiben ist Schamlosigkeit."); auto s = String("In allem Schreiben ist Schamlosigkeit.");
assert(s.capacity == 38); assert(s.capacity == 38);
@ -992,7 +956,7 @@ struct String
* *
* Returns: Null-terminated string. * Returns: Null-terminated string.
*/ */
const(char)* toStringz() @nogc nothrow pure const(char)* toStringz() @nogc nothrow pure @system
{ {
reserve(length + 1); reserve(length + 1);
this.data[length] = '\0'; this.data[length] = '\0';
@ -1000,7 +964,7 @@ struct String
} }
/// ///
@nogc pure unittest @nogc nothrow pure @system unittest
{ {
auto s = String("C string."); auto s = String("C string.");
assert(s.toStringz()[0] == 'C'); assert(s.toStringz()[0] == 'C');
@ -1019,7 +983,7 @@ struct String
alias opDollar = length; alias opDollar = length;
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Piscis primuin a capite foetat."); auto s = String("Piscis primuin a capite foetat.");
assert(s.length == 31); assert(s.length == 31);
@ -1045,7 +1009,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Alea iacta est."); auto s = String("Alea iacta est.");
assert(s[0] == 'A'); assert(s[0] == 'A');
@ -1068,7 +1032,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Plutarchus"); auto s = String("Plutarchus");
auto r = s[]; auto r = s[];
@ -1087,7 +1051,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = const String("Was ich vermag, soll gern geschehen. Goethe"); auto s = const String("Was ich vermag, soll gern geschehen. Goethe");
auto r1 = s[]; auto r1 = s[];
@ -1163,7 +1127,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
String s; String s;
assert(s.empty); assert(s.empty);
@ -1208,7 +1172,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Vladimir Soloviev"); auto s = String("Vladimir Soloviev");
auto r = s[9 .. $]; auto r = s[9 .. $];
@ -1272,7 +1236,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Черная, потом пропахшая выть!"); auto s = String("Черная, потом пропахшая выть!");
s = String("Как мне тебя не ласкать, не любить?"); s = String("Как мне тебя не ласкать, не любить?");
@ -1300,10 +1264,11 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Оловом светится лужная голь..."); auto s = String("Оловом светится лужная голь...");
s = "Грустная песня, ты - русская боль."; s = "Грустная песня, ты - русская боль.";
assert(s == "Грустная песня, ты - русская боль.");
} }
/** /**
@ -1345,7 +1310,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
assert(String("Голубая кофта.") < String("Синие глаза.")); assert(String("Голубая кофта.") < String("Синие глаза."));
assert(String("Никакой я правды") < String("милой не сказал")[]); assert(String("Никакой я правды") < String("милой не сказал")[]);
@ -1398,7 +1363,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
assert(String("Милая спросила:") != String("Крутит ли метель?")); assert(String("Милая спросила:") != String("Крутит ли метель?"));
assert(String("Затопить бы печку,") != String("постелить постель.")[]); assert(String("Затопить бы печку,") != String("постелить постель.")[]);
@ -1431,7 +1396,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("alea iacta est."); auto s = String("alea iacta est.");
@ -1456,7 +1421,7 @@ struct String
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
} }
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s1 = String("Buttercup"); auto s1 = String("Buttercup");
auto s2 = String("Cap"); auto s2 = String("Cap");
@ -1470,7 +1435,7 @@ struct String
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
} }
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s1 = String("Wow"); auto s1 = String("Wow");
s1[] = 'a'; s1[] = 'a';
@ -1483,7 +1448,7 @@ struct String
return opSliceAssign(value, 0, length); return opSliceAssign(value, 0, length);
} }
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s1 = String("ö"); auto s1 = String("ö");
s1[] = "oe"; s1[] = "oe";
@ -1575,7 +1540,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Казнить нельзя помиловать."); auto s = String("Казнить нельзя помиловать.");
s.insertAfter(s[0 .. 27], ","); s.insertAfter(s[0 .. 27], ",");
@ -1604,7 +1569,7 @@ struct String
} }
/// ///
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
auto s = String("Казнить нельзя помиловать."); auto s = String("Казнить нельзя помиловать.");
s.insertBefore(s[27 .. $], ","); s.insertBefore(s[27 .. $], ",");
@ -1628,8 +1593,8 @@ struct String
mixin DefaultAllocator; mixin DefaultAllocator;
} }
// Postblit works. // Postblit works
@nogc pure @safe unittest @nogc nothrow pure @safe unittest
{ {
void internFunc(String arg) void internFunc(String arg)
{ {
@ -1648,7 +1613,7 @@ struct String
topFunc(String("asdf")); topFunc(String("asdf"));
} }
// Const range produces mutable ranges. // Const range produces mutable ranges
@nogc pure @safe unittest @nogc pure @safe unittest
{ {
auto s = const String("И снизу лед, и сверху - маюсь между."); auto s = const String("И снизу лед, и сверху - маюсь между.");
@ -1674,7 +1639,7 @@ struct String
} }
} }
// Can pop multibyte characters. // Can pop multibyte characters
@nogc pure @safe unittest @nogc pure @safe unittest
{ {
auto s = String("\U00024B62\U00002260"); auto s = String("\U00024B62\U00002260");
@ -1691,3 +1656,12 @@ struct String
s[$ - 3] = 0xf0; s[$ - 3] = 0xf0;
assertThrown!UTFException(&(range.popFront)); assertThrown!UTFException(&(range.popFront));
} }
// Inserts own char range correctly
@nogc nothrow pure @safe unittest
{
auto s1 = String(`ü`);
String s2;
s2.insertBack(s1[]);
assert(s1 == s2);
}