Skip to main content

EntityPool.ixx File

Object pool for efficient Entity management and recycling. More...

Included Headers

#include <memory> #include <unordered_map> #include <vector> #include <cassert> #include <limits> #include <span> #include <cstddef> #include <helios.ecs.types> #include <helios.ecs.types.EntityHandle> #include <helios.engine.util.Guid>

Namespaces Index

namespacehelios
namespaceengine
namespaceruntime
namespacepooling

Classes Index

classEntityPool<THandle>

Object pool for efficient Entity lifecycle management. More...

Description

Object pool for efficient Entity management and recycling.

Provides a memory-efficient pooling mechanism for frequently spawned and despawned Entities, such as projectiles, particles, or enemies. Pre-allocates objects at construction time and reuses them to avoid runtime allocation overhead.

File Listing

The file content with the documentation metadata removed is:

1
9module;
10
11#include <memory>
12#include <unordered_map>
13#include <vector>
14#include <cassert>
15#include <limits>
16#include <span>
17#include <cstddef>
18
19
20export module helios.engine.runtime.pooling.EntityPool;
21
22import helios.engine.util.Guid;
23import helios.ecs.types.EntityHandle;
24import helios.ecs.types;
25
27
28
45 template <typename THandle>
46 class EntityPool {
47
48
49 protected:
50
56 std::vector<size_t> activeIndex_;
57
63 std::vector<size_t> versionIndex_;
64
68 std::vector<THandle> activeEntities_;
69
73 std::vector<THandle> inactiveEntities_;
74
78 size_t poolSize_ = 0;
79
83 helios::ecs::types::EntityId minEntityId_ = std::numeric_limits<helios::ecs::types::EntityId>::max();
84
88 helios::ecs::types::EntityId maxEntityId_ = std::numeric_limits<helios::ecs::types::EntityId>::lowest();
89
93 size_t delta_ = 0;
94
99
103 bool locked_ = false;
104
105 public:
106
107
116 explicit EntityPool(
117 size_t poolSize
118 ) :
120 guid_(helios::engine::util::Guid::generate()) {
123 }
124
125
132 return guid_;
133 }
134
141 return poolSize_;
142 }
143
156
157 if (inactiveEntities_.empty()) {
158 return false;
159 }
160
162 inactiveEntities_.pop_back();
163
164
165 auto idx = entityHandle.entityId - delta_;
166
167 if (activeIndex_.size() <= idx) {
168 activeIndex_.resize(idx + 1, helios::ecs::types::EntityTombstone);
169 versionIndex_.resize(idx + 1, helios::ecs::types::EntityTombstone);
170 }
171
173 versionIndex_[idx] = entityHandle.versionId;
174
176
177 return true;
178 }
179
186 return locked_;
187 }
188
195 void lock() noexcept {
196 locked_ = true;
198 activeIndex_.resize(maxEntityId_ - delta_ + 1, helios::ecs::types::EntityTombstone);
199 versionIndex_.resize(maxEntityId_ - delta_ + 1, helios::ecs::types::EntityTombstone);
200 }
201
213
214 assert(!locked_ && "Pool is locked");
215
216 assert(entityHandle.isValid() && "Unexpected invalid entityHandle");
217
218 const size_t used = (activeCount() + inactiveCount());
219
220 minEntityId_ = std::min(minEntityId_, entityHandle.entityId);
221 maxEntityId_ = std::max(maxEntityId_, entityHandle.entityId);
222
223
224 if (used < size()) {
226 return true;
227 }
228
229 return false;
230 }
231
246
247 assert(entityHandle.isValid() && "Unexpected invalid entityHandle");
248
249 assert(entityHandle.entityId >= delta_ && "Unexpected entityHandle");
250
251 const auto sparseIdx = entityHandle.entityId - delta_;
252
253 assert(sparseIdx < activeIndex_.size() && "Unexpected sparse index");
254
255 const auto denseIndex = activeIndex_[sparseIdx];
256 if (denseIndex == helios::ecs::types::EntityTombstone) {
257 return false;
258 }
259
260 assert(versionIndex_[sparseIdx] == entityHandle.versionId && "Version mismatch");
261
263
264 if (denseIndex != activeEntities_.size() - 1) {
265 // swap the last entityHandle in activeEntities with the
266 // entityHandle to remove, effectively overwriting entityHandle
267 // to release with a currently active entityHandle
271 }
272
273
274 // the swap operation has create a duplicate entry,
275 // remove the one at the tail
276 activeEntities_.pop_back();
277
278 // clear the queried entityHandle from active index and update
279 // inactiveEntities
280 activeIndex_[sparseIdx] = helios::ecs::types::EntityTombstone;
281 versionIndex_[sparseIdx] = helios::ecs::types::EntityTombstone;
282
284
285 return true;
286 }
287
300
301 assert(entityHandle.isValid() && "Unexpected invalid entityHandle");
302
303 const auto sparseIdx = entityHandle.entityId - delta_;
304
305 assert(sparseIdx < activeIndex_.size() && "Unexpected sparse index");
306
307 const auto denseIndex = activeIndex_[sparseIdx];
308
309 if (denseIndex == helios::ecs::types::EntityTombstone) {
310 return false;
311 }
312
313 assert(versionIndex_[sparseIdx] == entityHandle.versionId && "Version mismatch");
314
315 if (denseIndex != activeEntities_.size() - 1) {
316 const auto lastEntityHandle = activeEntities_.back();
320 }
321
322 activeEntities_.pop_back();
323
324 activeIndex_[sparseIdx] = helios::ecs::types::EntityTombstone;
325 versionIndex_[sparseIdx] = helios::ecs::types::EntityTombstone;
326
327 return true;
328
329 }
330
331
338 return activeEntities_.size();
339 }
340
347 return inactiveEntities_.size();
348 }
349
355 std::span<THandle> inactiveEntities() {
356 return inactiveEntities_;
357 };
358
364 std::span<THandle> activeEntities() {
365 return activeEntities_;
366 };
367 };
368
369}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.