Created
January 4, 2017 18:57
-
-
Save JackStouffer/42aae01b9cd4c86ae42086642270b407 to your computer and use it in GitHub Desktop.
auto decoding test for std.conv.parse!int
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.stdio; | |
import std.range; | |
import std.algorithm; | |
import std.traits; | |
import std.container; | |
import std.meta; | |
import std.conv; | |
import std.datetime; | |
Target parse1(Target, Source)(ref Source s) | |
if (isSomeChar!(ElementType!Source) && | |
isIntegral!Target && !is(Target == enum)) | |
{ | |
static if (Target.sizeof < int.sizeof) | |
{ | |
// smaller types are handled like integers | |
auto v = .parse!(Select!(Target.min < 0, int, uint))(s); | |
auto result = ()@trusted{ return cast(Target) v; }(); | |
if (result == v) | |
return result; | |
throw new ConvOverflowException("Overflow in integral conversion"); | |
} | |
else | |
{ | |
// int or larger types | |
static if (Target.min < 0) | |
bool sign = 0; | |
else | |
enum bool sign = 0; | |
enum char maxLastDigit = Target.min < 0 ? 7 : 5; | |
uint c; | |
if (s.empty) | |
goto Lerr; | |
static if (isAutodecodableString!Source) | |
c = s[0]; | |
else | |
c = s.front; | |
static if (Target.min < 0) | |
{ | |
switch (c) | |
{ | |
case '-': | |
sign = true; | |
goto case '+'; | |
case '+': | |
static if (isAutodecodableString!Source) | |
s = s[1 .. $]; | |
else | |
s.popFront(); | |
if (s.empty) | |
goto Lerr; | |
static if (isAutodecodableString!Source) | |
c = s[0]; | |
else | |
c = s.front; | |
break; | |
default: | |
break; | |
} | |
} | |
c -= '0'; | |
if (c <= 9) | |
{ | |
Target v = cast(Target)c; | |
static if (isAutodecodableString!Source) | |
s = s[1 .. $]; | |
else | |
s.popFront(); | |
while (!s.empty) | |
{ | |
static if (isAutodecodableString!Source) | |
c = cast(typeof(c)) (s[0] - '0'); | |
else | |
c = cast(typeof(c)) (s.front - '0'); | |
if (c > 9) | |
break; | |
if (v >= 0 && (v < Target.max/10 || | |
(v == Target.max/10 && c <= maxLastDigit + sign))) | |
{ | |
// Note: `v` can become negative here in case of parsing | |
// the most negative value: | |
v = cast(Target) (v * 10 + c); | |
static if (isAutodecodableString!Source) | |
s = s[1 .. $]; | |
else | |
s.popFront(); | |
} | |
else | |
throw new ConvOverflowException("Overflow in integral conversion"); | |
} | |
if (sign) | |
v = -v; | |
return v; | |
} | |
Lerr: | |
throw new Exception(cast(string) s); | |
} | |
} | |
Target parse2(Target, Source)(ref Source s) | |
if (isSomeChar!(ElementType!Source) && | |
isIntegral!Target && !is(Target == enum)) | |
{ | |
static if (Target.sizeof < int.sizeof) | |
{ | |
// smaller types are handled like integers | |
auto v = .parse!(Select!(Target.min < 0, int, uint))(s); | |
auto result = ()@trusted{ return cast(Target) v; }(); | |
if (result == v) | |
return result; | |
throw new ConvOverflowException("Overflow in integral conversion"); | |
} | |
else | |
{ | |
// int or larger types | |
static if (Target.min < 0) | |
bool sign = 0; | |
else | |
enum bool sign = 0; | |
enum char maxLastDigit = Target.min < 0 ? 7 : 5; | |
uint c; | |
static if (isNarrowString!Source) | |
{ | |
import std.string : representation, assumeUTF; | |
auto source = s.representation; | |
} | |
else | |
{ | |
alias source = s; | |
} | |
if (source.empty) | |
goto Lerr; | |
c = source.front; | |
static if (Target.min < 0) | |
{ | |
switch (c) | |
{ | |
case '-': | |
sign = true; | |
goto case '+'; | |
case '+': | |
source.popFront(); | |
if (source.empty) | |
goto Lerr; | |
c = source.front; | |
break; | |
default: | |
break; | |
} | |
} | |
c -= '0'; | |
if (c <= 9) | |
{ | |
Target v = cast(Target)c; | |
source.popFront(); | |
while (!source.empty) | |
{ | |
c = cast(typeof(c)) (source.front - '0'); | |
if (c > 9) | |
break; | |
if (v >= 0 && (v < Target.max/10 || | |
(v == Target.max/10 && c <= maxLastDigit + sign))) | |
{ | |
// Note: `v` can become negative here in case of parsing | |
// the most negative value: | |
v = cast(Target) (v * 10 + c); | |
source.popFront(); | |
} | |
else | |
throw new ConvOverflowException("Overflow in integral conversion"); | |
} | |
if (sign) | |
v = -v; | |
static if (isNarrowString!Source) | |
s = source.assumeUTF; | |
return v; | |
} | |
Lerr: | |
static if (isNarrowString!Source) | |
throw new Exception(source.assumeUTF); | |
else | |
throw new Exception(source); | |
} | |
} | |
Target parse3(Target, Source)(ref Source s) | |
if (isSomeChar!(ElementType!Source) && | |
isIntegral!Target && !is(Target == enum)) | |
{ | |
static if (Target.sizeof < int.sizeof) | |
{ | |
// smaller types are handled like integers | |
auto v = .parse!(Select!(Target.min < 0, int, uint))(s); | |
auto result = ()@trusted{ return cast(Target) v; }(); | |
if (result == v) | |
return result; | |
throw new ConvOverflowException("Overflow in integral conversion"); | |
} | |
else | |
{ | |
// int or larger types | |
static if (Target.min < 0) | |
bool sign = 0; | |
else | |
enum bool sign = 0; | |
enum char maxLastDigit = Target.min < 0 ? 7 : 5; | |
uint c; | |
if (s.empty) | |
goto Lerr; | |
c = s.front; | |
static if (Target.min < 0) | |
{ | |
switch (c) | |
{ | |
case '-': | |
sign = true; | |
goto case '+'; | |
case '+': | |
s.popFront(); | |
if (s.empty) | |
goto Lerr; | |
c = s.front; | |
break; | |
default: | |
break; | |
} | |
} | |
c -= '0'; | |
if (c <= 9) | |
{ | |
Target v = cast(Target)c; | |
s.popFront(); | |
while (!s.empty) | |
{ | |
c = cast(typeof(c)) (s.front - '0'); | |
if (c > 9) | |
break; | |
if (v >= 0 && (v < Target.max/10 || | |
(v == Target.max/10 && c <= maxLastDigit + sign))) | |
{ | |
// Note: `v` can become negative here in case of parsing | |
// the most negative value: | |
v = cast(Target) (v * 10 + c); | |
s.popFront(); | |
} | |
else | |
throw new ConvOverflowException("Overflow in integral conversion"); | |
} | |
if (sign) | |
v = -v; | |
return v; | |
} | |
Lerr: | |
throw new Exception(cast(string) s); | |
} | |
} | |
__gshared char[] test = ['1', '2', '3', '4', '5', '6', '7', '8', '9']; | |
void main() | |
{ | |
enum n = 50_000_000; | |
int result; | |
StopWatch sw; | |
Duration sum; | |
TickDuration last = TickDuration.from!"seconds"(0); | |
foreach(i; 0 .. n) | |
{ | |
sw.start(); | |
// Current | |
//result = parse1!int(test); | |
// New | |
result = parse2!int(test); | |
// Old | |
//result = parse3!int(test); | |
sw.stop(); | |
test = ['1', '2', '3', '4', '5', '6', '7', '8', '9']; | |
auto time = sw.peek() - last; | |
last = sw.peek(); | |
sum += time.to!Duration(); | |
} | |
writeln("Total time: ", sum); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment