co_ecs 0.9.0
Cobalt ECS
Loading...
Searching...
No Matches
stack_allocator.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cassert>
4#include <cstddef>
5#include <memory>
6#include <utility>
7
9
10namespace co_ecs::detail {
11
13class stack_allocator {
14private:
15 using padding_t = uint8_t;
16
18 struct alloc_header {
19 padding_t padding;
20 };
21
22public:
26 stack_allocator(void* ptr, std::size_t size) : _start(static_cast<char*>(ptr)), _size(size) {
27 }
28
29 stack_allocator(const stack_allocator& rhs) = delete;
30 stack_allocator& operator=(const stack_allocator& rhs) = delete;
31
34 stack_allocator(stack_allocator&& rhs) noexcept :
35 _start(std::exchange(rhs._start, nullptr)), _size(std::exchange(rhs._size, 0)) {
36 }
37
41 stack_allocator& operator=(stack_allocator&& rhs) noexcept {
42 _start = std::exchange(rhs._start, nullptr);
43 _size = std::exchange(rhs._size, 0);
44 return *this;
45 }
46
51 auto allocate(std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept -> void* {
52 assert(is_power_of_2(alignment) && "Alignment must be a power of two");
53 assert((alignment <= std::numeric_limits<padding_t>::max()) && "Alignment is out of range");
54
55 // Get the top of the stack
56 char* top = _start + _offset;
57 // Get the pointer to the top + 1 allocation header
58 void* ptr = top + sizeof(alloc_header);
59 // Calculate remaining space
60 auto remaining_space = _size - _offset - sizeof(alloc_header);
61 // Calculate aligned pointer
62 void* aligned_ptr = std::align(alignment, bytes, ptr, remaining_space);
63 if (!aligned_ptr) {
64 return nullptr;
65 }
66
67 // Get the required padding from the top of the stack to the allocation
68 auto padding = static_cast<padding_t>(static_cast<char*>(aligned_ptr) - top);
69 // Increment offset by padding and allocation size
70 _offset += padding + bytes;
71
72 // Write header
73 new (static_cast<char*>(aligned_ptr) - sizeof(alloc_header)) alloc_header{ padding };
74
75 return aligned_ptr;
76 }
77
80 void deallocate(void* ptr) noexcept {
81 assert((ptr < _start + _size) && (ptr >= _start) && "Outside allocation range");
82
83 // Fetch header
84 auto* hdr = reinterpret_cast<alloc_header*>(static_cast<char*>(ptr) - sizeof(alloc_header));
85 // Decrement offset
86 _offset = static_cast<char*>(ptr) - hdr->padding - _start;
87
88 hdr->~alloc_header(); // no-op
89 }
90
93 [[nodiscard]] auto remaining() const noexcept -> std::size_t {
94 return (_size - _offset);
95 }
96
98 void reset() noexcept {
99 _offset = 0;
100 }
101
102private:
103 char* _start;
104 std::size_t _offset{};
105 std::size_t _size;
106};
107
108} // namespace co_ecs::detail
Definition component.hpp:17
constexpr auto is_power_of_2(auto value) -> bool
Check if value is a power of 2.
Definition bits.hpp:17
STL namespace.