co_ecs 0.9.0
Cobalt ECS
Loading...
Searching...
No Matches
base_registry.hpp
Go to the documentation of this file.
1#pragma once
2
7#include <co_ecs/entity.hpp>
9
10namespace co_ecs {
11
14public:
17 [[nodiscard]] constexpr entity get_entity() const noexcept {
18 return _ent;
19 }
20
21private:
22 friend class base_registry;
23
24 constexpr placeholder_entity(entity ent) : _ent(ent) {
25 }
26
27 [[nodiscard]] constexpr operator entity() const noexcept {
28 return _ent;
29 }
30
31private:
32 entity _ent;
33};
34
36public:
45 [[nodiscard]] constexpr auto alive(entity ent) const noexcept -> bool {
46 return _entity_pool.alive(ent);
47 }
48
55 void destroy(entity ent) {
56 auto location = get_location(ent);
57
58 // returns the entity that has been moved to a new location
59 auto moved = location.archetype->swap_erase(location);
60 remove_location(ent.id());
61
62 if (moved) {
63 set_location(moved->id(), location);
64 }
65
66 _entity_pool.recycle(ent);
67 }
68
76 [[nodiscard]] constexpr auto archetypes() noexcept -> class archetypes& {
77 return _archetypes;
78 }
79
87 [[nodiscard]] constexpr auto archetypes() const noexcept -> const class archetypes& {
88 return _archetypes;
89 }
90
98 [[nodiscard]] constexpr auto reserve() -> placeholder_entity {
99 return placeholder_entity{ _entity_pool.reserve() };
100 }
101
104 constexpr void sync() {
105 _entity_pool.flush();
106 }
107
112 template<component... C>
113 [[nodiscard]] constexpr auto has(entity ent) const -> bool {
114 const auto& location = get_location(ent);
115 return (location.archetype->template contains<C>() && ...);
116 }
117
121 constexpr void visit(entity ent, auto&& func) {
122 const auto& location = get_location(ent);
123 auto& archetype = *location.archetype;
124 location.archetype->visit(location, std::forward<decltype(func)>(func));
125 }
126
130 constexpr void visit(entity ent, auto&& func) const {
131 const auto& location = get_location(ent);
132 const auto& archetype = *location.archetype;
133 archetype.visit(location, std::forward<decltype(func)>(func));
134 }
135
136protected:
137 friend class entity_ref;
138 friend class const_entity_ref;
139
140 template<component... Components>
141 constexpr auto create_impl(Components&&... args) -> entity {
142 // compile-time check to make sure all component types in parameter pack are unique
143 [[maybe_unused]] detail::unique_types<Components...> uniqueness_check;
144
145 auto entity = allocate();
146 auto archetype = _archetypes.ensure_archetype<Components...>();
147 auto location = archetype->template emplace<Components...>(entity, std::forward<Components>(args)...);
148 set_location(entity.id(), location);
149 return entity;
150 }
151
152 template<component C>
153 constexpr auto set_impl(entity ent) -> std::pair<bool, C*> {
154 auto& location = get_location(ent);
155 auto*& archetype = location.archetype;
156
157 if (archetype->contains<C>()) {
158 return { false, std::addressof(archetype->template get<C>(location)) };
159 } else {
160 auto new_archetype = _archetypes.ensure_archetype_added<C>(archetype);
161 auto [new_location, moved] = archetype->move(location, *new_archetype);
162
163 auto ptr = std::addressof(new_archetype->template get<C>(new_location));
164
165 if (moved) {
166 set_location(moved->id(), location);
167 }
168
169 archetype = new_archetype;
170 set_location(ent.id(), new_location);
171
172 return { true, ptr };
173 }
174 }
175
176 template<component C>
177 constexpr void remove(entity ent) {
178 auto& location = get_location(ent);
179 auto*& archetype = location.archetype;
180
181 if (!archetype->contains<C>()) {
182 return;
183 }
184 auto new_archetype = _archetypes.ensure_archetype_removed<C>(archetype);
185 auto [new_location, moved] = archetype->move(location, *new_archetype);
186 if (moved) {
187 set_location(moved->id(), location);
188 }
189
190 archetype = new_archetype;
191 set_location(ent.id(), new_location);
192 }
193
194 template<component... Args>
195 constexpr static auto get_impl(auto&& self, entity ent) -> decltype(auto) {
196 auto& location = self.get_location(ent);
197
198 constexpr auto is_const = std::is_const_v<std::remove_reference_t<decltype(self)>>;
199 using archetype_t = std::conditional_t<is_const, const archetype, archetype>;
200
201 archetype_t* archetype = location.archetype;
202 return std::forward_as_tuple(archetype->template get<Args>(location)...);
203 }
204
205 [[nodiscard]] constexpr auto allocate() -> entity {
206 return _entity_pool.create();
207 }
208
210 assert((&dest != this) && "Move to the same registry does not make sense");
211 return move(ent, dest, dest.allocate());
212 }
213
214 entity copy(entity ent, base_registry& dest) const {
215 return copy(ent, dest, dest.allocate());
216 }
217
219 auto location = get_location(ent);
220 auto* src_archetype = location.archetype;
221 auto* dst_archetype = dest._archetypes.ensure_archetype(src_archetype->components());
222
223 auto [new_location, moved] = src_archetype->move(location, *dst_archetype);
224
225 remove_location(ent.id());
226 if (moved && moved != ent) { // moved entity has been transfered to a different Registry
227 set_location(moved->id(), location);
228 }
229 _entity_pool.recycle(ent);
230
231 // TODO: handle inside Archetype
232 *dst_archetype
233 ->chunks() // in dst Archetype chunks
234 [new_location.chunk_index] // find the Chunk the entity was moved to
235 .ptr_unchecked<entity>(new_location.entry_index) = placeholder; // update entity value in the Chunk
236
237 dest.set_location(placeholder.get_entity().id(), new_location);
238
239 return placeholder;
240 }
241
242 entity copy(entity ent, base_registry& dest, placeholder_entity placeholder) const {
243 auto location = get_location(ent);
244 auto* src_archetype = location.archetype;
245 auto* dst_archetype = dest._archetypes.ensure_archetype(src_archetype->components());
246 auto new_location = src_archetype->copy(location, *dst_archetype);
247
248 // TODO: handle inside Archetype
249 *dst_archetype
250 ->chunks() // in dst Archetype chunks
251 [new_location.chunk_index] // find the Chunk the EntityId was moved to
252 .ptr_unchecked<entity>(new_location.entry_index) = placeholder; // update EntityId value in the Chunk
253
254 dest.set_location(placeholder.get_entity().id(), new_location);
255
256 return placeholder;
257 }
258
260 return copy(ent, *this, allocate());
261 }
262
264 return copy(ent, *this, placeholder);
265 }
266
267private:
268 constexpr void ensure_alive(const entity& ent) const {
269 if (!alive(ent)) {
270 throw entity_not_found{ ent };
271 }
272 }
273
274 [[nodiscard]] constexpr auto get_location(entity ent) -> entity_location& {
275 ensure_alive(ent);
276 return _entity_archetype_map.at(ent.id());
277 }
278
279 [[nodiscard]] constexpr auto get_location(entity ent) const -> const entity_location& {
280 ensure_alive(ent);
281 return _entity_archetype_map.at(ent.id());
282 }
283
284 constexpr void set_location(typename entity::id_t entity_id, const entity_location& location) {
285 _entity_archetype_map[entity_id] = location;
286 }
287
288 constexpr void remove_location(typename entity::id_t entity_id) {
289 _entity_archetype_map.erase(entity_id);
290 }
291
292protected:
296};
297
298
299} // namespace co_ecs
Archetype groups entities that share the same types of components. Archetype has a list of fixed size...
Definition archetype.hpp:15
auto contains() const noexcept -> bool
Check if archetype has component C.
Definition archetype.hpp:172
archetype()=default
Construct a new archetype object without components.
auto move(const entity_location &location, archetype &other) -> std::pair< entity_location, std::optional< entity > >
Move entity and its components to a different archetype and returns a pair where the first element is...
Definition archetype.hpp:94
void visit(const entity_location &location, auto &&func)
Visit all components of an entity.
Definition archetype.hpp:135
Container for archetypes, holds a map from component set to archetype.
Definition archetype.hpp:292
auto ensure_archetype_removed(const archetype *anchor_archetype) -> archetype *
Get or create an archetype by removing Components from an anchor archetype.
Definition archetype.hpp:359
auto ensure_archetype_added(const archetype *anchor_archetype) -> archetype *
Get or create an archetype by adding new Components to an anchor archetype.
Definition archetype.hpp:340
auto ensure_archetype(const component_meta_set &components) -> archetype *
Get or create an archetype given the component meta set.
Definition archetype.hpp:306
Definition base_registry.hpp:35
constexpr void sync()
Synchronizes concurently reserved entities.
Definition base_registry.hpp:104
constexpr auto create_impl(Components &&... args) -> entity
Definition base_registry.hpp:141
constexpr auto reserve() -> placeholder_entity
Reserves an entity in a thread-safe manner.
Definition base_registry.hpp:98
detail::sparse_map< typename entity::id_t, entity_location > _entity_archetype_map
Definition base_registry.hpp:295
constexpr auto has(entity ent) const -> bool
Checks if the specified entity has all the given components.
Definition base_registry.hpp:113
class archetypes _archetypes
Definition base_registry.hpp:294
constexpr auto alive(entity ent) const noexcept -> bool
Checks if the specified entity is currently active within the registry.
Definition base_registry.hpp:45
void destroy(entity ent)
Destroys the given entity.
Definition base_registry.hpp:55
entity move(entity ent, base_registry &dest)
Definition base_registry.hpp:209
entity move(entity ent, base_registry &dest, placeholder_entity placeholder)
Definition base_registry.hpp:218
static constexpr auto get_impl(auto &&self, entity ent) -> decltype(auto)
Definition base_registry.hpp:195
constexpr void visit(entity ent, auto &&func)
Visit all components of an entity.
Definition base_registry.hpp:121
constexpr auto set_impl(entity ent) -> std::pair< bool, C * >
Definition base_registry.hpp:153
entity copy(entity ent, base_registry &dest, placeholder_entity placeholder) const
Definition base_registry.hpp:242
entity_pool _entity_pool
Definition base_registry.hpp:293
constexpr void visit(entity ent, auto &&func) const
Visit all components of an entity (const variant).
Definition base_registry.hpp:130
entity clone(entity ent)
Definition base_registry.hpp:259
constexpr auto archetypes() const noexcept -> const class archetypes &
Provides access to the immutable list of archetypes in the registry.
Definition base_registry.hpp:87
entity copy(entity ent, base_registry &dest) const
Definition base_registry.hpp:214
constexpr void remove(entity ent)
Definition base_registry.hpp:177
constexpr auto archetypes() noexcept -> class archetypes &
Provides access to the modifiable list of archetypes in the registry.
Definition base_registry.hpp:76
entity clone(entity ent, placeholder_entity placeholder)
Definition base_registry.hpp:263
constexpr auto allocate() -> entity
Definition base_registry.hpp:205
Represents a reference to an entity within a registry.
Definition entity_ref.hpp:355
Exception raised when accessing non existing entity.
Definition exceptions.hpp:13
Represents a reference to an entity within a registry.
Definition entity_ref.hpp:13
Placeholder (reserved) entity.
Definition base_registry.hpp:13
constexpr entity get_entity() const noexcept
Get underlaying entity handle.
Definition base_registry.hpp:17
Component concept. The component must be a struct/class that can be move constructed and move assigna...
Definition component.hpp:86
sparse_table< K, T, true, Allocator > sparse_map
Sparse map.
Definition sparse_map.hpp:12
Definition archetype.hpp:11
detail::handle_pool< entity > entity_pool
Pool of entities that generates and recycles entity IDs.
Definition entity.hpp:16
detail::handle< struct entity_tag_t > entity
Represents an entity, consisting of an ID and generation.
Definition entity.hpp:13