Skip to content

Instantly share code, notes, and snippets.

@JackStouffer
Created January 4, 2017 18:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JackStouffer/42aae01b9cd4c86ae42086642270b407 to your computer and use it in GitHub Desktop.
Save JackStouffer/42aae01b9cd4c86ae42086642270b407 to your computer and use it in GitHub Desktop.
auto decoding test for std.conv.parse!int
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