SDEngine
Game Engine
Loading...
Searching...
No Matches
SparseEntitySet.inl
Go to the documentation of this file.
1// TODO(invariants): Add assertions after mutations:
2// - Add(): assert(denseEntities.size() == denseData.size())
3// - Remove(): assert(denseEntities.size() == denseData.size()) after swap-and-pop
4// - Remove(): assert(sparse[lastPage][lastOffset] == denseIdx) after update
5// - DeserializeFrom(): call ValidateInvariants() at end
6#pragma once
7
8template<typename T>
9template<typename... Args>
11 const usize page = entity.index >> SHIFT;
12 const usize offset = entity.index & MASK;
13
14 if (page >= sparse.size())
15 sparse.resize(page + 1);
16 if (!sparse[page]) {
17 sparse[page] = std::make_unique<usize[]>(PAGE_SIZE);
18 std::fill_n(sparse[page].get(), PAGE_SIZE, std::numeric_limits<usize>::max());
19 }
20
21 usize dense_idx = sparse[page][offset];
22 if (dense_idx != std::numeric_limits<usize>::max()) {
23 dense_data[dense_idx] = T{std::forward<Args>(args)...};
24 dense_entities[dense_idx] = entity;
25 } else {
26 sparse[page][offset] = dense_entities.size(); // end
27 dense_data.push_back(T{std::forward<Args>(args)...});
28 dense_entities.push_back(entity);
29 }
30#ifndef NDEBUG
31 ValidateInvariants();
32#endif
33}
34template<typename T>
36 const usize page = entity.index >> SHIFT;
37 const usize offset = entity.index & MASK;
38
39 if (page >= sparse.size() || !sparse[page])
40 return false; // out of bounds
41
42 usize dense_idx = sparse[page][offset];
43 if (dense_idx == std::numeric_limits<usize>::max())
44 return false; // doesnt exist
45
46 if (dense_entities[dense_idx] != entity)
47 return false; // wrong generation
48
49 // move, last to removed pos
50 usize last_idx = dense_entities.size() - 1;
51 Entity last_entity = dense_entities[last_idx];
52
53 dense_data[dense_idx] = std::move(dense_data[last_idx]);
54 dense_entities[dense_idx] = last_entity;
55
56 // update sparse index
57 const usize last_page = last_entity.index >> SHIFT;
58 const usize last_offset = last_entity.index & MASK;
60
61 // free index
62 sparse[page][offset] = std::numeric_limits<usize>::max();
63
64 // remove duplicated last
65 dense_data.pop_back();
66 dense_entities.pop_back();
67#ifndef NDEBUG
68 ValidateInvariants();
69#endif
70
71 return true;
72}
73template<typename T>
75 const usize page = entity.index >> SHIFT;
76 const usize offset = entity.index & MASK;
77
78 if (page >= sparse.size() || !sparse[page])
79 return nullptr;
80
81 usize dense_idx = sparse[page][offset];
82
83 if (dense_idx == std::numeric_limits<usize>::max())
84 return nullptr; // cant get something that doesnt have data in this component.
86 // Check if the entity is still alive
87 if (dense_entities[dense_idx] != entity)
88 return nullptr;
89
90
91 return &dense_data[dense_idx];
92}
93template<typename T>
94const T* SparseEntitySet<T>::get(const Entity entity) const {
95 const usize page = entity.index >> SHIFT;
96 const usize offset = entity.index & MASK;
97
98 if (page >= sparse.size() || !sparse[page])
99 return nullptr;
100
101 usize dense_idx = sparse[page][offset];
102
103 if (dense_idx == std::numeric_limits<usize>::max())
104 return nullptr;
105
106 if (dense_entities[dense_idx] != entity)
107 return nullptr;
108
109
110 return &dense_data[dense_idx];
111}
112template<typename T>
113std::optional<ComponentDebugInfo> SparseEntitySet<T>::get_debug_info(Entity e) {
115 T* ptr = get(e);
116 if (!ptr)
117 return std::nullopt;
118
120 } else {
121 return std::nullopt; // not a component
122 }
123}
Definition SparseEntitySet.hpp:42
usize size() const
Definition SparseEntitySet.hpp:92
Definition component_registration.hpp:100
Definition component_registration.hpp:71
Definition Entity.hpp:18
constexpr T g_type_max
Definition types.hpp:21
std::size_t usize
Definition types.hpp:18