Make allocate take a template type
So we use the right alignment
This commit is contained in:
@@ -67,7 +67,7 @@ void ArenaAllocator::reset() {
|
||||
void *ArenaAllocator::realloc(void *ptr, size_t old_size, size_t new_size,
|
||||
size_t alignment) {
|
||||
if (ptr == nullptr) {
|
||||
return allocate(new_size, alignment);
|
||||
return allocate_raw(new_size, alignment);
|
||||
}
|
||||
|
||||
if (new_size == old_size) {
|
||||
@@ -119,7 +119,7 @@ void *ArenaAllocator::realloc(void *ptr, size_t old_size, size_t new_size,
|
||||
}
|
||||
|
||||
// Growing but can't extend in place - need to allocate new space and copy
|
||||
void *new_ptr = allocate(new_size, alignment);
|
||||
void *new_ptr = allocate_raw(new_size, alignment);
|
||||
if (new_ptr && ptr) {
|
||||
// Copy all the old data since we're growing
|
||||
std::memcpy(new_ptr, ptr, old_size);
|
||||
|
||||
@@ -150,12 +150,14 @@ public:
|
||||
ArenaAllocator &operator=(ArenaAllocator &&other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Allocate memory with the specified size and alignment.
|
||||
* @brief Allocate raw memory with the specified size and alignment.
|
||||
*
|
||||
* This is the core allocation method providing ~1ns allocation performance.
|
||||
* It performs lazy initialization on first use and automatically grows
|
||||
* the arena when needed using geometric growth (doubling block sizes).
|
||||
*
|
||||
* For type-safe allocation, prefer the allocate<T>() template method.
|
||||
*
|
||||
* @param size Number of bytes to allocate (0 returns nullptr)
|
||||
* @param alignment Required alignment (default: alignof(std::max_align_t))
|
||||
* @return Pointer to allocated memory, or nullptr if size is 0
|
||||
@@ -168,10 +170,10 @@ public:
|
||||
*
|
||||
* ## Example:
|
||||
* ```cpp
|
||||
* void* ptr1 = arena.allocate(100); // Default alignment
|
||||
* void* ptr2 = arena.allocate(64, 16); // 16-byte aligned
|
||||
* void* ptr1 = arena.allocate_raw(100); // Default alignment
|
||||
* void* ptr2 = arena.allocate_raw(64, 16); // 16-byte aligned
|
||||
* MyStruct* ptr3 = static_cast<MyStruct*>(
|
||||
* arena.allocate(sizeof(MyStruct), alignof(MyStruct)));
|
||||
* arena.allocate_raw(sizeof(MyStruct), alignof(MyStruct)));
|
||||
* ```
|
||||
*
|
||||
* ## Performance Note:
|
||||
@@ -179,7 +181,8 @@ public:
|
||||
* The allocation path is extremely hot and inlining eliminates function
|
||||
* call overhead, allowing the ~1ns allocation performance.
|
||||
*/
|
||||
void *allocate(size_t size, size_t alignment = alignof(std::max_align_t)) {
|
||||
void *allocate_raw(size_t size,
|
||||
size_t alignment = alignof(std::max_align_t)) {
|
||||
if (size == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -288,10 +291,60 @@ public:
|
||||
"ArenaAllocator::construct requires trivially destructible types. "
|
||||
"Objects constructed in the arena will not have their destructors "
|
||||
"called.");
|
||||
void *ptr = allocate(sizeof(T), alignof(T));
|
||||
void *ptr = allocate_raw(sizeof(T), alignof(T));
|
||||
return new (ptr) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate space for an array of size T objects with proper alignment.
|
||||
*
|
||||
* This is a type-safe convenience method that combines sizing and alignment
|
||||
* calculations for allocating arrays of type T. It's preferred over calling
|
||||
* allocate_raw() directly as it prevents common errors with size calculations
|
||||
* and alignment requirements.
|
||||
*
|
||||
* @tparam T The type of objects to allocate space for (must be trivially
|
||||
* destructible)
|
||||
* @param size Number of T objects to allocate space for
|
||||
* @return Pointer to allocated memory suitable for constructing an array of T
|
||||
* objects
|
||||
* @throws std::bad_alloc if memory allocation fails
|
||||
*
|
||||
* ## Type Requirements:
|
||||
* T must be trivially destructible (std::is_trivially_destructible_v<T>).
|
||||
* This ensures consistency with the arena allocator's design where
|
||||
* destructors are never called.
|
||||
*
|
||||
* ## Example:
|
||||
* ```cpp
|
||||
* // Allocate space for 100 integers
|
||||
* int* numbers = arena.allocate<int>(100);
|
||||
*
|
||||
* // Allocate space for 50 POD structs
|
||||
* MyPOD* objects = arena.allocate<MyPOD>(50);
|
||||
*
|
||||
* // Initialize some elements (no automatic construction)
|
||||
* numbers[0] = 42;
|
||||
* new (&objects[0]) MyPOD(arg1, arg2);
|
||||
* ```
|
||||
*
|
||||
* ## Note:
|
||||
* This method only allocates memory - it does not construct objects.
|
||||
* Use placement new or other initialization methods as needed.
|
||||
*/
|
||||
template <typename T> T *allocate(size_t size) {
|
||||
static_assert(
|
||||
std::is_trivially_destructible_v<T>,
|
||||
"ArenaAllocator::allocate requires trivially destructible types. "
|
||||
"Objects allocated in the arena will not have their destructors "
|
||||
"called.");
|
||||
if (size == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
void *ptr = allocate_raw(sizeof(T) * size, alignof(T));
|
||||
return static_cast<T *>(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the allocator to reuse the first block, freeing all others.
|
||||
*
|
||||
@@ -542,7 +595,7 @@ public:
|
||||
T *allocate(size_type n) {
|
||||
if (n == 0)
|
||||
return nullptr;
|
||||
return static_cast<T *>(arena_->allocate(n * sizeof(T), alignof(T)));
|
||||
return static_cast<T *>(arena_->allocate_raw(n * sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
void deallocate(T *ptr, size_type n) noexcept {
|
||||
|
||||
@@ -45,7 +45,7 @@ std::string_view CommitRequest::store_string(std::string_view str) {
|
||||
return {};
|
||||
}
|
||||
|
||||
char *arena_str = static_cast<char *>(arena_.allocate(str.size()));
|
||||
char *arena_str = arena_.allocate<char>(str.size());
|
||||
std::memcpy(arena_str, str.data(), str.size());
|
||||
|
||||
return std::string_view(arena_str, str.size());
|
||||
@@ -78,7 +78,7 @@ std::string_view CommitRequest::decode_base64(std::string_view base64_str) {
|
||||
return {};
|
||||
}
|
||||
|
||||
char *output = static_cast<char *>(arena_.allocate(output_len));
|
||||
char *output = arena_.allocate<char>(output_len);
|
||||
if (!output) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user