#include <future>
#include <vector>
#include <iostream>
#include <iomanip>
#include <windows.h>
using namespace std;

class StopWatch {
public:
    StopWatch();
    void start();
    void stop();
private:
    bool running;
    double f;
    long long start_time;
    long long total_time;
    long long getExecutionTime() const;
    void printError() const;
    friend ostream& operator<<(ostream& o, const StopWatch& sw);
};

StopWatch::StopWatch() : running(false), total_time(0) {
    LARGE_INTEGER performanceFrequency;
    if (QueryPerformanceFrequency(&performanceFrequency) == 0) {
        printError();
    }
    f = double(performanceFrequency.QuadPart);
}

void StopWatch::start() {
    if (!running) {
        running = true;
        start_time = getExecutionTime();
    }
}

void StopWatch::stop() {
    if (running) {
        running = false;
        total_time = getExecutionTime() - start_time;
    }
}

long long StopWatch::getExecutionTime() const {
    LARGE_INTEGER performanceCount;
    if (QueryPerformanceCounter(&performanceCount) == 0) {
        printError();
    }
    return performanceCount.QuadPart;
}

void StopWatch::printError() const {
    LPTSTR lpMsgBuf(0);
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        lpMsgBuf,
        0,
        NULL
        );
    cerr << lpMsgBuf << endl;
    LocalFree(lpMsgBuf);
}

ostream& operator<<(ostream& o, const StopWatch& sw) {
    long long res = sw.running ? sw.getExecutionTime() - sw.start_time : sw.total_time;
    return o << fixed << setprecision(2) << res / sw.f << " sec";
}

int som(const vector<int>& v) {
    int s = 0;
    for (auto e : v) {
        s += e;
    }
    return s;
}

#define ASYNC
// Choose launch policy
#define LAUNCH launch::async
//#define LAUNCH launch::deferred

int main() {
    vector<int> v1(10000000, 1);
    vector<int> v2( 5000000, 2);
    vector<int> v3( 5000000, 4);

    StopWatch sw;
    sw.start();

#ifdef ASYNC
    auto s1 = async(LAUNCH, &som, ref(v1));
    auto s2 = async(LAUNCH, &som, ref(v2));
    auto s3 = async(LAUNCH, &som, ref(v3));
    cout << "som = " << s1.get() + s2.get() + s3.get() << endl;
#else
    cout << "som = " << som(v1) + som(v2) + som(v3) << endl;
#endif

    sw.stop();
    cout << "Tijdsduur: " << sw << endl;

    cin.get();
    return 0;
}
