#include <string>
#include <cstdlib>
#include <chrono>
#include <algorithm>
#include <cassert>
#include <climits>
#include <iostream>

void append_Ethon(std::string& s, int value, int radix=10)
{
    if(value < 0)
    {
        s.push_back('-');
        value = -value;
    }
   
    assert(radix > 1 && radix < 17);
    char const* chars = "0123456789abcdef";
   
    char buffer[sizeof(int) * CHAR_BIT];
    char* iter = buffer;
    while(value >= radix)
    {
        *iter = chars[value % radix];
        value /= radix;
        ++iter;
    }
    *iter = chars[value];
   
    s.append(std::reverse_iterator<char*>(iter + 1), std::reverse_iterator<char*>(buffer));
}

void append_Ethon2(std::string& s, int value, int radix=10)
{
    if(value < 0)
    {
        s.push_back('-');
        value = -value;
    }
   
    assert(radix > 1 && radix < 11);
   
    char buffer[sizeof(int) * CHAR_BIT];
    char* iter = buffer;
    while(value >= radix)
    {
        *iter = '0' + value % radix;
        value /= radix;
        ++iter;
    }
    *iter = '0' + value % radix;
   
    s.append(std::reverse_iterator<char*>(iter + 1), std::reverse_iterator<char*>(buffer));
}

void append_Ethon3(std::string& s, int value)
{
    if(value < 0)
    {
        s.push_back('-');
        value = -value;
    }
   
    char const* chars =
        "00010203040506070809"
        "10111213141516171819"
        "20212223242526272829"
        "30313233343536373839"
        "40414243444546474849"
        "50515253545556575859"
        "60616263646566676869"
        "70717273747576777879"
        "80818283848586878889"
        "90919293949596979899"
      ;
   
    char buffer[64];
    char* iter = buffer;
    while(value >= 100)
    {
        *iter = chars[value % 100 * 2 + 1];
        ++iter;
        *iter = chars[value % 100 * 2];
        value /= 100;
        ++iter;
    }
    if(value >= 10)
    {
        *iter = chars[value * 2];
        ++iter;
        *iter = chars[value * 2 + 1];
        ++iter;
    }
    else
    {
        *iter = '0' + value;
    }
   
    s.append(std::reverse_iterator<char*>(iter + 1), std::reverse_iterator<char*>(buffer));
}

void append_Ethon4(std::string& s, int value)
{
    if(value < 0)
    {
        s.push_back('-');
        value = -value;
    }
   
    char const* chars =
        "00010203040506070809"
        "10111213141516171819"
        "20212223242526272829"
        "30313233343536373839"
        "40414243444546474849"
        "50515253545556575859"
        "60616263646566676869"
        "70717273747576777879"
        "80818283848586878889"
        "90919293949596979899"
      ;
      
    unsigned size;
    if(value >=10000)
    {
        if(value >=10000000)
        {
            if(value >=1000000000)
                size=10;
            else if(value >=100000000)
                size=9;
            else 
                size=8;
        }
        else
        {
            if(value >=1000000)
                size=7;
            else if(value >=100000)
                size=6;
            else
                size=5;
        }
    }
    else 
    {
        if(value >=100)
        {
            if(value >=1000)
                size=4;
            else
                size=3;
        }
        else
        {
            if(value >=10)
                size=2;
            else
                size=1;
        }
    }
   
    s.resize(s.size() + size);
    std::reverse_iterator<std::string::iterator> iter( (s.end()) );
    while(value >= 100)
    {
        *iter = chars[value % 100 * 2 + 1];
        ++iter;
        *iter = chars[value % 100 * 2];
        value /= 100;
        ++iter;
    }
    if(value >= 10)
    {
        *iter = chars[value * 2];
        ++iter;
        *iter = chars[value * 2 + 1];
        ++iter;
    }
    else
    {
        *iter = '0' + value;
    }
}

void append_snprintf(std::string& s, int value)
{
    char buffer[64];
    snprintf(buffer, 64, "%d", value);
    s.append(buffer);
}

void append_tostring(std::string& s, int value)
{
    s.append(std::to_string(value));
}

void append_stackoverflow1(std::string& s, int n)
{
    const char digit_pairs[201] = {
      "00010203040506070809"
      "10111213141516171819"
      "20212223242526272829"
      "30313233343536373839"
      "40414243444546474849"
      "50515253545556575859"
      "60616263646566676869"
      "70717273747576777879"
      "80818283848586878889"
      "90919293949596979899"
    };

    if(n==0)
    {
        s += "0";
        return;
    }

    int sign = -(n<0);
    unsigned int val = (n^sign)-sign;

    int size;
    if(val>=10000)
    {
        if(val>=10000000)
        {
            if(val>=1000000000)
                size=10;
            else if(val>=100000000)
                size=9;
            else 
                size=8;
        }
        else
        {
            if(val>=1000000)
                size=7;
            else if(val>=100000)
                size=6;
            else
                size=5;
        }
    }
    else 
    {
        if(val>=100)
        {
            if(val>=1000)
                size=4;
            else
                size=3;
        }
        else
        {
            if(val>=10)
                size=2;
            else
                size=1;
        }
    }
    size -= sign;
    auto oldSize = s.size();
    s.resize(oldSize + size);
    char* c = &s[oldSize];
    if(sign)
        *c='-';

    c += size-1;
    while(val>=100)
    {
       int pos = val % 100;
       val /= 100;
       *(short*)(c-1)=*(short*)(digit_pairs+2*pos); 
       c-=2;
    }
    while(val>0)
    {
        *c--='0' + (val % 10);
        val /= 10;
    }
}

unsigned const N = 10000000;

int main()
{
    using namespace std;
    srand(time(0));
    
    vector<int> values( (N) );
    generate(values.begin(), values.end(), rand);
    
    // Warmup.
    {
        string s;
        
        for(unsigned i = 0; i < N; ++i)
            append_Ethon(s, values[i]);
            
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_Ethon(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "Ethon (Lookuptable): " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_Ethon2(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "Ethon (No Lookuptable): " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_Ethon3(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "Ethon (Larger Lookuptable): " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_Ethon4(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "Ethon (Larger Lookuptable, no Buffer): " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_tostring(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "std::to_string: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_snprintf(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "snprintf: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
    
    {
        string s;
        
        auto start = chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < N; ++i)
            append_stackoverflow1(s, values[i]);
        auto end = chrono::high_resolution_clock::now();
            
        cout << "stackoverflow1: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n";
        cout << "Anti Optimize: " << s.back() << endl;
    }
}
