6#include <memory_resource>
34 void*
do_allocate(
size_t bytes,
size_t alignment)
override {
return arena_.allocate(bytes, alignment); }
37 if (
this == &other)
return true;
60 [[nodiscard]]
constexpr T*
allocate(
size_t num_elems) {
return arena.allocate<T>(num_elems); }
66 return &
arena == &a.arena;
70 return &
arena != &a.arena;
79 template<class U, std::enable_if_t<std::is_convertible_v<U*, T*>,
int> = 0>
82 constexpr void operator()(T* ptr)
const noexcept(
noexcept(ptr->~T())) { ptr->~T(); }
86 using Ptr = std::unique_ptr<T, Deleter<T>>;
87 using State = std::pair<size_t, size_t>;
93 : page_size_(page_size) {
94 pages_.emplace_back();
120 template<
class T,
class... Args>
132 if (num_bytes == 0)
return nullptr;
136 if (aligned_index + num_bytes > pages_.back().size) {
137 pages_.emplace_back(std::max(page_size_, num_bytes),
align);
141 auto result = pages_.back().buffer + aligned_index;
142 index_ = aligned_index + num_bytes;
147 [[nodiscard]]
constexpr T*
allocate(
size_t num_elems) {
148 return static_cast<T*
>(
allocate(num_elems *
sizeof(T),
alignof(T)));
165 assert(num_bytes <= index_);
168 [[nodiscard]]
State state() const noexcept {
return {pages_.size(), index_}; }
171 assert(
state.first > 0);
172 assert(
state.first <= pages_.size());
173 while (pages_.size() >
state.first)
175 assert(
state.second <= pages_.back().size);
176 index_ =
state.second;
183 swap(a1.pages_, a2.pages_);
184 swap(a1.page_size_, a2.page_size_);
185 swap(a1.index_, a2.index_);
190 static constexpr size_t align(
size_t i,
size_t a)
noexcept {
return (i + (a - 1)) & ~(a - 1); }
193 constexpr Arena&
align(
size_t a)
noexcept {
return index_ =
align(index_, a), *
this; }
196 constexpr Page() noexcept = default;
197 Page(
size_t size,
size_t align)
200 , buffer((
char*)::operator new[](size, std::align_val_t(align))) {}
201 constexpr ~Page() noexcept {
202 if (buffer) ::operator
delete[](buffer, std::align_val_t(align));
205 const size_t size = 0;
206 const size_t align = 0;
207 char* buffer =
nullptr;
210 std::list<Page> pages_;
A memory resource bridge in order to use this Arena for pmr containers.
bool do_is_equal(const std::pmr::memory_resource &other) const noexcept override
MemoryResource(Arena &arena) noexcept
void do_deallocate(void *, size_t, size_t) override
void * do_allocate(size_t bytes, size_t alignment) override
An arena pre-allocates so-called pages of size Arena::page_size_.
constexpr void deallocate(size_t num_bytes) noexcept
Removes num_bytes again.
void deallocate(State state) noexcept
Arena(const Arena &)=delete
Arena(Arena &&other) noexcept
constexpr void * allocate(size_t num_bytes, size_t align)
Get n bytes of fresh memory.
static constexpr size_t align(size_t i, size_t a) noexcept
Align i to a.
std::pmr::memory_resource * resource() noexcept
std::pair< size_t, size_t > State
Arena(size_t page_size=Default_Page_Size)
friend void swap(Arena &a1, Arena &a2) noexcept
Arena & operator=(Arena)=delete
std::unique_ptr< T, Deleter< T > > Ptr
const std::pmr::memory_resource * resource() const noexcept
constexpr T * allocate(size_t num_elems)
constexpr Ptr< T > mk(Args &&... args)
This is a std::unique_ptr that uses the Arena under the hood and whose Deleter will only invoke the d...
constexpr Allocator< T > allocator() noexcept
Create Allocator from Arena.
static constexpr size_t Default_Page_Size
1MB.
State state() const noexcept
Default Pos/Loc stream output and dump helpers.
An allocator in order to use this Arena for containers.
constexpr bool operator!=(const Allocator< U > &a) const noexcept
constexpr T * allocate(size_t num_elems)
constexpr bool operator==(const Allocator< U > &a) const noexcept
constexpr void deallocate(T *, size_t) noexcept
constexpr Allocator(const Arena::Allocator< U > &allocator) noexcept
constexpr Allocator(Arena &arena) noexcept
constexpr Deleter() noexcept=default
constexpr void operator()(T *ptr) const noexcept(noexcept(ptr->~T()))