Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 76726e1655e204c8663ef81235fd26e931475d42 Fuji Goro committed Sep 2, 2011
Showing with 249 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +5 −0 Makefile
  3. +145 −0 fast_strtox.h
  4. +93 −0 test.cpp
@@ -0,0 +1,6 @@
+*~
+*.out
+*.dSYM
+*.swp
+test
+
@@ -0,0 +1,5 @@
+
+test: fast_strtox.h test.cpp
+ g++ -O3 test.cpp -o test
+ ./test
+
@@ -0,0 +1,145 @@
+// a faster replacement of strtof(3), strtod(3) and simple version of
+// strtol(3)
+//
+// strtof() and strtod() are originated from a Perl module JSON::XS's
+// implementation
+// Copyright (c) Marc Lehmann <schmorp@schmorp.de>, http://home.schmorp.de/
+// The COPYING says "This module is licensed under the same terms as perl itself."
+//
+
+#pragma once
+#include <cmath> // for std::pow()
+#include <climits> // for ULONG_MAX
+#include <cassert>
+
+#define strtof fast_strtof
+#define strtod fast_strtod
+#define strtol fast_strtol
+
+namespace {
+ typedef unsigned char uchar_t;
+ using std::pow;
+
+ const char* fast_strtod_scan1(const char* s,
+ double* const accum, int* const expo, int const postdp, int maxdepth)
+ {
+ unsigned long uaccum = 0;
+ int eaccum = 0;
+
+ // if we recurse too deep, skip all remaining digits
+ // to avoid a stack overflow attack
+ if (--maxdepth <= 0) {
+ while (((uchar_t)*s - (uchar_t)'0') < 10) {
+ ++s;
+ }
+ }
+
+ for (;;) {
+ uchar_t dig = (uchar_t)*s - (uchar_t)'0';
+
+ if (dig >= 10) {
+ if (dig == (uchar_t)((uchar_t)'.' - (uchar_t)'0')) {
+ ++s;
+ s = fast_strtod_scan1(s, accum, expo, 1, maxdepth);
+ }
+ else if ((dig | ' ') == 'e' - '0') {
+ int exp2 = 0;
+ bool neg = false;
+
+ ++s;
+
+ if (*s == '-') {
+ ++s;
+ neg = true;
+ }
+ else if (*s == '+') {
+ ++s;
+ }
+
+ while ((dig = (uchar_t)*s - (uchar_t)'0') < 10) {
+ exp2 = exp2 * 10 + *s++ - '0';
+ }
+
+ *expo += neg ? -exp2 : exp2;
+ }
+
+ break;
+ }
+
+ ++s;
+
+ uaccum = uaccum * 10 + dig;
+ ++eaccum;
+
+ // if we have too many digits, then recurse for more
+ // we actually do this for rather few digits
+ if (uaccum >= (ULONG_MAX - 9) / 10) {
+ if (postdp) *expo -= eaccum;
+ s = fast_strtod_scan1(s, accum, expo, postdp, maxdepth);
+ if (postdp) *expo += eaccum;
+
+ break;
+ }
+ }
+
+ // this relies greatly on the quality of the pow ()
+ // implementation of the platform, but a good
+ // implementation is hard to beat.
+ // (IEEE 754 conformant ones are required to be exact)
+ if (postdp) *expo -= eaccum;
+ *accum += uaccum * pow(10.0, *expo);
+ *expo += eaccum;
+ return s;
+ }
+
+ template <typename Float>
+ Float fast_str_to_float(const char* nptr, const char** endptr) {
+ double accum = 0.0;
+ int expo = 0;
+ bool neg = false;
+
+ if(*nptr == '-') {
+ ++nptr;
+ neg = true;
+ }
+ nptr = fast_strtod_scan1(nptr, &accum, &expo, 0, 10);
+ if(endptr) {
+ *endptr = nptr;
+ }
+ return static_cast<Float>( neg ? -accum : accum );
+ }
+
+ inline float fast_strtof(const char* nptr, char** endptr) {
+ return fast_str_to_float<float>(nptr, (const char**)endptr);
+ }
+ inline double fast_strtod(const char* nptr, char** endptr) {
+ return fast_str_to_float<double>(nptr, (const char**)endptr);
+ }
+
+
+ static inline
+ long fast_strtol(const char* s, char** endp, int const base) {
+ assert(base == 10); // only support base=10
+
+ bool neg = false;
+ if(*s == '-') {
+ ++s;
+ neg = true;
+ }
+
+ long result = 0;
+
+ while(true) {
+ if((uchar_t)*s > (uchar_t)'9' || (uchar_t)*s < (uchar_t)'0') {
+ break;
+ }
+ result = result * 10 + (uchar_t)*s - (uchar_t)'0';
+ ++s;
+ }
+ *endp = (char*)s;
+
+ return neg ? -result : result;
+ }
+
+} // end namespace
+
@@ -0,0 +1,93 @@
+#include <iostream>
@mattn

mattn Sep 2, 2011

#include <cstdlib>
+#include "fast_strtox.h"
+
+#undef strtof
+#undef strtod
+#undef strtol
+
+int main() {
+ int i = 0;
+
+ std::cout << "# strtof()" << std::endl;
+ {
+ const char* const str = "3.14159265358979323846264338327950288,foo";
+ char* e = NULL;
+ char* d = NULL;
+
+ float f = std::strtof(str, &e);
+ float g = fast_strtof(str, &d);
+
+ if(f == g) {
+ std::cout << "ok " << ++i << "\n";
+ }
+ else {
+ std::cout << "not ok " << ++i << "\n";
+ std::cout << "got: " << g << std::endl;
+ std::cout << "expected: " << f << std::endl;
+ }
+ if(e == d) {
+ std::cout << "ok " << ++i << "\n";
+ }
+ else {
+ std::cout << "not ok " << ++i << "\n";
+ std::cout << "got: " << (str - d) << std::endl;
+ std::cout << "expected: " << (str - e) << std::endl;
+ }
+ }
+
+ std::cout << "# strtod()" << std::endl;
+ {
+ const char* const str = "3.14159265358979323846264338327950288,foo";
+ char* e = NULL;
+ char* d = NULL;
+
+ float f = std::strtof(str, &e);
+ float g = fast_strtof(str, &d);
+
+ if(f == g) {
+ std::cout << "ok " << ++i << "\n";
+ }
+ else {
+ std::cout << "not ok " << ++i << "\n";
+ std::cout << "got: " << g << std::endl;
+ std::cout << "expected: " << f << std::endl;
+ }
+ if(e == d) {
+ std::cout << "ok " << ++i << "\n";
+ }
+ else {
+ std::cout << "not ok " << ++i << "\n";
+ std::cout << "got: " << (str - d) << std::endl;
+ std::cout << "expected: " << (str - e) << std::endl;
+ }
+ }
+
+ std::cout << "# strtol()" << std::endl;
+ {
+ const char* const str = "3.14159265358979323846264338327950288,foo";
+ char* e = NULL;
+ char* d = NULL;
+
+ float f = std::strtol(str, &e, 10);
+ float g = fast_strtol(str, &d, 10);
+
+ if(f == g) {
+ std::cout << "ok " << ++i << "\n";
+ }
+ else {
+ std::cout << "not ok " << ++i << "\n";
+ std::cout << "got: " << g << std::endl;
+ std::cout << "expected: " << f << std::endl;
+ }
+ if(e == d) {
+ std::cout << "ok " << ++i << "\n";
+ }
+ else {
+ std::cout << "not ok " << ++i << "\n";
+ std::cout << "got: " << (str - d) << std::endl;
+ std::cout << "expected: " << (str - e) << std::endl;
+ }
+ }
+ return 0;
+}
+

0 comments on commit 76726e1

Please sign in to comment.