#include <iostream>
#include <chrono>
#include <unordered_map>
#include <algorithm>
#include <random>

using namespace std; 

int hextoint1 (char number)
{
	if (number == '0') 
		return 0;
	if (number == '1')
		return 1;
	if (number == '2') 
		return 2;
	if (number == '3')
		return 3;
	if (number == '4')
		return 4;
	if (number == '5')
		return 5;
	if (number == '6')
		return 6;
	if (number == '7')
		return 7;
	if (number == '8')
		return 8;
	if (number == '9') 
		return 9;
	if (number == 'a') 
		return 10;
	if (number == 'b') 
		return 11;
	if (number == 'c') 
		return 12;
	if (number == 'd') 
		return 13;
	if (number == 'e') 
		return 14;
	if (number == 'f') 
		return 15;
	return -1;
}

std::unordered_map<char, int> table{
	{ '0', 0 },{ '1', 1 },{ '2', 2 },
	{ '3', 3 },{ '4', 4 },{ '5', 5 },
	{ '6', 6 },{ '7', 7 },{ '8', 8 },
	{ '9', 9 },{ 'a', 10 },{ 'A', 10 },
	{ 'b', 11 },{ 'B', 11 },{ 'c', 12 },
	{ 'C', 12 },{ 'd', 13 },{ 'D', 13 },
	{ 'e', 14 },{ 'E', 14 },{ 'f', 15 },
	{ 'F', 15 },{ 'x', 0 },{ 'X', 0 } };

int hextoint2 (char number)
{
	return table[(std::size_t)number];
}


int hextoint4(char number)
{
	if (number >= '0' && number <= '9')
		return number - '0';
	else if (number >= 'a' && number <= 'f')
		return number - 'a' + 0x0a;
	else return -1;
}

struct Mytable {
	int x[128];
	Mytable() : x{}
	{
		fill(begin(x), end(x), -1); 
		for (int i = '0'; i <= '9'; i++)
			x[i] = i - '0';  
		for (int i = 'A'; i <= 'F'; i++)
			x[i] = x[i-'A'+'a'] = i - 'A'+0xa;
	}
};

int hextoint5(char number)
{
	static Mytable mytable;
	return  (number < 0 || number>128) ? -1 : mytable.x[number];
}

int hextoint6(char number)
{
	switch (number) {
	case '0': return 0;
	case '1': return 1;
	case '2': return 2;
	case '3': return 3;
	case '4': return 4;
	case '5': return 5;
	case '6': return 6;
	case '7': return 7;
	case '8': return 8;
	case '9': return 9;
	case 'A': case 'a': return 0xa;
	case 'B': case 'b': return 0xb;
	case 'C': case 'c': return 0xc;
	case 'D': case 'd': return 0xd;
	case 'E': case 'e': return 0xe;
	case 'F': case 'f': return 0xf;
	default: return - 1;
	}
}

const int variants = 5; 
const long long maxloop = 10000000; 
struct Bench {
	int(*f)(char); 
	char *s; 
} bench[variants] = {
	hextoint1, "If chain                ",
	hextoint2, "Map(no error processing)",
	hextoint4, "Compact if              ",
	hextoint5, "Table based             ",
	hextoint6, "Switch                  ",
};

int main()
{
	mt19937 generator;
	std::uniform_int_distribution<int> myrandom(0, 16); 
	const char *s = "0123456789abcdef";
	volatile int x;

	for (int i = 0; i < variants; i++) {
		cout << bench[i].s<<" "; 
		chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now(); 
		for (long long j = 0; j < maxloop; j++) {
			char c = s[myrandom(generator)];
			x = bench[i].f(c); 
		}
		chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now();
		long dt = chrono::duration_cast<chrono::milliseconds>(t2 - t1).count(); 
		cout << dt << " ms for " << maxloop << " iterations = " << dt * 1000000 / maxloop << " ns/it" << endl; 
	}
	cin.get(); 
}