mirror of
https://github.com/dlang/phobos.git
synced 2025-05-11 14:41:08 +03:00
Merge pull request #2667 from 9il/conv
std.conv: clean imports & parse (null and bool) fix
This commit is contained in:
commit
c0028b4cf9
1 changed files with 42 additions and 41 deletions
83
std/conv.d
83
std/conv.d
|
@ -21,10 +21,9 @@ WIKI = Phobos/StdConv
|
||||||
*/
|
*/
|
||||||
module std.conv;
|
module std.conv;
|
||||||
|
|
||||||
import core.checkedint, core.stdc.string;
|
public import std.ascii : LetterCase;
|
||||||
import std.algorithm, std.array, std.ascii, std.exception, std.range,
|
|
||||||
std.string, std.traits, std.typecons, std.typetuple, std.utf;
|
import std.exception, std.range, std.traits, std.typetuple;
|
||||||
import std.format;
|
|
||||||
|
|
||||||
/* ************* Exceptions *************** */
|
/* ************* Exceptions *************** */
|
||||||
|
|
||||||
|
@ -835,6 +834,7 @@ T toImpl(T, S)(S value)
|
||||||
}
|
}
|
||||||
else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
|
else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
// Converting void array to string
|
// Converting void array to string
|
||||||
alias Char = Unqual!(ElementEncodingType!T);
|
alias Char = Unqual!(ElementEncodingType!T);
|
||||||
auto raw = cast(const(ubyte)[]) value;
|
auto raw = cast(const(ubyte)[]) value;
|
||||||
|
@ -848,6 +848,7 @@ T toImpl(T, S)(S value)
|
||||||
}
|
}
|
||||||
else static if (isPointer!S && is(S : const(char)*))
|
else static if (isPointer!S && is(S : const(char)*))
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : strlen;
|
||||||
// It is unsafe because we cannot guarantee that the pointer is null terminated.
|
// It is unsafe because we cannot guarantee that the pointer is null terminated.
|
||||||
return value ? cast(T) value[0 .. strlen(value)].dup : cast(string)null;
|
return value ? cast(T) value[0 .. strlen(value)].dup : cast(string)null;
|
||||||
}
|
}
|
||||||
|
@ -1375,6 +1376,7 @@ T toImpl(T, S)(S value)
|
||||||
|
|
||||||
static if (isStaticArray!T)
|
static if (isStaticArray!T)
|
||||||
{
|
{
|
||||||
|
import std.string : format;
|
||||||
auto res = to!(E[])(value);
|
auto res = to!(E[])(value);
|
||||||
enforce!ConvException(T.length == res.length,
|
enforce!ConvException(T.length == res.length,
|
||||||
format("Length mismatch when converting to static array: %s vs %s", T.length, res.length));
|
format("Length mismatch when converting to static array: %s vs %s", T.length, res.length));
|
||||||
|
@ -1744,7 +1746,7 @@ T toImpl(T, S)(S value)
|
||||||
if (Member == value)
|
if (Member == value)
|
||||||
return Member;
|
return Member;
|
||||||
}
|
}
|
||||||
|
import std.string : format;
|
||||||
throw new ConvException(format("Value (%s) does not match any member value of enum '%s'", value, T.stringof));
|
throw new ConvException(format("Value (%s) does not match any member value of enum '%s'", value, T.stringof));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1837,20 +1839,20 @@ unittest
|
||||||
|
|
||||||
Target parse(Target, Source)(ref Source s)
|
Target parse(Target, Source)(ref Source s)
|
||||||
if (isInputRange!Source &&
|
if (isInputRange!Source &&
|
||||||
!isExactSomeString!Source &&
|
|
||||||
isSomeChar!(ElementType!Source) &&
|
isSomeChar!(ElementType!Source) &&
|
||||||
is(Unqual!Target == bool))
|
is(Unqual!Target == bool))
|
||||||
{
|
{
|
||||||
|
import std.ascii : toLower;
|
||||||
if (!s.empty)
|
if (!s.empty)
|
||||||
{
|
{
|
||||||
auto c1 = std.ascii.toLower(s.front);
|
auto c1 = toLower(s.front);
|
||||||
bool result = (c1 == 't');
|
bool result = (c1 == 't');
|
||||||
if (result || c1 == 'f')
|
if (result || c1 == 'f')
|
||||||
{
|
{
|
||||||
s.popFront();
|
s.popFront();
|
||||||
foreach (c; result ? "rue" : "alse")
|
foreach (c; result ? "rue" : "alse")
|
||||||
{
|
{
|
||||||
if (s.empty || std.ascii.toLower(s.front) != c)
|
if (s.empty || toLower(s.front) != c)
|
||||||
goto Lerr;
|
goto Lerr;
|
||||||
s.popFront();
|
s.popFront();
|
||||||
}
|
}
|
||||||
|
@ -2160,6 +2162,7 @@ in
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
|
import core.checkedint : mulu, addu;
|
||||||
if (radix == 10)
|
if (radix == 10)
|
||||||
return parse!Target(s);
|
return parse!Target(s);
|
||||||
|
|
||||||
|
@ -2259,6 +2262,7 @@ Target parse(Target, Source)(ref Source s)
|
||||||
if (isExactSomeString!Source &&
|
if (isExactSomeString!Source &&
|
||||||
is(Target == enum))
|
is(Target == enum))
|
||||||
{
|
{
|
||||||
|
import std.algorithm : startsWith;
|
||||||
Target result;
|
Target result;
|
||||||
size_t longest_match = 0;
|
size_t longest_match = 0;
|
||||||
|
|
||||||
|
@ -2316,6 +2320,8 @@ Target parse(Target, Source)(ref Source p)
|
||||||
if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
|
if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
|
||||||
isFloatingPoint!Target && !is(Target == enum))
|
isFloatingPoint!Target && !is(Target == enum))
|
||||||
{
|
{
|
||||||
|
import std.ascii : isDigit, isAlpha, toLower, toUpper, isHexDigit;
|
||||||
|
|
||||||
static import core.stdc.math/* : HUGE_VAL*/;
|
static import core.stdc.math/* : HUGE_VAL*/;
|
||||||
|
|
||||||
static immutable real[14] negtab =
|
static immutable real[14] negtab =
|
||||||
|
@ -2343,7 +2349,7 @@ Target parse(Target, Source)(ref Source p)
|
||||||
sign++;
|
sign++;
|
||||||
p.popFront();
|
p.popFront();
|
||||||
enforce(!p.empty, bailOut());
|
enforce(!p.empty, bailOut());
|
||||||
if (std.ascii.toLower(p.front) == 'i')
|
if (toLower(p.front) == 'i')
|
||||||
goto case 'i';
|
goto case 'i';
|
||||||
enforce(!p.empty, bailOut());
|
enforce(!p.empty, bailOut());
|
||||||
break;
|
break;
|
||||||
|
@ -2354,11 +2360,11 @@ Target parse(Target, Source)(ref Source p)
|
||||||
case 'i': case 'I':
|
case 'i': case 'I':
|
||||||
p.popFront();
|
p.popFront();
|
||||||
enforce(!p.empty, bailOut());
|
enforce(!p.empty, bailOut());
|
||||||
if (std.ascii.toLower(p.front) == 'n')
|
if (toLower(p.front) == 'n')
|
||||||
{
|
{
|
||||||
p.popFront();
|
p.popFront();
|
||||||
enforce(!p.empty, bailOut());
|
enforce(!p.empty, bailOut());
|
||||||
if (std.ascii.toLower(p.front) == 'f')
|
if (toLower(p.front) == 'f')
|
||||||
{
|
{
|
||||||
// 'inf'
|
// 'inf'
|
||||||
p.popFront();
|
p.popFront();
|
||||||
|
@ -2401,7 +2407,7 @@ Target parse(Target, Source)(ref Source p)
|
||||||
while (isHexDigit(i))
|
while (isHexDigit(i))
|
||||||
{
|
{
|
||||||
anydigits = 1;
|
anydigits = 1;
|
||||||
i = std.ascii.isAlpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0';
|
i = isAlpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0';
|
||||||
if (ndigits < 16)
|
if (ndigits < 16)
|
||||||
{
|
{
|
||||||
msdec = msdec * 16 + i;
|
msdec = msdec * 16 + i;
|
||||||
|
@ -2587,14 +2593,14 @@ Target parse(Target, Source)(ref Source p)
|
||||||
}
|
}
|
||||||
else // not hex
|
else // not hex
|
||||||
{
|
{
|
||||||
if (std.ascii.toUpper(p.front) == 'N' && !startsWithZero)
|
if (toUpper(p.front) == 'N' && !startsWithZero)
|
||||||
{
|
{
|
||||||
// nan
|
// nan
|
||||||
p.popFront();
|
p.popFront();
|
||||||
enforce(!p.empty && std.ascii.toUpper(p.front) == 'A',
|
enforce(!p.empty && toUpper(p.front) == 'A',
|
||||||
new ConvException("error converting input to floating point"));
|
new ConvException("error converting input to floating point"));
|
||||||
p.popFront();
|
p.popFront();
|
||||||
enforce(!p.empty && std.ascii.toUpper(p.front) == 'N',
|
enforce(!p.empty && toUpper(p.front) == 'N',
|
||||||
new ConvException("error converting input to floating point"));
|
new ConvException("error converting input to floating point"));
|
||||||
// skip past the last 'n'
|
// skip past the last 'n'
|
||||||
p.popFront();
|
p.popFront();
|
||||||
|
@ -3010,23 +3016,6 @@ Target parse(Target, Source)(ref Source s)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// string to bool conversions
|
|
||||||
Target parse(Target, Source)(ref Source s)
|
|
||||||
if (isExactSomeString!Source &&
|
|
||||||
is(Unqual!Target == bool))
|
|
||||||
{
|
|
||||||
if (s.length >= 4 && icmp(s[0 .. 4], "true") == 0)
|
|
||||||
{
|
|
||||||
s = s[4 .. $];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (s.length >= 5 && icmp(s[0 .. 5], "false") == 0)
|
|
||||||
{
|
|
||||||
s = s[5 .. $];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw parseError("bool should be case-insensitive 'true' or 'false'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tests for to!bool and parse!bool
|
Tests for to!bool and parse!bool
|
||||||
|
@ -3054,17 +3043,20 @@ Target parse(Target, Source)(ref Source s)
|
||||||
assert(b == true);
|
assert(b == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// string to null literal conversions
|
// input range to null literal conversions
|
||||||
Target parse(Target, Source)(ref Source s)
|
Target parse(Target, Source)(ref Source s)
|
||||||
if (isExactSomeString!Source &&
|
if (isInputRange!Source &&
|
||||||
|
isSomeChar!(ElementType!Source) &&
|
||||||
is(Unqual!Target == typeof(null)))
|
is(Unqual!Target == typeof(null)))
|
||||||
{
|
{
|
||||||
if (s.length >= 4 && icmp(s[0 .. 4], "null") == 0)
|
import std.ascii : toLower;
|
||||||
|
foreach (c; "null")
|
||||||
{
|
{
|
||||||
s = s[4 .. $];
|
if (s.empty || toLower(s.front) != c)
|
||||||
return null;
|
throw parseError("null should be case-insensitive 'null'");
|
||||||
|
s.popFront();
|
||||||
}
|
}
|
||||||
throw parseError("null should be case-insensitive 'null'");
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@safe pure unittest
|
@safe pure unittest
|
||||||
|
@ -3089,12 +3081,13 @@ Target parse(Target, Source)(ref Source s)
|
||||||
//Used internally by parse Array/AA, to remove ascii whites
|
//Used internally by parse Array/AA, to remove ascii whites
|
||||||
package void skipWS(R)(ref R r)
|
package void skipWS(R)(ref R r)
|
||||||
{
|
{
|
||||||
|
import std.ascii : isWhite;
|
||||||
static if (isSomeString!R)
|
static if (isSomeString!R)
|
||||||
{
|
{
|
||||||
//Implementation inspired from stripLeft.
|
//Implementation inspired from stripLeft.
|
||||||
foreach (i, dchar c; r)
|
foreach (i, dchar c; r)
|
||||||
{
|
{
|
||||||
if (!std.ascii.isWhite(c))
|
if (!isWhite(c))
|
||||||
{
|
{
|
||||||
r = r[i .. $];
|
r = r[i .. $];
|
||||||
return;
|
return;
|
||||||
|
@ -3105,7 +3098,7 @@ package void skipWS(R)(ref R r)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (; !r.empty && std.ascii.isWhite(r.front); r.popFront())
|
for (; !r.empty && isWhite(r.front); r.popFront())
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3365,6 +3358,7 @@ private dchar parseEscape(Source)(ref Source s)
|
||||||
|
|
||||||
dchar getHexDigit()(ref Source s_ = s) // workaround
|
dchar getHexDigit()(ref Source s_ = s) // workaround
|
||||||
{
|
{
|
||||||
|
import std.ascii : isAlpha, isHexDigit;
|
||||||
if (s_.empty)
|
if (s_.empty)
|
||||||
throw parseError("Unterminated escape sequence");
|
throw parseError("Unterminated escape sequence");
|
||||||
s_.popFront();
|
s_.popFront();
|
||||||
|
@ -3373,7 +3367,7 @@ private dchar parseEscape(Source)(ref Source s)
|
||||||
dchar c = s_.front;
|
dchar c = s_.front;
|
||||||
if (!isHexDigit(c))
|
if (!isHexDigit(c))
|
||||||
throw parseError("Hex digit is missing");
|
throw parseError("Hex digit is missing");
|
||||||
return std.ascii.isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0';
|
return isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
dchar result;
|
dchar result;
|
||||||
|
@ -3877,6 +3871,7 @@ private template emplaceImpl(T)
|
||||||
chunk = arg;
|
chunk = arg;
|
||||||
else static if (is(UArg == UT))
|
else static if (is(UArg == UT))
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
memcpy(&chunk, &arg, T.sizeof);
|
memcpy(&chunk, &arg, T.sizeof);
|
||||||
static if (hasElaborateCopyConstructor!T)
|
static if (hasElaborateCopyConstructor!T)
|
||||||
typeid(T).postblit(cast(void*)&chunk);
|
typeid(T).postblit(cast(void*)&chunk);
|
||||||
|
@ -3891,6 +3886,7 @@ private template emplaceImpl(T)
|
||||||
chunk[] = arg[];
|
chunk[] = arg[];
|
||||||
else static if (is(Unqual!(ElementEncodingType!Arg) == UE))
|
else static if (is(Unqual!(ElementEncodingType!Arg) == UE))
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
assert(N == chunk.length, "Array length missmatch in emplace");
|
assert(N == chunk.length, "Array length missmatch in emplace");
|
||||||
memcpy(cast(void*)&chunk, arg.ptr, T.sizeof);
|
memcpy(cast(void*)&chunk, arg.ptr, T.sizeof);
|
||||||
static if (hasElaborateCopyConstructor!T)
|
static if (hasElaborateCopyConstructor!T)
|
||||||
|
@ -3906,6 +3902,7 @@ private template emplaceImpl(T)
|
||||||
chunk[] = arg;
|
chunk[] = arg;
|
||||||
else static if (is(UArg == Unqual!E))
|
else static if (is(UArg == Unqual!E))
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
//Note: We copy everything, and then postblit just once.
|
//Note: We copy everything, and then postblit just once.
|
||||||
//This is as exception safe as what druntime can provide us.
|
//This is as exception safe as what druntime can provide us.
|
||||||
foreach(i; 0 .. N)
|
foreach(i; 0 .. N)
|
||||||
|
@ -3954,6 +3951,7 @@ private template emplaceImpl(T)
|
||||||
chunk = args[0];
|
chunk = args[0];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
memcpy(&chunk, &args[0], T.sizeof);
|
memcpy(&chunk, &args[0], T.sizeof);
|
||||||
static if (hasElaborateCopyConstructor!T)
|
static if (hasElaborateCopyConstructor!T)
|
||||||
typeid(T).postblit(&chunk);
|
typeid(T).postblit(&chunk);
|
||||||
|
@ -4011,6 +4009,7 @@ private ref T emplaceInitializer(T)(ref T chunk) @trusted pure nothrow
|
||||||
chunk = T.init;
|
chunk = T.init;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
static immutable T init = T.init;
|
static immutable T init = T.init;
|
||||||
memcpy(&chunk, &init, T.sizeof);
|
memcpy(&chunk, &init, T.sizeof);
|
||||||
}
|
}
|
||||||
|
@ -4703,6 +4702,7 @@ unittest
|
||||||
|
|
||||||
unittest //@@@9559@@@
|
unittest //@@@9559@@@
|
||||||
{
|
{
|
||||||
|
import std.typecons : Nullable;
|
||||||
alias I = Nullable!int;
|
alias I = Nullable!int;
|
||||||
auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))();
|
auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))();
|
||||||
auto asArray = std.array.array(ints);
|
auto asArray = std.array.array(ints);
|
||||||
|
@ -4887,6 +4887,7 @@ unittest
|
||||||
|
|
||||||
private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName)
|
private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName)
|
||||||
{
|
{
|
||||||
|
import std.string : format;
|
||||||
enforce!ConvException(chunk.length >= typeSize,
|
enforce!ConvException(chunk.length >= typeSize,
|
||||||
format("emplace: Chunk size too small: %s < %s size = %s",
|
format("emplace: Chunk size too small: %s < %s size = %s",
|
||||||
chunk.length, typeName, typeSize));
|
chunk.length, typeName, typeSize));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue