Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
helios::memory::DoubleFrameAllocator Class Referencefinal

Double-buffered frame allocator. More...

#include <double_frame_allocator.hpp>

Public Member Functions

 DoubleFrameAllocator (size_t capacity_per_buffer)
 Constructs a double frame allocator with specified capacity per buffer.
 
 DoubleFrameAllocator (const DoubleFrameAllocator &)=delete
 
 DoubleFrameAllocator (DoubleFrameAllocator &&other) noexcept
 
 ~DoubleFrameAllocator () noexcept=default
 
DoubleFrameAllocatoroperator= (const DoubleFrameAllocator &)=delete
 
DoubleFrameAllocatoroperator= (DoubleFrameAllocator &&other) noexcept
 
AllocationResult Allocate (size_t size, size_t alignment=kDefaultAlignment) noexcept
 Allocates memory from the current frame buffer.
 
template<typename T >
T * Allocate () noexcept
 Allocates memory for a single object of type T.
 
template<typename T >
T * Allocate (size_t count) noexcept
 Allocates memory for an array of objects of type T.
 
template<typename T , typename... Args>
requires std::constructible_from<T, Args...>
T * AllocateAndConstruct (Args &&... args) noexcept(std::is_nothrow_constructible_v< T, Args... >)
 Allocates and constructs a single object of type T.
 
template<typename T >
requires std::default_initializable<T>
T * AllocateAndConstructArray (size_t count) noexcept(std::is_nothrow_default_constructible_v< T >)
 Allocates and default-constructs an array of objects of type T.
 
void NextFrame () noexcept
 Advances to the next frame, switching buffers.
 
void Reset () noexcept
 Resets both buffers.
 
AllocatorStats Stats () const noexcept
 Gets combined statistics for both buffers.
 
AllocatorStats CurrentFrameStats () const noexcept
 Gets statistics for the current frame buffer.
 
AllocatorStats PreviousFrameStats () const noexcept
 Gets statistics for the previous frame buffer.
 
size_t Capacity () const noexcept
 Gets the total capacity across both buffers.
 
size_t CurrentBufferIndex () const noexcept
 Gets the current frame buffer index.
 
size_t PreviousBufferIndex () const noexcept
 Gets the previous frame buffer index.
 
size_t FreeSpace () const noexcept
 Gets free space in current buffer.
 

Static Public Attributes

static constexpr size_t kBufferCount = 2
 

Detailed Description

Double-buffered frame allocator.

Maintains two frame buffers, allowing memory from the previous frame to remain valid while allocating for the current frame. Useful when data needs to be accessible for one additional frame (e.g., GPU upload buffers, interpolation).

The allocator automatically switches between buffers on each frame.

Uses atomic for buffer index and frame transitions. Previous frame's data remains valid until the next frame begins. Allocations are lock-free since FrameAllocator uses atomic operations internally.

Note
Thread-safe.

Definition at line 32 of file double_frame_allocator.hpp.

Constructor & Destructor Documentation

◆ DoubleFrameAllocator() [1/3]

helios::memory::DoubleFrameAllocator::DoubleFrameAllocator ( size_t  capacity_per_buffer)
inlineexplicit

Constructs a double frame allocator with specified capacity per buffer.

Warning
Triggers assertion if capacity_per_buffer is 0.
Parameters
capacity_per_bufferSize of each buffer in bytes

Definition at line 41 of file double_frame_allocator.hpp.

42 : allocators_{FrameAllocator(capacity_per_buffer), FrameAllocator(capacity_per_buffer)} {}

◆ DoubleFrameAllocator() [2/3]

helios::memory::DoubleFrameAllocator::DoubleFrameAllocator ( const DoubleFrameAllocator )
delete

◆ DoubleFrameAllocator() [3/3]

helios::memory::DoubleFrameAllocator::DoubleFrameAllocator ( DoubleFrameAllocator &&  other)
inlinenoexcept

Definition at line 174 of file double_frame_allocator.hpp.

175 : allocators_(std::move(other.allocators_)),
176 current_buffer_(other.current_buffer_.load(std::memory_order_acquire)) {
177 other.current_buffer_.store(0, std::memory_order_release);
178}

◆ ~DoubleFrameAllocator()

helios::memory::DoubleFrameAllocator::~DoubleFrameAllocator ( )
defaultnoexcept

Member Function Documentation

◆ Allocate() [1/3]

template<typename T >
T * helios::memory::DoubleFrameAllocator::Allocate ( )
inlinenoexcept

Allocates memory for a single object of type T.

Convenience function that calculates size and alignment from the type. The returned memory is uninitialized - use placement new to construct the object.

Template Parameters
TType to allocate memory for
Returns
Pointer to allocated memory, or nullptr on failure

Definition at line 231 of file double_frame_allocator.hpp.

231 {
232 constexpr size_t size = sizeof(T);
233 constexpr size_t alignment = std::max(alignof(T), kMinAlignment);
234 auto result = Allocate(size, alignment);
235 return static_cast<T*>(result.ptr);
236}
T * Allocate() noexcept
Allocates memory for a single object of type T.
constexpr size_t kMinAlignment
Minimum alignment for any allocation.

◆ Allocate() [2/3]

template<typename T >
T * helios::memory::DoubleFrameAllocator::Allocate ( size_t  count)
inlinenoexcept

Allocates memory for an array of objects of type T.

Convenience function that calculates size and alignment from the type. The returned memory is uninitialized - use placement new to construct objects.

Template Parameters
TType to allocate memory for
Parameters
countNumber of objects to allocate space for
Returns
Pointer to allocated memory, or nullptr on failure

Definition at line 239 of file double_frame_allocator.hpp.

239 {
240 if (count == 0) [[unlikely]] {
241 return nullptr;
242 }
243 constexpr size_t alignment = std::max(alignof(T), kMinAlignment);
244 const size_t size = sizeof(T) * count;
245 auto result = Allocate(size, alignment);
246 return static_cast<T*>(result.ptr);
247}

◆ Allocate() [3/3]

AllocationResult helios::memory::DoubleFrameAllocator::Allocate ( size_t  size,
size_t  alignment = kDefaultAlignment 
)
inlinenoexcept

Allocates memory from the current frame buffer.

This operation is lock-free as it only reads the atomic buffer index and delegates to the thread-safe FrameAllocator.

Warning
Triggers assertion in next cases:
  • Alignment is not a power of 2.
  • Alignment is less than kMinAlignment.
Parameters
sizeNumber of bytes to allocate
alignmentAlignment requirement (must be power of 2)
Returns
AllocationResult with pointer and actual allocated size, or {nullptr, 0} on failure

Definition at line 193 of file double_frame_allocator.hpp.

193 {
194 // Lock-free: current_buffer_ is atomic, FrameAllocator::Allocate is thread-safe via atomics
195 const size_t buffer = current_buffer_.load(std::memory_order_acquire);
196 return allocators_[buffer].Allocate(size, alignment);
197}

◆ AllocateAndConstruct()

template<typename T , typename... Args>
requires std::constructible_from<T, Args...>
T * helios::memory::DoubleFrameAllocator::AllocateAndConstruct ( Args &&...  args)
inlinenoexcept

Allocates and constructs a single object of type T.

Convenience function that allocates memory and constructs the object in-place.

Template Parameters
TType to allocate and construct
ArgsConstructor argument types
Parameters
argsArguments to forward to T's constructor
Returns
Pointer to constructed object, or nullptr on allocation failure

Definition at line 251 of file double_frame_allocator.hpp.

252 {
253 T* ptr = Allocate<T>();
254 if (ptr != nullptr) [[likely]] {
255 std::construct_at(ptr, std::forward<Args>(args)...);
256 }
257 return ptr;
258}

◆ AllocateAndConstructArray()

template<typename T >
requires std::default_initializable<T>
T * helios::memory::DoubleFrameAllocator::AllocateAndConstructArray ( size_t  count)
inlinenoexcept

Allocates and default-constructs an array of objects of type T.

Convenience function that allocates memory and default-constructs objects in-place.

Template Parameters
TType to allocate and construct (must be default constructible)
Parameters
countNumber of objects to allocate and construct
Returns
Pointer to first constructed object, or nullptr on allocation failure

Definition at line 262 of file double_frame_allocator.hpp.

263 {
264 T* ptr = Allocate<T>(count);
265 if (ptr != nullptr) [[likely]] {
266 for (size_t i = 0; i < count; ++i) {
267 std::construct_at(ptr + i);
268 }
269 }
270 return ptr;
271}

◆ Capacity()

size_t helios::memory::DoubleFrameAllocator::Capacity ( ) const
inlinenoexcept

Gets the total capacity across both buffers.

Returns
Total capacity in bytes

Definition at line 145 of file double_frame_allocator.hpp.

145 {
146 return allocators_.front().Capacity() + allocators_.back().Capacity();
147 }

◆ CurrentBufferIndex()

size_t helios::memory::DoubleFrameAllocator::CurrentBufferIndex ( ) const
inlinenoexcept

Gets the current frame buffer index.

Returns
Current buffer index (0 or 1)

Definition at line 153 of file double_frame_allocator.hpp.

153{ return current_buffer_.load(std::memory_order_relaxed); }

◆ CurrentFrameStats()

AllocatorStats helios::memory::DoubleFrameAllocator::CurrentFrameStats ( ) const
inlinenoexcept

Gets statistics for the current frame buffer.

Returns
AllocatorStats for current buffer

Definition at line 273 of file double_frame_allocator.hpp.

273 {
274 const size_t buffer = current_buffer_.load(std::memory_order_relaxed);
275 return allocators_[buffer].Stats();
276}

◆ FreeSpace()

size_t helios::memory::DoubleFrameAllocator::FreeSpace ( ) const
inlinenoexcept

Gets free space in current buffer.

Returns
Free space in bytes

Definition at line 283 of file double_frame_allocator.hpp.

283 {
284 const size_t buffer = current_buffer_.load(std::memory_order_relaxed);
285 return allocators_[buffer].FreeSpace();
286}

◆ NextFrame()

void helios::memory::DoubleFrameAllocator::NextFrame ( )
inlinenoexcept

Advances to the next frame, switching buffers.

Resets the new current buffer and makes the old current buffer the previous buffer.

Warning
Not thread-safe with Allocate(). Must be called from a single thread while no other threads are allocating. Typically called once per frame by the main thread.

Definition at line 199 of file double_frame_allocator.hpp.

199 {
200 // Switch to the other buffer
201 const size_t new_buffer = 1 - current_buffer_.load(std::memory_order_relaxed);
202
203 // Reset the new current buffer before switching
204 allocators_[new_buffer].Reset();
205
206 // Switch to new buffer
207 current_buffer_.store(new_buffer, std::memory_order_release);
208}

◆ operator=() [1/2]

DoubleFrameAllocator & helios::memory::DoubleFrameAllocator::operator= ( const DoubleFrameAllocator )
delete

◆ operator=() [2/2]

DoubleFrameAllocator & helios::memory::DoubleFrameAllocator::operator= ( DoubleFrameAllocator &&  other)
inlinenoexcept

Definition at line 180 of file double_frame_allocator.hpp.

180 {
181 if (this == &other) [[unlikely]] {
182 return *this;
183 }
184
185 allocators_ = std::move(other.allocators_);
186
187 current_buffer_.store(other.current_buffer_.load(std::memory_order_acquire), std::memory_order_release);
188 other.current_buffer_.store(0, std::memory_order_release);
189
190 return *this;
191}

◆ PreviousBufferIndex()

size_t helios::memory::DoubleFrameAllocator::PreviousBufferIndex ( ) const
inlinenoexcept

Gets the previous frame buffer index.

Returns
Previous buffer index (0 or 1)

Definition at line 159 of file double_frame_allocator.hpp.

159 {
160 return 1 - current_buffer_.load(std::memory_order_relaxed);
161 }

◆ PreviousFrameStats()

AllocatorStats helios::memory::DoubleFrameAllocator::PreviousFrameStats ( ) const
inlinenoexcept

Gets statistics for the previous frame buffer.

Returns
AllocatorStats for previous buffer

Definition at line 278 of file double_frame_allocator.hpp.

278 {
279 const size_t buffer = current_buffer_.load(std::memory_order_relaxed);
280 return allocators_[1 - buffer].Stats();
281}

◆ Reset()

void helios::memory::DoubleFrameAllocator::Reset ( )
inlinenoexcept

Resets both buffers.

Clears all allocations from both buffers.

Definition at line 210 of file double_frame_allocator.hpp.

210 {
211 allocators_.front().Reset();
212 allocators_.back().Reset();
213}

◆ Stats()

AllocatorStats helios::memory::DoubleFrameAllocator::Stats ( ) const
inlinenoexcept

Gets combined statistics for both buffers.

Returns
AllocatorStats with combined usage information

Definition at line 215 of file double_frame_allocator.hpp.

215 {
216 const AllocatorStats stats0 = allocators_.front().Stats();
217 const AllocatorStats stats1 = allocators_.back().Stats();
218
219 return {
220 .total_allocated = stats0.total_allocated + stats1.total_allocated,
221 .total_freed = stats0.total_freed + stats1.total_freed,
222 .peak_usage = std::max(stats0.peak_usage, stats1.peak_usage),
223 .allocation_count = stats0.allocation_count + stats1.allocation_count,
224 .total_allocations = stats0.total_allocations + stats1.total_allocations,
225 .total_deallocations = stats0.total_deallocations + stats1.total_deallocations,
226 .alignment_waste = stats0.alignment_waste + stats1.alignment_waste,
227 };
228}

Member Data Documentation

◆ kBufferCount

constexpr size_t helios::memory::DoubleFrameAllocator::kBufferCount = 2
staticconstexpr

Definition at line 34 of file double_frame_allocator.hpp.