#pragma once

#include <string>
#include <vector>
#include <utility>

template<typename Tp>
class FixedAllocator {
 public:
  explicit FixedAllocator(std::uint64_t page_size) :
      page_allocator_(PageAllocator(sizeof(Tp) * page_size)),
      page_size_(page_size) {
  }

  Tp *Allocate() {
    Tp *page = nullptr;
    if (free_.size() == 0) {
      page = static_cast<Tp *>(page_allocator_.Allocate());
      free_.push_back(std::make_pair(page_size_, page));
    }
    auto page_size = free_.front();
    if (page_size.first < page_size_ - 1) {
      free_[0].first--;
      free_[0].second++;
    } else {
      free_.erase(free_.begin());
    }
    return page_size.second;
  }

  void Deallocate(Tp *p) {
    for ( size_t i = 0; i < free_.size(); i++ ) {
      if ((free_[i].second - p) == -1) {
        free_[i].first++;
        free_[i].second = p;
        return;
      }
    }
    free_.push_back(std::make_pair(1, p));
  }

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

 private:
  PageAllocator page_allocator_;
  const std::uint64_t page_size_;
  std::vector<std::pair<uint64_t, Tp *>> free_;
};