libdonut 2.3.6
Application framework for cross-platform game development in C++20
Loading...
Searching...
No Matches
LinearAllocator.hpp
Go to the documentation of this file.
1#ifndef DONUT_LINEAR_ALLOCATOR_HPP
2#define DONUT_LINEAR_ALLOCATOR_HPP
3
4#include <algorithm> // std::max
5#include <cassert> // assert
6#include <cstddef> // std::size_t, std::byte, std::max_align_t
7#include <memory> // std::align
8#include <new> // std::align_val_t
9#include <span> // std::span
10#include <utility> // std::exchange, std::swap
11#include <vector> // std::vector
12
13namespace donut {
14
16public:
18 : LinearMemoryResource(std::span<std::byte>{}) {}
19
20 explicit LinearMemoryResource(std::span<std::byte> initialMemory) noexcept
21 : remainingMemoryBegin(initialMemory.data())
22 , remainingMemorySize(initialMemory.size())
23 , nextChunkSize(std::max(std::size_t{1024}, initialMemory.size() + initialMemory.size() / 2)) {}
24
25 void* allocate(std::size_t size, std::size_t alignment) {
26 if (size == 0) {
27 [[unlikely]];
28 size = 1;
29 }
30 void* result = std::align(alignment, size, remainingMemoryBegin, remainingMemorySize);
31 if (!result) {
32 [[unlikely]];
33 const std::size_t newChunkSize = std::max(size, nextChunkSize);
34 const std::size_t newChunkAlignment = std::max(alignment, alignof(std::max_align_t));
35 if (extraMemory.capacity() < 4) {
36 extraMemory.reserve(4);
37 }
38 AlignedHeapMemoryChunk& newChunk = extraMemory.emplace_back(newChunkSize, newChunkAlignment);
39 remainingMemoryBegin = newChunk.memory;
40 remainingMemorySize = newChunkSize;
41 nextChunkSize += nextChunkSize / 2;
42 result = remainingMemoryBegin;
43 }
44 remainingMemoryBegin = static_cast<std::byte*>(remainingMemoryBegin) + size;
45 remainingMemorySize -= size;
46 return result;
47 }
48
49 [[nodiscard]] std::size_t getRemainingCapacity() const noexcept {
50 return remainingMemorySize;
51 }
52
53private:
54 struct AlignedHeapMemoryChunk {
55 void* memory;
56 std::size_t alignment;
57
58 AlignedHeapMemoryChunk(std::size_t size, std::size_t alignment)
59 : memory(operator new[](size, static_cast<std::align_val_t>(alignment)))
60 , alignment(alignment) {}
61
62 ~AlignedHeapMemoryChunk() {
63 operator delete[](memory, static_cast<std::align_val_t>(alignment));
64 }
65
66 AlignedHeapMemoryChunk(const AlignedHeapMemoryChunk&) = delete;
67
68 AlignedHeapMemoryChunk(AlignedHeapMemoryChunk&& other) noexcept
69 : memory(std::exchange(other.memory, nullptr))
70 , alignment(std::exchange(other.alignment, 1)) {}
71
72 AlignedHeapMemoryChunk& operator=(const AlignedHeapMemoryChunk&) = delete;
73
74 AlignedHeapMemoryChunk& operator=(AlignedHeapMemoryChunk&& other) noexcept {
75 std::swap(memory, other.memory);
76 std::swap(alignment, other.alignment);
77 return *this;
78 }
79 };
80
81 void* remainingMemoryBegin;
82 std::size_t remainingMemorySize;
83 std::size_t nextChunkSize;
84 std::vector<AlignedHeapMemoryChunk> extraMemory{};
85};
86
87template <typename T>
89public:
90 using value_type = T;
91
92 LinearAllocator(LinearMemoryResource* memoryResource) noexcept
93 : memoryResource(memoryResource) {
94 assert(memoryResource);
95 }
96
97 template <typename U>
98 LinearAllocator(const LinearAllocator<U>& other) noexcept
99 : memoryResource(other.memoryResource) {}
100
101 LinearAllocator(const LinearAllocator& other) noexcept = default;
102 LinearAllocator(LinearAllocator&& other) noexcept = default;
103 LinearAllocator& operator=(const LinearAllocator& other) noexcept = default;
104 LinearAllocator& operator=(LinearAllocator&& other) noexcept = default;
105
106 [[nodiscard]] T* allocate(std::size_t n) {
107 return static_cast<T*>(memoryResource->allocate(n * sizeof(T), alignof(T)));
108 }
109
110 void deallocate(T*, std::size_t) noexcept {}
111
112 template <typename U>
113 [[nodiscard]] bool operator==(const LinearAllocator<U>& other) const noexcept {
114 return memoryResource == other.memoryResource;
115 }
116
117private:
118 template <typename U>
119 friend class LinearAllocator;
120
121 LinearMemoryResource* memoryResource;
122};
123
124} // namespace donut
125
126#endif
Definition LinearAllocator.hpp:88
bool operator==(const LinearAllocator< U > &other) const noexcept
Definition LinearAllocator.hpp:113
void deallocate(T *, std::size_t) noexcept
Definition LinearAllocator.hpp:110
LinearAllocator(LinearAllocator &&other) noexcept=default
LinearAllocator & operator=(const LinearAllocator &other) noexcept=default
LinearAllocator(const LinearAllocator< U > &other) noexcept
Definition LinearAllocator.hpp:98
LinearAllocator & operator=(LinearAllocator &&other) noexcept=default
LinearAllocator(LinearMemoryResource *memoryResource) noexcept
Definition LinearAllocator.hpp:92
T value_type
Definition LinearAllocator.hpp:90
T * allocate(std::size_t n)
Definition LinearAllocator.hpp:106
LinearAllocator(const LinearAllocator &other) noexcept=default
Definition LinearAllocator.hpp:15
void * allocate(std::size_t size, std::size_t alignment)
Definition LinearAllocator.hpp:25
LinearMemoryResource(std::span< std::byte > initialMemory) noexcept
Definition LinearAllocator.hpp:20
LinearMemoryResource() noexcept
Definition LinearAllocator.hpp:17
std::size_t getRemainingCapacity() const noexcept
Definition LinearAllocator.hpp:49
Definition Application.hpp:9