#define _SECURE_SCL 0
#define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
#include <iostream>
#include <sstream>
#include <string>
#include <boost/range/iterator_range.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/chrono.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <cmath>
#include <cstdlib>
using namespace std;
using namespace boost;
using namespace boost::chrono;
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
int parse_int(const string& valueStr)
{
int result;
qi::parse(valueStr.begin(), valueStr.end(), qi::int_, result);
return result;
}
double parse_double(const string& valueStr)
{
double result;
qi::parse(valueStr.begin(), valueStr.end(), qi::double_, result);
return result;
}
template <typename T> T tabs(T x) {return x < 0 ? -x : x;}
bool AlmostEqual2sComplement(double A, double B, int maxUlps)
{
// Make sure maxUlps is non-negative and small enough that the
// default NAN won't compare as equal to anything.
assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
int64_t aInt = *(int64_t*)&A;
// Make aInt lexicographically ordered as a twos-complement int
if (aInt < 0)
aInt = 0x8000000000000000 - aInt;
// Make bInt lexicographically ordered as a twos-complement int
int64_t bInt = *(int64_t*)&B;
if (bInt < 0)
bInt = 0x8000000000000000 - bInt;
int64_t intDiff = tabs(aInt - bInt);
if (intDiff <= maxUlps)
return true;
return false;
}
template<typename T>
bool test(T value, const std::string& valueStr)
{
typedef steady_clock test_clock;
test_clock::time_point start, stop;
const int iterations = 1000000;
cout << endl << iterations << " iterations of \"" << valueStr << "\":" << endl;
bool isInteger = (double) atoi(valueStr.c_str()) == (double) value;
if (isInteger)
{
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (atoi(valueStr.c_str()) != value)
return false;
stop = test_clock::now();
cout << "atoi: " << duration<double>(stop - start) << endl;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
{
const char* stringToConvert = valueStr.c_str();
const char* endOfConversion = stringToConvert;
long value2 = strtol(stringToConvert, const_cast<char**>(&endOfConversion), 10);
if (value2 == 0.0 && stringToConvert == endOfConversion) // error: conversion could not be performed
throw bad_lexical_cast();
if (value2 != (long) value)
return false;
}
stop = test_clock::now();
cout << "strtol: " << duration<double>(stop - start) << endl;
long scanValue;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
{
sscanf(valueStr.c_str(), "%ld", &scanValue);
if (scanValue != value)
return false;
}
stop = test_clock::now();
cout << "sscanf: " << duration<double>(stop - start) << endl;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (parse_int(valueStr) != value)
return false;
stop = test_clock::now();
cout << "Spirit: " << duration<double>(stop - start) << endl;
}
else
{
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (!AlmostEqual2sComplement(atof(valueStr.c_str()), value, 1))
return false;
stop = test_clock::now();
cout << "atof: " << duration<double>(stop - start) << endl;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
{
const char* stringToConvert = valueStr.c_str();
const char* endOfConversion = stringToConvert;
double value2 = strtod( stringToConvert, const_cast<char**>(&endOfConversion) );
if (value2 == 0.0 && stringToConvert == endOfConversion) // error: conversion could not be performed
throw bad_lexical_cast();
if (!AlmostEqual2sComplement(value2, value, 1))
return false;
}
stop = test_clock::now();
cout << "strtod: " << duration<double>(stop - start) << endl;
double scanValue;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
{
sscanf(valueStr.c_str(), "%lf", &scanValue);
if (!AlmostEqual2sComplement(scanValue, value, 1))
return false;
}
stop = test_clock::now();
cout << "sscanf: " << duration<double>(stop - start) << endl;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (!AlmostEqual2sComplement(parse_double(valueStr), value, 1))
return false;
stop = test_clock::now();
cout << "Spirit: " << duration<double>(stop - start) << endl;
}
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (lexical_cast<T>(valueStr) != value)
return false;
stop = test_clock::now();
cout << "lexical_cast(string): " << duration<double>(stop - start) << endl;
iterator_range<string::const_iterator> valueRng = make_iterator_range(valueStr.begin(), valueStr.end());
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (lexical_cast<T>(valueRng) != value)
return false;
stop = test_clock::now();
cout << "lexical_cast(iterator_range): " << duration<double>(stop - start) << endl;
start = test_clock::now();
for (int i=0; i < iterations; ++i)
if (lexical_cast<T>(string(valueRng.begin(), valueRng.end())) != value)
return false;
stop = test_clock::now();
cout << "lexical_cast(iterator_range->string): " << duration<double>(stop - start) << endl;
return true;
}
int main()
{
test(123, "123");
test(123567890, "123567890");
test(1.23456, "1.23456");
test(1.23456789e42, "1.23456789e42");
return 0;
}