//
// Created by Lenovo on 16.11.2021.
//

#ifndef FIXEDALLOCATOR_FIXED_ALLOCATOR_H
#define FIXEDALLOCATOR_FIXED_ALLOCATOR_H
#pragma once

#include <cstdint>

using std::uint64_t;

template<typename Tp>
class FixedAllocator {
    PageAllocator page_allocator_;
    std::vector<Tp*> free, used;
    const std::uint64_t pages;

 public:
    explicit FixedAllocator(std::uint64_t page_size) :
            page_allocator_(page_size * sizeof(Tp)),
            free(),  used(), pages(page_size) {
        Tp* p = reinterpret_cast<Tp*>(page_allocator_.Allocate());
        free.push_back(p);
        for (std::uint64_t i = 0; i < page_size - 1; i++) {
            p++;
            free.push_back(p);
        }
    }

    Tp* Allocate() {
        Tp* p;
        if (free.empty()) {
            Tp* pp = reinterpret_cast<Tp*>(page_allocator_.Allocate());
            free.push_back(pp);
            for (std::uint64_t i = 0; i < pages - 1; i++) {
                pp++;
                free.push_back(pp);
            }
        }

        p = free[free.size() - 1];
        free.pop_back();
        used.push_back(p);
        return p;
    }

    void Deallocate(Tp* p) {
        free.push_back(p);
        used.pop_back();
    }

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

#endif  //FIXEDALLOCATOR_FIXED_ALLOCATOR_H