Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
MemoryChunkAllocator.h
Go to the documentation of this file.
1
7
8#pragma once
9#ifndef ECS__MEMORY_CHUNK_ALLOCATOR_H__
10#define ECS__MEMORY_CHUNK_ALLOCATOR_H__
11
12#include "API.h"
14
15#include <shared_mutex>
16
17namespace ECS { namespace Memory {
18
19 template<class OBJECT_TYPE, size_t MAX_CHUNK_OBJECTS>
21 {
22 static const size_t MAX_OBJECTS = MAX_CHUNK_OBJECTS;
23
25 static const size_t ALLOC_SIZE = (sizeof(OBJECT_TYPE) + alignof(OBJECT_TYPE)) * MAX_OBJECTS;
26
27 const char* m_AllocatorTag;
28
29 public:
30
32 using ObjectList = eastl::list<OBJECT_TYPE*>;
33
34
35
46
48 {
49 public:
50
53
56
58 allocator(allocaor)
59 {
60 this->chunkStart = reinterpret_cast<uptr>(allocator->GetMemoryAddress0());
61 this->chunkEnd = this->chunkStart + ALLOC_SIZE;
62 this->objects.clear();
63 }
64
65 }; // class EntityMemoryChunk
66
67 using MemoryChunks = eastl::list<MemoryChunk*>;
68
78
79 class iterator : public eastl::iterator<eastl::forward_iterator_tag, OBJECT_TYPE>
80 {
81 typename MemoryChunks::iterator m_CurrentChunk;
82 typename MemoryChunks::iterator m_End;
83
84 typename ObjectList::iterator m_CurrentObject;
85
86
87 public:
88
89 iterator(typename MemoryChunks::iterator begin, typename MemoryChunks::iterator end) noexcept :
91 m_End(end)
92 {
93 if (begin != end)
94 {
95 assert((*m_CurrentChunk) != nullptr);
96 m_CurrentObject = (*m_CurrentChunk)->objects.begin();
97 }
98 else
99 {
100 m_CurrentObject = (*eastl::prev(m_End))->objects.end();
101 }
102 }
103
104
105 inline iterator& operator++() noexcept
106 {
107 // move to next object in current chunk
109
110 // if we reached end of list, move to next chunk
111 if (m_CurrentObject == (*m_CurrentChunk)->objects.end())
112 {
114
115 if (m_CurrentChunk != m_End)
116 {
117 // set object iterator to begin of next chunk list
118 assert((*m_CurrentChunk) != nullptr);
119 m_CurrentObject = (*m_CurrentChunk)->objects.begin();
120 }
121 }
122
123 return *this;
124 }
125
126 inline OBJECT_TYPE* operator()() const noexcept { return *m_CurrentObject; }
127 inline OBJECT_TYPE& operator*() const noexcept { return *(*m_CurrentObject); }
128 inline OBJECT_TYPE* operator->() const noexcept { return *m_CurrentObject; }
129
130 inline bool operator==(iterator& other) noexcept
131 {
132 return ((this->m_CurrentChunk == other.m_CurrentChunk) && (this->m_CurrentObject == other.m_CurrentObject));
133 }
134 inline bool operator!=(iterator& other) noexcept
135 {
136 return ((this->m_CurrentChunk != other.m_CurrentChunk) && (this->m_CurrentObject != other.m_CurrentObject));
137 }
138
139 }; // ComponentContainer::iterator
140
141 protected:
142
144 std::shared_mutex m_lock;
145
146 public:
147
148
149 MemoryChunkAllocator(const char* allocatorTag = nullptr) noexcept :
150 m_AllocatorTag(allocatorTag)
151 {
152
153 // create initial chunk
154 std::scoped_lock<std::shared_mutex> lock(m_lock);
155 Allocator* allocator = new Allocator(ALLOC_SIZE, Allocate(ALLOC_SIZE, allocatorTag), sizeof(OBJECT_TYPE), alignof(OBJECT_TYPE));
156 this->m_Chunks.push_back(new MemoryChunk(allocator));
157 }
158
160 {
161 std::scoped_lock<std::shared_mutex> lock(m_lock);
162
163 // make sure all entities will be released!
164 for (auto chunk : this->m_Chunks)
165 {
166 for (auto obj : chunk->objects)
167 ((OBJECT_TYPE*)obj)->~OBJECT_TYPE();
168
169 chunk->objects.clear();
170
171 // free allocated allocator memory
172 Free((void*)chunk->allocator->GetMemoryAddress0());
173 delete chunk->allocator;
174 chunk->allocator = nullptr;
175
176 // delete helper chunk object
177 delete chunk;
178 chunk = nullptr;
179 }
180 }
181
193
195 {
196 void* slot = nullptr;
197
198 {
199 std::shared_lock<std::shared_mutex> lock(m_lock);
200 // get next free slot
201 for (auto chunk : this->m_Chunks)
202 {
203 if (chunk->objects.size() > MAX_OBJECTS)
204 continue;
205
206 slot = chunk->allocator->allocate(sizeof(OBJECT_TYPE), alignof(OBJECT_TYPE));
207 if (slot != nullptr)
208 {
209 chunk->objects.push_back((OBJECT_TYPE*)slot);
210 break;
211 }
212 }
213 }
214 // all chunks are full... allocate a new one
215 if (slot == nullptr)
216 {
217 std::scoped_lock<std::shared_mutex> lock(m_lock);
218 Allocator* allocator = new Allocator(ALLOC_SIZE, Allocate(ALLOC_SIZE, this->m_AllocatorTag), sizeof(OBJECT_TYPE), alignof(OBJECT_TYPE));
219 MemoryChunk* newChunk = new MemoryChunk(allocator);
220
221 // put new chunk in front
222 this->m_Chunks.push_front(newChunk);
223
224 slot = newChunk->allocator->allocate(sizeof(OBJECT_TYPE), alignof(OBJECT_TYPE));
225
226 assert(slot != nullptr && "Unable to create new object. Out of memory?!");
227 newChunk->objects.clear();
228 newChunk->objects.push_back((OBJECT_TYPE*)slot);
229 }
230
231 return slot;
232 }
233
246
247 void DestroyObject(void* object)
248 {
249 std::scoped_lock<std::shared_mutex> lock(m_lock);
250 const uptr adr = reinterpret_cast<uptr>(object);
251
252 for (auto chunk : this->m_Chunks)
253 {
254 if (chunk->chunkStart <= adr && adr < chunk->chunkEnd)
255 {
256 // note: no need to call d'tor since it was called already by 'delete'
257
258 const size_t objectCount = chunk->objects.size();
259
260 chunk->objects.remove((OBJECT_TYPE*)object);
261 assert(chunk->objects.size() != objectCount && "Remove failed!");
262 (void*)objectCount;
263
264 chunk->allocator->free(object);
265 return;
266 }
267 }
268
269 assert(false && "Failed to delete object. Memory corruption?!");
270 }
271
272
273 inline iterator begin() noexcept { return iterator(this->m_Chunks.begin(), this->m_Chunks.end()); }
274 inline iterator end() noexcept { return iterator(this->m_Chunks.end(), this->m_Chunks.end()); }
275 inline size_t size() noexcept { return eastl::distance(begin(), end()); }
276
277 }; // MemoryChunkAllocator
278
279}} // namespace ECS::Memory
280
281#endif // ECS__MEMORY_CHUNK_ALLOCATOR_H__
282
const void * GetMemoryAddress0() const
Definition: IAllocator.h:80
virtual void * allocate(size_t size, u8 alignment) override
void Free(void *pMem)
Definition: API.cpp:55
const void * Allocate(size_t memSize, const char *user=nullptr)
Definition: API.cpp:50
iterator(typename MemoryChunks::iterator begin, typename MemoryChunks::iterator end) noexcept
MemoryChunkAllocator(const char *allocatorTag=nullptr) noexcept
eastl::list< OBJECT_TYPE * > ObjectList
eastl::list< MemoryChunk * > MemoryChunks
static const size_t ALLOC_SIZE
Summary: Byte size to fit approx. MAX_CHUNK_OBJECTS objects.
Memory::Allocator::PoolAllocator Allocator
uintptr_t uptr
Definition: Platform.h:64