42 std::byte* _data_start;
44 std::byte* _prev_slot =
nullptr;
46 std::byte* get_slot_next_at(
const std::byte* ptr) {
48 std::memcpy(&out, ptr,
sizeof(
void*));
52 destroy_fn get_slot_destroy_at(
const std::byte* ptr) {
54 std::memcpy(&out, ptr +
sizeof(
void*),
sizeof(
destroy_fn));
58 void* get_slot_data_at(std::byte* ptr) {
59 return ptr +
sizeof(
void*) +
sizeof(
destroy_fn);
62 void set_slot_next_at(std::byte* ptr,
void* next) {
63 std::memcpy(ptr, &next,
sizeof(
void*));
66 void set_slot_destroy_at(std::byte* ptr,
destroy_fn fn) {
67 std::memcpy(ptr +
sizeof(
void*), &fn,
sizeof(
destroy_fn));
70 std::byte* first_slot() {
71 return _data_end == _data_start ? nullptr : _data_start;
76 bump_ptr_pool(std::size_t sz = ZEN_DEFAULT_POOL_CHUNK_SIZE) {
78 _data_start =
new std::byte[_data_sz +
sizeof(
void*)];
79 memset(_data_start, 0, _data_sz +
sizeof(
void*));
80 _data_end = _data_start;
84 return _data_start == _data_end;
87 std::size_t max_bytes_free()
const {
88 auto free = _data_sz - (_data_end - _data_start);
89 auto header_size =
sizeof(
void*) +
sizeof(
destroy_fn);
90 return free < header_size ? 0 : free - header_size;
93 std::size_t capacity()
const {
97 void* allocate(std::size_t sz, std::size_t alignment,
destroy_fn destroy) {
98 void* data = get_slot_data_at(_data_end);
99 std::size_t free = max_bytes_free();
100 if (!std::align(alignment, sz, data, free)) {
103 set_slot_destroy_at(_data_end, destroy);
105 set_slot_next_at(_prev_slot, _data_end);
107 _prev_slot = _data_end;
108 _data_end =
static_cast<std::byte*
>(data) + sz;
113 auto curr_slot = first_slot();
115 get_slot_destroy_at(curr_slot)(get_slot_data_at(
reinterpret_cast<std::byte*
>(curr_slot)));
116 curr_slot = get_slot_next_at(curr_slot);
121 static std::size_t min_size_for(std::size_t sz) {
122 return power_of_2_ceil(sz +
sizeof(
void*) +
sizeof(
destroy_fn));
139class growing_bump_ptr_pool {
141 std::list<bump_ptr_pool*> chunks;
145 growing_bump_ptr_pool(std::size_t min_size = ZEN_DEFAULT_GROWING_BUMP_PTR_POOL_MIN_SIZE) {
146 chunks.push_back(
new bump_ptr_pool { power_of_2_ceil(min_size) });
149 growing_bump_ptr_pool(growing_bump_ptr_pool&& other):
150 chunks(std::move(other.chunks)) {}
152 void* allocate(std::size_t sz, std::size_t alignment,
destroy_fn destroy) {
153 auto last_chunk = chunks.back();
154 void* ptr = last_chunk->allocate(sz, alignment, destroy);
155 if (ZEN_LIKELY(ptr)) {
160 bump_ptr_pool::min_size_for(sz),
161 next_power_of_2(last_chunk->capacity())
164 if (ZEN_UNLIKELY(next_chunk ==
nullptr)) {
167 chunks.push_back(next_chunk);
168 return next_chunk->allocate(sz, alignment, destroy);
171 ~growing_bump_ptr_pool() {
172 for (
auto chunk: chunks) {