#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
#include <array>
#define onlyAtEnd(a) typename std::enable_if<sizeof...(a) == 0 > ::type
template<int a, int b>
class Entry
{
public:
static constexpr int VAL = a;
static constexpr int PROB = b;
};
template<typename... EntryTypes>
class NumChooser
{
private:
const int SUM;
static constexpr int NUM_VALS = sizeof...(EntryTypes);
public:
static constexpr int size()
{
return NUM_VALS;
}
template<typename T, typename... args>
constexpr int calcSum()
{
return T::PROB + calcSum < args...>();
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int calcSum()
{
return 0;
}
NumChooser() : SUM(calcSum < EntryTypes... >()) { }
template<typename T, typename... args>
constexpr int find(int left, int previous = 0)
{
return left < 0 ? previous : find < args... >(left - T::PROB, T::VAL);
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int find(int left, int previous)
{
return previous;
}
constexpr int choose()
{
return find < EntryTypes... >(1 + (rand() % SUM));
}
};
NumChooser <
Entry<0, 10>,
Entry<1, 50>,
Entry<2, 80>,
Entry<3, 01>
> chooser;
// Warning! The test code below is very hackish and not well crafted!
int main()
{
srand(time(nullptr));
std::array<int, chooser.size() > frequency{};
const int NUM_AV = 50000; // How many trials to average
const int NUM_TRIALS = 1000;
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed;
double templateTime = 0;
for (int av = 0; av < NUM_AV; ++av)
{
start = std::chrono::system_clock::now();
for (int i = 0; i < NUM_TRIALS; ++i)
frequency[chooser.choose()]++;
end = std::chrono::system_clock::now();
elapsed = end-start;
double time = elapsed.count();
templateTime = (av*templateTime + time) / (av + 1);
if ((NUM_AV/100) < 1 || av % (NUM_AV/100)==0)
std::cout << 100.0*av / (NUM_AV - 1) << "%" << std::endl;
}
const int SUM = 141;
const int VALS[] = {0,1,2,3};
const int PROB[] = {10,50,80,01};
double basicTime = 0;
int id, val;
for (int av = 0; av < NUM_AV; ++av)
{
start = std::chrono::system_clock::now();
for (int i = 0; i < NUM_TRIALS; ++i)
{
val = 1 + rand()%SUM;
id = -1;
do
{
++id;
val -= PROB[id];
}
while(val>0);
frequency[VALS[id]]++;
}
end = std::chrono::system_clock::now();
elapsed = end-start;
double t = elapsed.count();
basicTime = (av * basicTime + t) / (av + 1);
if ((NUM_AV/100) < 1 || av % (NUM_AV/100)==0)
std::cout << 100.0*av / (NUM_AV - 1) << "%" << std::endl;
}
std::cout << "Template based implementation:" << std::endl;
std::cout << templateTime << std::endl;
std::cout << "Basic implementation:" << std::endl;
std::cout << basicTime << std::endl;
double change = 100.0*(templateTime - basicTime) / basicTime;
std::cout << "Template % change:" << std::endl;
std::cout << change << std::endl;
}