#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 namespace gp { class arena : public allocator { gp::optional> allocator_v; size_t next; size_t count; gp::buffer data; public: arena() : next(0) , count(0) , data(gp::buffer(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(reinterpret_cast(v),reinterpret_cast(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(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; } } virtual bool try_reallocate(void*, size_t) { return false; } 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]); } } }; }