#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>

using namespace std;
using namespace boost;
using namespace boost::chrono;
namespace qi = boost::spirit::qi;

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)
            if (strtol(valueStr.c_str(), NULL, 10) != (long) value)
                return false;
        stop = test_clock::now();
        cout << "strtol: " << 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)
            if (!AlmostEqual2sComplement(strtod(valueStr.c_str(), NULL), value, 1))
                return false;
        stop = test_clock::now();
        cout << "strtod: " << 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;
}
