Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
fixed_arena_allocator.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/assert.hpp>
6#include <helios/memory/details/profile.hpp>
7
8#include <atomic>
9#include <cstddef>
10#include <cstdint>
11#include <memory_resource>
12
13namespace helios::mem {
14
15/**
16 * @brief PMR arena with fixed runtime capacity.
17 * @details Lock-free bump allocation with no growth. Individual deallocation is
18 * a no-op; memory is reclaimed by `Reset()` or destruction.
19 * @warning `Reset()` must not run concurrently with `allocate`.
20 */
21class FixedArenaAllocator final : public std::pmr::memory_resource {
22public:
23 /**
24 * @brief Constructs fixed arena with the given backing capacity.
25 * @warning Triggers assertion if `capacity == 0`. Triggers verification
26 * failure if backing allocation fails.
27 * @param capacity Backing buffer size in bytes
28 */
29 explicit FixedArenaAllocator(size_t capacity) noexcept;
31
32 /**
33 * @brief Move-constructs fixed arena from another instance.
34 * @param other Source allocator; left in empty moved-from state
35 */
36 FixedArenaAllocator(FixedArenaAllocator&& other) noexcept { MoveFrom(other); }
37 ~FixedArenaAllocator() noexcept override { Release(); }
38
40
41 /**
42 * @brief Move-assigns fixed arena state from another instance.
43 * @param other Source allocator; left in empty moved-from state
44 * @return Reference to this allocator
45 */
47
48 /**
49 * @brief Soft-resets bump offset and statistics.
50 * @warning Must not be called concurrently with `allocate`.
51 */
52 void Reset() noexcept;
53
54 /**
55 * @brief Returns true when no bytes have been bumped.
56 * @return True if empty, false otherwise
57 */
58 [[nodiscard]] bool Empty() const noexcept {
59 return offset_.load(std::memory_order_relaxed) == 0;
60 }
61
62 /**
63 * @brief Checks whether pointer belongs to this arena's backing buffer.
64 * @param ptr Pointer to test
65 * @return True when owned, false otherwise
66 */
67 [[nodiscard]] bool Owns(const void* ptr) const noexcept;
68
69 /**
70 * @brief Returns runtime statistics snapshot.
71 * @return Allocator stats for this arena
72 */
73 [[nodiscard]] AllocatorStats Stats() const noexcept;
74
75 /**
76 * @brief Returns configured backing capacity.
77 * @return Capacity in bytes
78 */
79 [[nodiscard]] size_t InitialCapacity() const noexcept { return capacity_; }
80
81 /**
82 * @brief Returns configured backing capacity.
83 * @return Capacity in bytes
84 */
85 [[nodiscard]] size_t TotalCapacity() const noexcept { return capacity_; }
86
87private:
88 void MoveFrom(FixedArenaAllocator& other) noexcept;
89 void Release() noexcept;
90
91 [[nodiscard]] void* do_allocate(size_t bytes, size_t alignment) override;
92 void do_deallocate(void* ptr, size_t bytes, size_t alignment) override;
93 [[nodiscard]] bool do_is_equal(
94 const std::pmr::memory_resource& other) const noexcept override {
95 return this == &other;
96 }
97
98 size_t capacity_ = 0;
99 std::byte* buffer_ = nullptr;
100 std::atomic<size_t> offset_{0};
101 std::atomic<size_t> peak_usage_{0};
102 std::atomic<size_t> allocation_count_{0};
103 std::atomic<size_t> total_allocations_{0};
104 std::atomic<size_t> total_deallocations_{0};
105 std::atomic<size_t> alignment_waste_{0};
106};
107
108inline FixedArenaAllocator::FixedArenaAllocator(size_t capacity) noexcept
109 : capacity_(capacity) {
110 HELIOS_ASSERT(capacity_ > 0, "capacity must be greater than zero!");
111 buffer_ = static_cast<std::byte*>(
112 AlignedAlloc(kDefaultAlignment, capacity_, false));
113 HELIOS_VERIFY(buffer_ != nullptr, "Failed to allocate fixed arena!");
114 HELIOS_MEMORY_PROFILE_ALLOC(buffer_, capacity_, "FixedArenaAllocator");
115}
116
118 FixedArenaAllocator&& other) noexcept {
119 if (this == &other) [[unlikely]] {
120 return *this;
121 }
122
123 Release();
124 MoveFrom(other);
125 return *this;
126}
127
128inline void FixedArenaAllocator::Reset() noexcept {
129 HELIOS_MEMORY_PROFILE_SCOPE_N("helios::mem::FixedArenaAllocator::Reset");
130
131 offset_.store(0, std::memory_order_relaxed);
132 peak_usage_.store(0, std::memory_order_relaxed);
133 allocation_count_.store(0, std::memory_order_relaxed);
134 total_allocations_.store(0, std::memory_order_relaxed);
135 total_deallocations_.store(0, std::memory_order_relaxed);
136 alignment_waste_.store(0, std::memory_order_relaxed);
137}
138
139inline bool FixedArenaAllocator::Owns(const void* ptr) const noexcept {
140 HELIOS_MEMORY_PROFILE_SCOPE_N("helios::mem::FixedArenaAllocator::Owns");
141
142 if (buffer_ == nullptr || ptr == nullptr) {
143 return false;
144 }
145
146 const auto address = reinterpret_cast<uintptr_t>(ptr);
147 const auto begin = reinterpret_cast<uintptr_t>(buffer_);
148 return address >= begin && address < begin + capacity_;
149}
150
152 return {
153 .total_allocated = offset_.load(std::memory_order_relaxed),
154 .peak_usage = peak_usage_.load(std::memory_order_relaxed),
155 .allocation_count = allocation_count_.load(std::memory_order_relaxed),
156 .total_allocations = total_allocations_.load(std::memory_order_relaxed),
157 .total_deallocations =
158 total_deallocations_.load(std::memory_order_relaxed),
159 .alignment_waste = alignment_waste_.load(std::memory_order_relaxed),
160 };
161}
162
163} // namespace helios::mem
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:259
#define HELIOS_VERIFY(condition,...)
Verify macro that always checks the condition.
Definition assert.hpp:323
PMR arena with fixed runtime capacity.
FixedArenaAllocator(FixedArenaAllocator &&other) noexcept
Move-constructs fixed arena from another instance.
FixedArenaAllocator(const FixedArenaAllocator &)=delete
size_t InitialCapacity() const noexcept
Returns configured backing capacity.
void Reset() noexcept
Soft-resets bump offset and statistics.
bool Owns(const void *ptr) const noexcept
Checks whether pointer belongs to this arena's backing buffer.
FixedArenaAllocator & operator=(const FixedArenaAllocator &)=delete
size_t TotalCapacity() const noexcept
Returns configured backing capacity.
AllocatorStats Stats() const noexcept
Returns runtime statistics snapshot.
bool Empty() const noexcept
Returns true when no bytes have been bumped.
FixedArenaAllocator(size_t capacity) noexcept
Constructs fixed arena with the given backing capacity.
void * AlignedAlloc(size_t alignment, size_t size, bool enable_profile=true) noexcept
Allocates memory with the specified alignment.
constexpr size_t kDefaultAlignment
Default alignment used by memory resources.
Definition common.hpp:14
STL namespace.
Runtime statistics snapshot for PMR allocators.
Definition common.hpp:163