FECS
Loading...
Searching...
No Matches
sparse_set.h
Go to the documentation of this file.
1
5
6#pragma once
7#include <fecs/core/types.h>
9#include <cassert>
10#include <array>
11
12namespace FECS
13{
14 namespace Container
15 {
23 {
24 public:
25 virtual ~ISparseSet() = default;
26
31 virtual void Remove(Entity e) = 0;
32
36 virtual void Clear() = 0;
37
43
49 };
50
60 template <typename T>
61 class SparseSet : public ISparseSet
62 {
63 public:
64 SparseSet()
65 {
66 }
67
73 inline void Insert(Entity e, const T& component)
74 {
75 assert(m_EntityManager->IsAlive(e) && "Cannot Assign to Dead Entity");
76 std::uint32_t idx = FECS::GetEntityIndex(e);
77
78 auto& slot = SparseSlot(idx);
79
80 if (slot == NPOS)
81 {
82 // new
83 slot = m_Dense.size();
84 m_DenseEntities.push_back(e);
85 m_Dense.push_back(component);
86 }
87 else
88 {
89 // override
90 m_Dense[slot] = component;
91 }
92 }
93
98 inline virtual void Remove(Entity e) override
99 {
100 assert(m_EntityManager->IsAlive(e) && "Cannot Remove from Dead Entity");
101 std::uint32_t idx = FECS::GetEntityIndex(e);
102
103 auto& slot = SparseSlot(idx);
104 if (slot == NPOS)
105 return;
106
107 std::uint32_t last = m_Dense.size() - 1;
108 if (slot != last)
109 {
110 // Swap with last to maintain compactness
111 m_Dense[slot] = std::move(m_Dense[last]);
112 m_DenseEntities[slot] = m_DenseEntities[last];
113
114 SparseSlot(GetEntityIndex(m_DenseEntities[slot])) = slot;
115 }
116
117 m_Dense.pop_back();
118 m_DenseEntities.pop_back();
119 slot = NPOS;
120 }
121
127 inline bool Has(Entity e) const
128 {
129 uint32_t idx = FECS::GetEntityIndex(e);
130 if (auto* page = PageFor(idx))
131 {
132 return (*page)[GetPageOffset(idx)] != NPOS;
133 }
134
135 return false;
136 }
137
143 inline T& Get(Entity e)
144 {
145 assert(m_EntityManager->IsAlive(e) && "Cannot Get on Dead Entity");
146 assert(Has(e) && "Component not Present");
147 std::uint32_t idx = GetEntityIndex(e);
148 auto* page = PageFor(idx);
149 assert(page && (*page)[GetPageOffset(idx)] != NPOS);
150 return m_Dense[(*page)[GetPageOffset(idx)]];
151 }
152
158 inline const T& Get(Entity e) const
159 {
160 assert(m_EntityManager->IsAlive(e) && "Cannot Get on Dead Entity");
161 assert(Has(e) && "Component not Present");
162 std::uint32_t idx = GetEntityIndex(e);
163 auto* page = PageFor(idx);
164 assert(page && (*page)[GetPageOffset(idx)] != NPOS);
165 return m_Dense[(*page)[GetPageOffset(idx)]];
166 }
167
172 inline std::size_t Size() const
173 {
174 return m_Dense.size();
175 }
176
182 inline Entity EntityAt(std::uint32_t i) const
183 {
184 return m_DenseEntities[i];
185 }
186
191 inline void Reserve(std::size_t amount)
192 {
193 std::uint32_t numPages = (amount + SPARSE_PAGE_SIZE - 1) / SPARSE_PAGE_SIZE;
194
195 if (m_Sparse.size() < numPages)
196 {
197 m_Sparse.resize(numPages, nullptr);
198 }
199
200 for (std::size_t p = 0; p < numPages; ++p)
201 {
202 if (!m_Sparse[p])
203 {
204 m_Sparse[p] = new std::array<std::uint32_t, SPARSE_PAGE_SIZE>();
205 m_Sparse[p]->fill(NPOS);
206 }
207 }
208
209 m_Dense.reserve(amount);
210 m_DenseEntities.reserve(amount);
211 }
212
217 virtual void SetEntityManager(Manager::EntityManager* m) override
218 {
219 m_EntityManager = m;
220 }
221
227 {
228 return m_EntityManager;
229 }
230
234 inline virtual void Clear() override
235 {
236 for (auto page : m_Sparse)
237 {
238 if (page)
239 page->fill(NPOS);
240 }
241 m_Dense.clear();
242 m_DenseEntities.clear();
243 }
244
245 private:
247 std::uint32_t& SparseSlot(std::uint32_t idx)
248 {
249 std::uint32_t p = GetPageIndex(idx);
250 if (p >= m_Sparse.size())
251 {
252 m_Sparse.resize(p + 1, nullptr);
253 }
254
255 if (!m_Sparse[p])
256 {
257 m_Sparse[p] = new std::array<std::uint32_t, SPARSE_PAGE_SIZE>();
258 m_Sparse[p]->fill(NPOS);
259 }
260
261 return (*m_Sparse[p])[GetPageOffset(idx)];
262 }
263
265 inline const std::uint32_t GetPageIndex(std::uint32_t idx) const
266 {
267 return idx / SPARSE_PAGE_SIZE;
268 }
269
271 inline const std::uint32_t GetPageOffset(std::uint32_t idx) const
272 {
273 return idx % SPARSE_PAGE_SIZE;
274 }
275
277 std::array<std::uint32_t, SPARSE_PAGE_SIZE>* PageFor(std::uint32_t idx)
278 {
279 std::uint32_t p = GetPageIndex(idx);
280 if (p >= m_Sparse.size())
281 return nullptr;
282 return m_Sparse[p];
283 }
284
286 const std::array<std::uint32_t, SPARSE_PAGE_SIZE>* PageFor(std::uint32_t idx) const
287 {
288 std::uint32_t p = GetPageIndex(idx);
289 if (p >= m_Sparse.size())
290 return nullptr;
291 return m_Sparse[p];
292 }
293
294 std::vector<T> m_Dense;
295 std::vector<Entity> m_DenseEntities;
296 std::vector<std::array<std::uint32_t, SPARSE_PAGE_SIZE>*> m_Sparse;
297 Manager::EntityManager* m_EntityManager;
298 };
299 }
300}
Interface for type-erased sparse sets.
Definition sparse_set.h:23
virtual Manager::EntityManager * GetEntityManager()=0
Gets the EntityManager associated with this pool.
virtual void Remove(Entity e)=0
Removes the component of a given entity.
virtual void SetEntityManager(Manager::EntityManager *m)=0
Sets the owning EntityManager for the pool.
virtual void Clear()=0
Clears all components in the pool.
virtual void SetEntityManager(Manager::EntityManager *m) override
Assigns the EntityManager used for liveness checks.
Definition sparse_set.h:217
bool Has(Entity e) const
Checks if the entity has a component.
Definition sparse_set.h:127
virtual void Remove(Entity e) override
Removes the component associated with an entity.
Definition sparse_set.h:98
void Reserve(std::size_t amount)
Pre-allocates memory for the given number of components.
Definition sparse_set.h:191
virtual Manager::EntityManager * GetEntityManager() override
Returns the EntityManager associated with this pool.
Definition sparse_set.h:226
Entity EntityAt(std::uint32_t i) const
Returns the entity as a specific index in the dense array.
Definition sparse_set.h:182
const T & Get(Entity e) const
Returns a const reference to the entity's components.
Definition sparse_set.h:158
void Insert(Entity e, const T &component)
Inserts or overrides a component for an entity,.
Definition sparse_set.h:73
virtual void Clear() override
Clears the sparse and dense storage completely.
Definition sparse_set.h:234
std::size_t Size() const
Returns the number of components currently stored.
Definition sparse_set.h:172
T & Get(Entity e)
Returns a mutable reference to the entity's components.
Definition sparse_set.h:143
Manages entity lifecycle, including creation, destruction, and version tracking.
Definition entity_manager.h:21
Defines the EntityManager, which handles creation and destruction of entities.
Defines core types and constants for the FECS ECS system.
std::uint32_t GetEntityIndex(Entity e)
Extracts the index portion from an entity ID.
Definition types.h:73
std::uint32_t Entity
Type alias for entity IDs (32-bit unsigned integer)
Definition types.h:28