//
//  main.cpp
//  Memoizator
//
//
#include <iostream>
#include <map>
#include <tuple>
#define MEMOIZATOR(N, R, ...)                               \
R _ ## N (__VA_ARGS__);                                     \
std::map<std::tuple<__VA_ARGS__>, R> _memo_ ## N;           \
template <typename ... Args>                                \
R N (Args ... args) {                                       \
    auto& _memo = _memo_ ## N;                              \
    auto result = _memo.find(std::make_tuple(args...));     \
    if (result != _memo.end()) {                            \
        return result->second;                              \
    }                                                       \
    else {                                                  \
        auto result = _ ## N  (args...);                    \
        _memo[std::make_tuple(args...)] = result;           \
        return result;                                      \
    }                                                       \
}    
MEMOIZATOR(fibonacci, long int, int);

int function_count = 0;

long int _fibonacci(int n) {
	function_count++;
    if (n == 1 or n == 2) {
        return 1;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

using namespace std;
int main(int argc, const char * argv[]) {
    // insert code here...
    cout << "Result: " << fibonacci(40) << endl;
    cout << "Fibonacci executed " << function_count << " times." <<endl;
    return 0;
}

