conv: Fix overflow hanndling in readIntegral

This commit is contained in:
Eugen Wissner 2018-07-17 16:03:05 +02:00
parent 99e06e0d04
commit 1b203507f6

View File

@ -282,8 +282,8 @@ final class ConvException : Exception
* *
* The function doesn't handle the sign (+ or -) or number prefixes (like 0x). * The function doesn't handle the sign (+ or -) or number prefixes (like 0x).
*/ */
package T readIntegral(T, R)(ref R range, ubyte base = 10) package T readIntegral(T, R)(ref R range, const ubyte base = 10)
if (isForwardRange!R if (isInputRange!R
&& isSomeChar!(ElementType!R) && isSomeChar!(ElementType!R)
&& isIntegral!T && isIntegral!T
&& isUnsigned!T) && isUnsigned!T)
@ -301,9 +301,9 @@ do
} }
T n; T n;
while (n <= boundary)
{
int digit; int digit;
do
{
if (range.front >= 'a') if (range.front >= 'a')
{ {
digit = range.front - 'W'; digit = range.front - 'W';
@ -332,17 +332,30 @@ do
return n; return n;
} }
} }
if (range.length > 1) while (n < boundary);
if (range.front >= 'a')
{
digit = range.front - 'W';
}
else if (range.front >= 'A')
{
digit = range.front - '7';
}
else if (range.front >= '0')
{
digit = range.front - '0';
}
else
{ {
return n; return n;
} }
int digit = range.front - '0';
if (n > cast(T) ((T.max - digit) / base)) if (n > cast(T) ((T.max - digit) / base))
{ {
return n; return n;
} }
n = cast(T) (n * base + digit); n = cast(T) (n * base + digit);
range.popFront();
return n; return n;
} }
@ -410,6 +423,14 @@ do
assert(number.empty); assert(number.empty);
} }
// Handles small overflows
@nogc nothrow pure @safe unittest
{
string number = "256";
assert(readIntegral!ubyte(number, 10) == 25);
assert(number.front == '6');
}
/** /**
* If the source type $(D_PARAM From) and the target type $(D_PARAM To) are * If the source type $(D_PARAM From) and the target type $(D_PARAM To) are
* equal, does nothing. If $(D_PARAM From) can be implicitly converted to * equal, does nothing. If $(D_PARAM From) can be implicitly converted to