Add arena allocator

This commit is contained in:
2025-08-14 11:15:48 -04:00
parent a2eef4ce25
commit b45fd1d29e
3 changed files with 380 additions and 0 deletions

88
src/arena_allocator.hpp Normal file
View File

@@ -0,0 +1,88 @@
#pragma once
#include <cstddef>
#include <memory>
#include <vector>
class ArenaAllocator {
public:
explicit ArenaAllocator(size_t initial_size = 1024)
: block_size_(initial_size), current_block_(0), current_offset_(0) {
add_block();
}
~ArenaAllocator() = default;
ArenaAllocator(const ArenaAllocator &) = delete;
ArenaAllocator &operator=(const ArenaAllocator &) = delete;
ArenaAllocator(ArenaAllocator &&) = default;
ArenaAllocator &operator=(ArenaAllocator &&) = default;
void *allocate(size_t size, size_t alignment = alignof(std::max_align_t)) {
if (size == 0) {
return nullptr;
}
char *block_start = blocks_[current_block_].get();
uintptr_t block_addr = reinterpret_cast<uintptr_t>(block_start);
size_t aligned_offset =
align_up(block_addr + current_offset_, alignment) - block_addr;
if (aligned_offset + size > block_size_) {
if (size > block_size_) {
throw std::bad_alloc();
}
add_block();
block_start = blocks_[current_block_].get();
block_addr = reinterpret_cast<uintptr_t>(block_start);
aligned_offset = align_up(block_addr, alignment) - block_addr;
}
void *ptr = block_start + aligned_offset;
current_offset_ = aligned_offset + size;
return ptr;
}
template <typename T, typename... Args> T *construct(Args &&...args) {
void *ptr = allocate(sizeof(T), alignof(T));
return new (ptr) T(std::forward<Args>(args)...);
}
void reset() {
current_block_ = 0;
current_offset_ = 0;
}
size_t total_allocated() const { return blocks_.size() * block_size_; }
size_t used_bytes() const {
return current_block_ * block_size_ + current_offset_;
}
size_t available_in_current_block() const {
return block_size_ - current_offset_;
}
size_t num_blocks() const { return blocks_.size(); }
private:
void add_block() {
blocks_.emplace_back(std::make_unique<char[]>(block_size_));
current_block_ = blocks_.size() - 1;
current_offset_ = 0;
}
static size_t align_up(size_t value, size_t alignment) {
if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
return value;
}
return (value + alignment - 1) & ~(alignment - 1);
}
size_t block_size_;
size_t current_block_;
size_t current_offset_;
std::vector<std::unique_ptr<char[]>> blocks_;
};