#ifndef OBJECTPOOL_H
#define OBJECTPOOL_H

#include "utils/UninitializedArray.h"

template<typename T, int N>
class ObjectPool {
    int freeIndex;

    union Node {
        int next;
        T t;

        template<typename... Args>
        Node(Args&&... args) : t(std::forward<Args>(args)...) {
        }

        ~Node() {
            t.~T();
        }
    };

    UninitializedArray<Node, N> data;

public:
    ObjectPool() : freeIndex(0) {
        for(int i = 0; i < N - 1; i++) {
            data[i].next = i + 1;
        }
        data[N - 1].next = -1;
    }

    template<typename... Args>
    int allocate(Args&&... args) {
        if(freeIndex == -1) {
            return -1;
        }
        int index = freeIndex;
        freeIndex = data[index].next;
        data.init(index, std::forward<Args>(args)...);
        return index;
    }

    void free(int p) {
        data.destroy(p);
        data[p].next = freeIndex;
        freeIndex = p;
    }

    T& operator[](int index) {
        return data[index].t;
    }

    const T& operator[](int index) const {
        return data[index].t;
    }
};

#endif