#include <atomic>
#include <iostream>
#include <thread>
#include <stdint.h>

using namespace std;

void run_in_pool(std::function<void() > routine, uint8_t max_thread = 4) {
    std::thread modifiers[max_thread];
    uint8_t i;

    for (i = 0; i < max_thread; i++) {
        modifiers[i] = std::thread(routine);
    }

    for (i = 0; i < max_thread; i++) {
        modifiers[i].join();
    }

}

struct List {
    uint32_t capacity;

    static List* create_ptr(uint32_t capacity) {
        uint32_t* buffer = new uint32_t[List::guess_size(capacity)];
        List* raw_ptr = (List*) buffer;
        raw_ptr->capacity = capacity;
        return raw_ptr;
    }

    uint32_t* get_data() {
        return (uint32_t*) (this +sizeof (List));
    }

    uint32_t get_size() {
        return this->capacity + sizeof (List);
    }

    static uint32_t guess_size(uint32_t capacity) {
        return capacity + sizeof (List);
    }

    void release() {
        delete[] this;
    }

    atomic<uint32_t>& get(uint32_t index) throw (invalid_argument) {
        if (index >= this->capacity) {
            throw invalid_argument("Invalid index");
        }
        atomic<uint32_t>* data_ptr = (atomic<uint32_t>*)this->get_data();
        return data_ptr[index];
    }

};

int main() {
    List* list_ptr = List::create_ptr(3);

    const uint32_t loop = 50, threads = 5;
    auto routine = [&]() {
        atomic<uint32_t>& ref = list_ptr->get(0);
        uint32_t expected, desired;
        bool exchanged;
        for (uint32_t i = 0; i < loop; i++) {
            do {
                expected = ref;
                desired = expected + 1;
            } while (!ref.compare_exchange_strong(expected, desired));
        }
    };
    run_in_pool(routine, threads);

    cout << "Value is: " << unsigned(list_ptr->get(0)) << " = " << loop * threads << endl;

    return 0;
}