// gx -O2 execpolicy.cc -ltbb

#include <mutex>
#include <algorithm>
#include <execution>
#include <iostream>
#include <unordered_set>

using namespace std;

struct ID
{
    unordered_set<thread::id> d_id;
    mutex d_mutex;
    void add(thread::id id)
    {
        lock_guard lg(d_mutex);
        d_id.insert(id);
    }
    size_t size()
    {
        size_t ret = d_id.size();
        d_id = unordered_set<thread::id>{};
        return ret;
    }
};

int main()
{
    ID ids;
    size_t nValues = 10'000;
    int *vect = new int[nValues];

    generate(vect, vect + nValues,                       // 1, ordered
//    generate(execution::par, vect, vect + nValues,
//    generate(execution::seq, vect, vect + nValues,         // 1, ordered
//  generate(execution::par_unseq, vect, vect + nValues,
//  generate(execution::unseq, vect, vect + nValues,         // 1, ordered
        [&, value = int(100)] () mutable
        {
            ids.add(this_thread::get_id());
            return value--;
        }
    );

    cout << "# threads: " << ids.size() << '\n';

    sort(execution::par, vect, vect + nValues,
        [&](int lhs, int rhs)
        {
            ids.add(this_thread::get_id());
            return lhs < rhs;
        }
    );

    cout << "# threads: " << ids.size() << '\n';

    for (size_t idx = 0; idx < 10; ++idx)
        cout << vect[idx] << ' ';
    cout << '\n';

    for (size_t idx = nValues - 10; idx != nValues; ++idx)
        cout << vect[idx] << ' ';
    cout << '\n';

    int check = vect[0];
    for (size_t idx = 0; idx < nValues; ++idx)
    {
        if (vect[idx] != check)
        {
            cout << "unordered\n";
            return 0;
        }
        ++check;
    }
}

// E.g., using execution::par:  # threads: 4
//       using execution::par:  # threads: 4
