#pragma once
#include <stack>

template<typename Tp>
class FixedAllocator {
    PageAllocator* page_allocator_;
    std::stack<Tp*>* free_pool;
    std::uint64_t page_size;
 public:
     explicit FixedAllocator(std::uint64_t page_size) {
         this->page_allocator_ = new PageAllocator(sizeof(Tp) * page_size);
         this->free_pool = new std::stack<Tp*>();
         this->page_size = page_size;
     }

     ~FixedAllocator() {
         delete page_allocator_;
         delete free_pool;
     }

     Tp* Allocate() {
         if (this->free_pool->empty()) {
             Tp* new_free_memory = (Tp*)this->page_allocator_->Allocate();

             for (size_t i = 0; i < page_size; ++i) {
                 this->free_pool->push(&new_free_memory[i]);
             }

             Tp* res = this->free_pool->top();
             this->free_pool->pop();

             return res;
         } else {
             Tp* res = this->free_pool->top();
             this->free_pool->pop();

             return res;
         }
     }

     void Deallocate(Tp* p) {
         this->free_pool->push(p);
     }

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