#pragma once
|
|
|
|
#include "gp_config.hpp"
|
|
|
|
#include "gp/algorithm/min_max.hpp"
|
|
#include "gp/algorithm/tmp_manip.hpp"
|
|
#include "gp/buffer.hpp"
|
|
#include "gp/math/integer_math.hpp"
|
|
#include "gp/allocator/allocator.hpp"
|
|
|
|
#include <type_traits>
|
|
|
|
namespace gp {
|
|
class arena : public allocator {
|
|
gp::optional<gp::reference_wrapper<allocator>> allocator_v;
|
|
size_t next;
|
|
size_t count;
|
|
gp::buffer<char> data;
|
|
public:
|
|
arena()
|
|
: next(0)
|
|
, count(0)
|
|
, data(gp::buffer<char>(nullptr,nullptr))
|
|
{}
|
|
|
|
arena(allocator& allocator_p, size_t sz)
|
|
: allocator_v(allocator_p)
|
|
, next(0)
|
|
, count(0)
|
|
, data(nullptr,nullptr)
|
|
{
|
|
if(sz != 0)
|
|
{
|
|
auto v = allocator_v.value().get().allocate(sz);
|
|
if(v != nullptr)
|
|
{
|
|
data=gp::buffer<char>(reinterpret_cast<char*>(v),reinterpret_cast<char*>(v)+sz);
|
|
}
|
|
}
|
|
}
|
|
|
|
arena(char* pos, size_t sz)
|
|
: next(0)
|
|
, count(0)
|
|
, data(pos,pos+sz)
|
|
{}
|
|
|
|
void reset() {
|
|
next = count = 0;
|
|
}
|
|
|
|
virtual void* allocate(size_t sz)
|
|
{
|
|
size_t align = gp::min((1 << gp::math::log2(sz)), 16);
|
|
size_t padding = align - (reinterpret_cast<uintptr_t>(data.begin().data + next)) % align;
|
|
|
|
auto ret=data.begin()+padding+next;
|
|
if(data.contains(ret))
|
|
{
|
|
count++;
|
|
next+=padding+sz;
|
|
return ret.data;
|
|
}
|
|
else
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return false whatever happens
|
|
*/
|
|
virtual bool try_reallocate(void*, size_t) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Deallocates the memory if every deallocated block as been deallocated, else marks one deallocation
|
|
*
|
|
* @param ptr the memory to deallocate
|
|
* @return true if either a deallocation or block release happened
|
|
* @return false if the pointer was not within the managed area
|
|
*/
|
|
virtual bool deallocate(void* ptr)
|
|
{
|
|
if(data.contains((char*)ptr))
|
|
{
|
|
count--;
|
|
if(count==0)
|
|
{
|
|
for(auto& i : data)
|
|
{
|
|
i=0;
|
|
}
|
|
next=0;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
virtual ~arena()
|
|
{
|
|
if(allocator_v.has_value())
|
|
{
|
|
allocator_v.value().get().deallocate(&data[0]);
|
|
}
|
|
}
|
|
};
|
|
}
|