#ifndef PAGEDBUFFER_H
#define PAGEDBUFFER_H

#include "System.h"
#include <vector>
#include <stdint.h>
#include <stdlib.h>

template <typename T>
class PagedBuffer
{
public:
    /**
     * Create a PagedBuffer.
     */
    PagedBuffer<T>()
    {
        m_n_per_page = System::page_size / sizeof(T);
        m_size = 0u;
    }

    ~PagedBuffer<T>()
    {
        for (auto it : m_pages)
        {
            System::free_pages(it, 1);
        }
    }

    const T & operator[](unsigned int index) const
    {
        while (index >= (m_pages.size() * m_n_per_page))
        {
            grow();
        }
        return m_pages[page_index(index)][index_in_page(index)];
    }

    T & operator[](unsigned int index)
    {
        while (index >= (m_pages.size() * m_n_per_page))
        {
            grow();
        }
        return m_pages[page_index(index)][index_in_page(index)];
    }

    size_t size() { return m_size; }

protected:
    unsigned int page_index(unsigned int index)
    {
        return index / m_n_per_page;
    }

    unsigned int index_in_page(unsigned int index)
    {
        return index % m_n_per_page;
    }

    void grow()
    {
        m_pages.push_back((T *)System::alloc_pages(1));
        m_size += m_n_per_page;
    }

    std::vector<T *> m_pages;
    unsigned long m_size;
    unsigned int m_n_per_page;
};

#endif
