#pragma once
#include <vector>
#include <unordered_set>
#include <stack>

template<typename Tp>
class FixedAllocator {
 private:
    PageAllocator page_allocator_;
    unsigned uint64_t page_size_;
    std::stack<Tp*> free_memory_;
    std::unordered_set<Tp*> memory_;

 public:
    explicit FixedAllocator(std::uint64_t page_size) :
    page_allocator_(page_size * sizeof(Tp)), page_size_(page_size) {}

    Tp* Allocate() {
        if (free_memory_.empty()) {
            Tp* free_memory = reinterpret_cast<Tp*>(page_allocator_.Allocate());

            for (unsigned uint64_t i = 0; i < page_size_; i++) {
                free_memory_.push(free_memory + i);
            }
        }

        Tp* free_memory = free_memory_.top();
        free_memory_.pop();

        return free_memory;
    }

    void Deallocate(Tp* p) {
        free_memory_.push(p);
    }

    const PageAllocator& InnerAllocator() const noexcept {
        return page_allocator_;
    }
};