Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
archetype.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/assert.hpp>
9
10#include <algorithm>
11#include <cstddef>
12#include <cstdint>
13#include <limits>
14#include <optional>
15#include <span>
16#include <string>
17#include <utility>
18#include <vector>
19
20#ifdef HELIOS_STL_FLAT_MAP_AVAILABLE
21#include <flat_map>
22#else
23#include <boost/container/flat_map.hpp>
24#endif
25
26namespace helios::ecs {
27
28/**
29 * @brief Stores entities and their component data in a Structure-of-Arrays
30 * layout for a specific archetype.
31 * @details An archetype represents a unique combination of component types.
32 * All entities sharing the same set of archetype-storage components are stored
33 * together for cache-friendly iteration.
34 *
35 * Internally maintains:
36 * - A dense entity list for fast iteration
37 * - One `TypedBufferArray` column per component type, indexed by
38 * `ComponentTypeIndex`
39 * - An entity-to-row mapping for O(1) lookup by entity index
40 *
41 * Removal uses swap-and-pop to maintain dense packing without leaving holes.
42 *
43 * Component data migration between archetypes is handled externally by
44 * `ComponentManager`, which uses typed function pointers from
45 * `ComponentMetadata` to avoid virtual calls and raw byte manipulation of
46 * non-trivial types.
47 *
48 * @note Not thread-safe.
49 */
50class Archetype {
51public:
52 using size_type = size_t;
53 using RowIndex = uint32_t;
54
55 static constexpr RowIndex kInvalidRow = std::numeric_limits<RowIndex>::max();
56
57 /**
58 * @brief Constructs an archetype for the given archetype id.
59 * @details Initializes one column per component type in the id.
60 * Columns are created untyped; they will be typed on first insert via
61 * `ComponentManager`.
62 * @param id The archetype id defining which component types this archetype
63 * stores
64 */
65 explicit Archetype(ArchetypeId id);
66 Archetype(const Archetype&) = delete;
67 Archetype(Archetype&&) noexcept = default;
68 ~Archetype() = default;
69
70 Archetype& operator=(const Archetype&) = delete;
71 Archetype& operator=(Archetype&&) noexcept = default;
72
73 /// @brief Removes all entities and component data from this archetype.
74 void Clear();
75
76 /**
77 * @brief Allocates a new row for an entity without initializing component
78 * data.
79 * @details Appends the entity to the entity list and returns the row index.
80 * The caller is responsible for pushing component data into each column
81 * afterwards. This is the primary entry point used by `ComponentManager`
82 * during entity migration.
83 * @warning Triggers assertion if entity is invalid or already present.
84 * @param entity Entity to allocate a row for
85 * @return Row index of the newly allocated row
86 */
88
89 /**
90 * @brief Adds an entity with multiple components.
91 * @warning Triggers assertion in next cases:
92 * - Entity is invalid.
93 * - Entity already exists in this archetype.
94 * - Any component type is not part of this archetype.
95 * @tparam Ts Component types, must be unique and at least 1 type
96 * @param entity Entity to add
97 * @param components Component values
98 * @return Row index of the new entity
99 */
100 template <ComponentTrait... Ts>
101 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
102 RowIndex Add(Entity entity, Ts&&... components);
103
104 /**
105 * @brief Removes an entity from this archetype using swap-and-pop.
106 * @warning Triggers assertion in next cases:
107 * - Entity is invalid.
108 * - Entity is not present in this archetype.
109 * @param entity Entity to remove
110 * @return The entity that was swapped into the removed row, or invalid entity
111 * if the removed entity was last
112 */
113 Entity Remove(Entity entity);
114
115 /**
116 * @brief Sets (overwrites) a component value for an existing entity.
117 * @warning Triggers assertion in next cases:
118 * - Entity is invalid.
119 * - Entity is not present in this archetype.
120 * - Component type is not part of this archetype.
121 * @tparam T Component type
122 * @param entity Entity to modify
123 * @param component New component value
124 */
125 template <ComponentTrait T>
126 void Set(Entity entity, T&& component);
127
128 /**
129 * @brief Emplaces (overwrites) a component for an existing entity.
130 * @warning Triggers assertion in next cases:
131 * - Entity is invalid.
132 * - Entity is not present in this archetype.
133 * - Component type is not part of this archetype.
134 * @tparam T Component type
135 * @tparam Args Constructor argument types
136 * @param entity Entity to modify
137 * @param args Arguments forwarded to component constructor
138 */
139 template <ComponentTrait T, typename... Args>
140 requires std::constructible_from<T, Args...>
141 void Emplace(Entity entity, Args&&... args);
142
143 /**
144 * @brief Gets a mutable reference to a component for an entity.
145 * @warning Triggers assertion in next cases:
146 * - Entity is invalid.
147 * - Entity is not present in this archetype.
148 * - Component type is not part of this archetype.
149 * @tparam T Component type
150 * @param entity Entity to query
151 * @return Mutable reference to component
152 */
153 template <ComponentTrait T>
154 [[nodiscard]] T& Get(Entity entity);
155
156 /**
157 * @brief Gets a const reference to a component for an entity.
158 * @warning Triggers assertion in next cases:
159 * - Entity is invalid.
160 * - Entity is not present in this archetype.
161 * - Component type is not part of this archetype.
162 * @tparam T Component type
163 * @param entity Entity to query
164 * @return Const reference to component
165 */
166 template <ComponentTrait T>
167 [[nodiscard]] const T& Get(Entity entity) const;
168
169 /**
170 * @brief Tries to get a mutable pointer to a component for an entity.
171 * @warning Triggers assertion if entity is invalid.
172 * @tparam T Component type
173 * @param entity Entity to query
174 * @return Pointer to component or `nullptr` if entity or type not found
175 */
176 template <ComponentTrait T>
177 [[nodiscard]] T* TryGet(Entity entity);
178
179 /**
180 * @brief Tries to get a const pointer to a component for an entity.
181 * @warning Triggers assertion if entity is invalid.
182 * @tparam T Component type
183 * @param entity Entity to query
184 * @return Const pointer to component or `nullptr` if entity or type not found
185 */
186 template <ComponentTrait T>
187 [[nodiscard]] const T* TryGet(Entity entity) const;
188
189 /**
190 * @brief Gets a typed span over an entire component column.
191 * @tparam T Component type
192 * @return Span of all component values of this type
193 */
194 template <ComponentTrait T>
195 [[nodiscard]] auto ComponentColumn() -> std::span<T>;
196
197 /**
198 * @brief Gets a const typed span over an entire component column.
199 * @tparam T Component type
200 * @return Const span of all component values of this type
201 */
202 template <ComponentTrait T>
203 [[nodiscard]] auto ComponentColumn() const -> std::span<const T>;
204
205 /**
206 * @brief Gets a raw column by component type index.
207 * @warning Triggers assertion if type index not found.
208 * @param index Component type index
209 * @return Reference to the column
210 */
211 [[nodiscard]] container::TypedBufferArray<>& Column(
212 ComponentTypeIndex index) noexcept;
213
214 /**
215 * @brief Gets a const raw column by component type index.
216 * @warning Triggers assertion if type index not found.
217 * @param index Component type index
218 * @return Const reference to the column
219 */
220 [[nodiscard]] const container::TypedBufferArray<>& Column(
221 ComponentTypeIndex index) const noexcept;
222
223 /**
224 * @brief Tries to get a raw column by component type index.
225 * @param index Component type index
226 * @return Pointer to column or `nullptr` if type index not found
227 */
228 [[nodiscard]] container::TypedBufferArray<>* TryColumn(
229 ComponentTypeIndex index) noexcept;
230
231 /**
232 * @brief Tries to get a const raw column by component type index.
233 * @param index Component type index
234 * @return Const pointer to column or `nullptr` if type index not found
235 */
236 [[nodiscard]] const container::TypedBufferArray<>* TryColumn(
237 ComponentTypeIndex index) const noexcept;
238
239 /**
240 * @brief Gets the row index for an entity.
241 * @warning Triggers assertion if entity is not present.
242 * @param entity Entity to look up
243 * @return Row index
244 */
245 [[nodiscard]] RowIndex Row(Entity entity) const;
246
247 /**
248 * @brief Gets the entity at a given row.
249 * @warning Triggers assertion if row is out of bounds.
250 * @param row Row index
251 * @return Entity at the given row
252 */
253 [[nodiscard]] Entity EntityAt(RowIndex row) const;
254
255 /**
256 * @brief Returns true if no entities are stored.
257 * @return True if the archetype is empty, false otherwise
258 */
259 [[nodiscard]] bool Empty() const noexcept { return entities_.empty(); }
260
261 /**
262 * @brief Checks if the archetype contains the given entity.
263 * @param entity Entity to check
264 * @return True if the entity is stored in this archetype, false otherwise
265 */
266 [[nodiscard]] bool Contains(Entity entity) const noexcept;
267
268 /**
269 * @brief Checks if this archetype has a column for the given component type.
270 * @tparam T Component type
271 * @return True if the archetype stores this component type, false otherwise
272 */
273 template <ComponentTrait T>
274 [[nodiscard]] bool HasColumn() const noexcept {
276 }
277
278 /**
279 * @brief Checks if this archetype has a column for the given component index.
280 * @param index Component type index
281 * @return True if the archetype stores this component type, false otherwise
282 */
283 [[nodiscard]] bool HasColumn(ComponentTypeIndex index) const noexcept {
284 return column_map_.contains(index);
285 }
286
287 /**
288 * @brief Gets the number of entities stored in this archetype.
289 * @return Entity count
290 */
291 [[nodiscard]] size_type EntityCount() const noexcept {
292 return entities_.size();
293 }
294
295 /**
296 * @brief Gets the number of component columns in this archetype.
297 * @return Column count
298 */
299 [[nodiscard]] size_type ColumnCount() const noexcept {
300 return columns_.size();
301 }
302
303 /**
304 * @brief Gets a span of all entities stored in this archetype.
305 * @return Const span of entities
306 */
307 [[nodiscard]] auto Entities() const noexcept -> std::span<const Entity> {
308 return entities_;
309 }
310
311 /**
312 * @brief Gets the archetype id.
313 * @return ArchetypeId of this archetype
314 */
315 [[nodiscard]] const ArchetypeId& Id() const noexcept { return id_; }
316
317private:
318#ifdef HELIOS_STL_FLAT_MAP_AVAILABLE
319 using ColumnMap = std::flat_map<ComponentTypeIndex, size_type>;
320 using EntityRowMap = std::flat_map<Entity::IndexType, RowIndex>;
321#else
322 using ColumnMap =
323 boost::container::flat_map<ComponentTypeIndex, size_type, std::less<>>;
324 using EntityRowMap = boost::container::flat_map<Entity::IndexType, RowIndex>;
325#endif
326
327 [[nodiscard]] auto ColumnIndex(ComponentTypeIndex index) const noexcept
328 -> std::optional<size_type>;
329
330 ArchetypeId id_;
331
332 std::vector<container::TypedBufferArray<>>
333 columns_; ///< One column per component type.
334 ColumnMap column_map_; ///< Maps ComponentTypeIndex -> column vector index.
335
336 std::vector<Entity> entities_; ///< Dense entity array, indexed by row.
337
338 EntityRowMap
339 entity_to_row_; ///< Maps entity index -> row. Sparse by entity index.
340};
341
342inline Archetype::Archetype(ArchetypeId id) : id_(std::move(id)) {
343 const auto types = id_.Types();
344 columns_.resize(types.size());
345 for (size_type i = 0; i < types.size(); ++i) {
346 column_map_.emplace(types[i], i);
347 }
348}
349
350inline void Archetype::Clear() {
351 for (auto& col : columns_) {
352 col.Clear();
353 }
354 entities_.clear();
355 entity_to_row_.clear();
356}
357
358inline auto Archetype::AllocateRow(Entity entity) -> RowIndex {
359 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
360 HELIOS_ASSERT(!Contains(entity), "Entity '{}' already present in archetype!",
361 entity);
362
363 auto row = static_cast<RowIndex>(entities_.size());
364 entities_.push_back(entity);
365 entity_to_row_.emplace(entity.Index(), row);
366 return row;
367}
368
369template <ComponentTrait... Ts>
370 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
371inline auto Archetype::Add(Entity entity, Ts&&... components) -> RowIndex {
372 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
373
374#ifdef HELIOS_ENABLE_ASSERTS
375 const std::array<bool, sizeof...(Ts)> has_column = {
377
378 constexpr std::array<std::string_view, sizeof...(Ts)> names = {
380
381 const bool all_has_column = std::ranges::all_of(has_column, std::identity{});
382 if (!all_has_column) {
383 std::string missing;
384 for (size_t i = 0; i < sizeof...(Ts); ++i) {
385 if (has_column[i]) {
386 continue;
387 }
388 if (!missing.empty()) {
389 missing.append(", ");
390 }
391 missing.append(names[i]);
392 }
393 HELIOS_ASSERT(false, "Components '{}' are not part of this archetype!",
394 missing);
395 }
396#endif
397
398 auto row = AllocateRow(entity);
399
400 // Push each component into its respective column.
401 (columns_[column_map_.at(ComponentTypeIndex::From<std::remove_cvref_t<Ts>>())]
402 .PushBack(std::forward<Ts>(components)),
403 ...);
404
405 return row;
406}
407
409 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
410 HELIOS_ASSERT(Contains(entity), "Entity '{}' not present in archetype!",
411 entity);
412
413 const RowIndex row = entity_to_row_.at(entity.Index());
414 const auto last_row = static_cast<RowIndex>(entities_.size() - 1);
415 Entity swapped_entity;
416
417 if (row != last_row) {
418 swapped_entity = entities_[last_row];
419 // Swap entity in dense list.
420 entities_[row] = swapped_entity;
421 entity_to_row_[swapped_entity.Index()] = row;
422
423 // Swap component data in every column.
424 for (auto& col : columns_) {
425 if (!col.Empty()) {
426 col.Swap(static_cast<size_type>(row), static_cast<size_type>(last_row));
427 }
428 }
429 }
430
431 // Pop back.
432 entities_.pop_back();
433 entity_to_row_.erase(entity.Index());
434
435 for (auto& col : columns_) {
436 if (!col.Empty()) {
437 col.PopBack();
438 }
439 }
440
441 return swapped_entity;
442}
443
444template <ComponentTrait T>
445inline void Archetype::Set(Entity entity, T&& component) {
446 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
447 HELIOS_ASSERT(Contains(entity), "Entity '{}' not present in archetype!",
448 entity);
449
450 using DecayedT = std::remove_cvref_t<T>;
451 constexpr auto type_index = ComponentTypeIndex::From<DecayedT>();
452
453 HELIOS_ASSERT(HasColumn(type_index),
454 "Component '{}' is not part of this archetype!",
456
457 auto& col = columns_[column_map_.at(type_index)];
458 const size_type row =
459 static_cast<size_type>(entity_to_row_.at(entity.Index()));
460
461 HELIOS_ASSERT(row <= col.Size(),
462 "Inconsistent archetype state for component '{}': row '{}' is "
463 "out of bounds for column size '{}'!",
464 ComponentNameOf<DecayedT>(), row, col.Size());
465
466 if (row == col.Size()) {
467 col.PushBack(std::forward<T>(component));
468 return;
469 }
470
471 col.template At<DecayedT>(row) = std::forward<T>(component);
472}
473
474template <ComponentTrait T, typename... Args>
475 requires std::constructible_from<T, Args...>
476inline void Archetype::Emplace(Entity entity, Args&&... args) {
477 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
478 HELIOS_ASSERT(Contains(entity), "Entity '{}' not present in archetype!",
479 entity);
480
481 using DecayedT = std::remove_cvref_t<T>;
482 constexpr auto type_index = ComponentTypeIndex::From<DecayedT>();
483
484 HELIOS_ASSERT(HasColumn(type_index),
485 "Component '{}' is not part of this archetype!",
487
488 auto& col = columns_[column_map_.at(type_index)];
489 const size_type row =
490 static_cast<size_type>(entity_to_row_.at(entity.Index()));
491
492 HELIOS_ASSERT(row <= col.Size(),
493 "Inconsistent archetype state for component '{}': row '{}' is "
494 "out of bounds for column size '{}'!",
495 ComponentNameOf<DecayedT>(), row, col.Size());
496
497 if (row == col.Size()) {
498 col.template EmplaceBack<DecayedT>(std::forward<Args>(args)...);
499 return;
500 }
501
502 auto& slot = col.template At<DecayedT>(row);
503
504 std::destroy_at(&slot);
505 std::construct_at(&slot, std::forward<Args>(args)...);
506}
507
508template <ComponentTrait T>
509inline T& Archetype::Get(Entity entity) {
510 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
511 HELIOS_ASSERT(Contains(entity), "Entity '{}' not present in archetype!",
512 entity);
513
514 constexpr auto type_index = ComponentTypeIndex::From<T>();
515 HELIOS_ASSERT(HasColumn(type_index),
516 "Component '{}' is not part of this archetype!",
518
519 auto& col = columns_[column_map_.at(type_index)];
520 const RowIndex row = entity_to_row_.at(entity.Index());
521 return col.template At<T>(static_cast<size_type>(row));
522}
523
524template <ComponentTrait T>
525inline const T& Archetype::Get(Entity entity) const {
526 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
527 HELIOS_ASSERT(Contains(entity), "Entity '{}' not present in archetype!",
528 entity);
529
530 constexpr auto type_index = ComponentTypeIndex::From<T>();
531 HELIOS_ASSERT(HasColumn(type_index),
532 "Component '{}' is not part of this archetype!",
534
535 const auto& col = columns_[column_map_.at(type_index)];
536 const RowIndex row = entity_to_row_.at(entity.Index());
537 return col.template At<T>(static_cast<size_type>(row));
538}
539
540template <ComponentTrait T>
541inline T* Archetype::TryGet(Entity entity) {
542 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
543
544 if (!Contains(entity)) {
545 return nullptr;
546 }
547
548 constexpr auto type_index = ComponentTypeIndex::From<T>();
549 const auto col_idx = ColumnIndex(type_index);
550 if (!col_idx.has_value()) {
551 return nullptr;
552 }
553
554 const size_type col_index = col_idx.value();
555 const RowIndex row = entity_to_row_.at(entity.Index());
556 return &columns_[col_index].template At<T>(static_cast<size_type>(row));
557}
558
559template <ComponentTrait T>
560inline const T* Archetype::TryGet(Entity entity) const {
561 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
562
563 if (!Contains(entity)) {
564 return nullptr;
565 }
566
567 constexpr auto type_index = ComponentTypeIndex::From<T>();
568 const auto col_idx = ColumnIndex(type_index);
569 if (!col_idx.has_value()) {
570 return nullptr;
571 }
572
573 const size_type col_index = col_idx.value();
574 const RowIndex row = entity_to_row_.at(entity.Index());
575 return &columns_[col_index].template At<T>(static_cast<size_type>(row));
576}
577
578template <ComponentTrait T>
579inline auto Archetype::ComponentColumn() -> std::span<T> {
580 constexpr auto type_index = ComponentTypeIndex::From<T>();
581
582 const auto col_idx = ColumnIndex(type_index);
583 if (!col_idx.has_value()) {
584 return {};
585 }
586
587 auto& col = columns_[col_idx.value()];
588 return col.template Data<T>();
589}
590
591template <ComponentTrait T>
592inline auto Archetype::ComponentColumn() const -> std::span<const T> {
593 constexpr auto type_index = ComponentTypeIndex::From<T>();
594
595 const auto col_idx = ColumnIndex(type_index);
596 if (!col_idx.has_value()) {
597 return {};
598 }
599
600 const auto& col = columns_[col_idx.value()];
601 return col.template Data<T>();
602}
603
604inline auto Archetype::Column(ComponentTypeIndex index) noexcept
606 const auto col_idx = ColumnIndex(index);
607 HELIOS_ASSERT(col_idx.has_value(),
608 "Component index '{}' is not part of this archetype!",
609 static_cast<size_t>(index));
610 return columns_[col_idx.value()];
611}
612
613inline auto Archetype::Column(ComponentTypeIndex index) const noexcept
615 const auto col_idx = ColumnIndex(index);
616 HELIOS_ASSERT(col_idx.has_value(),
617 "Component index '{}' is not part of this archetype!",
618 static_cast<size_t>(index));
619 return columns_[col_idx.value()];
620}
621
622inline auto Archetype::TryColumn(ComponentTypeIndex index) noexcept
624 const auto col_idx = ColumnIndex(index);
625 if (!col_idx.has_value()) {
626 return nullptr;
627 }
628 return &columns_[col_idx.value()];
629}
630
631inline auto Archetype::TryColumn(ComponentTypeIndex index) const noexcept
633 const auto col_idx = ColumnIndex(index);
634 if (!col_idx.has_value()) {
635 return nullptr;
636 }
637 return &columns_[col_idx.value()];
638}
639
640inline auto Archetype::Row(Entity entity) const -> RowIndex {
641 HELIOS_ASSERT(Contains(entity), "Entity '{}' not present in archetype!",
642 entity);
643 return entity_to_row_.at(entity.Index());
644}
645
647 HELIOS_ASSERT(static_cast<size_type>(row) < entities_.size(),
648 "Row index '{}' out of bounds (size: {})!",
649 static_cast<size_type>(row), entities_.size());
650 return entities_[static_cast<size_type>(row)];
651}
652
653inline bool Archetype::Contains(Entity entity) const noexcept {
654 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
655 return entity_to_row_.contains(entity.Index());
656}
657
658inline auto Archetype::ColumnIndex(ComponentTypeIndex index) const noexcept
659 -> std::optional<size_type> {
660 const auto it = column_map_.find(index);
661 if (it == column_map_.end()) {
662 return std::nullopt;
663 }
664 return it->second;
665}
666
667} // namespace helios::ecs
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:259
Type-erased sequential byte storage for a single type (array variant).
Unique identifier for an archetype, represented as a sorted set of component type indices.
bool HasColumn(ComponentTypeIndex index) const noexcept
Checks if this archetype has a column for the given component index.
Archetype(const Archetype &)=delete
void Clear()
Removes all entities and component data from this archetype.
Archetype(Archetype &&) noexcept=default
T & Get(Entity entity)
Gets a mutable reference to a component for an entity.
auto Entities() const noexcept -> std::span< const Entity >
Gets a span of all entities stored in this archetype.
RowIndex Row(Entity entity) const
Gets the row index for an entity.
void Set(Entity entity, T &&component)
Sets (overwrites) a component value for an existing entity.
size_type EntityCount() const noexcept
Gets the number of entities stored in this archetype.
RowIndex Add(Entity entity, Ts &&... components)
Adds an entity with multiple components.
auto ComponentColumn() -> std::span< T >
Gets a typed span over an entire component column.
container::TypedBufferArray & Column(ComponentTypeIndex index) noexcept
Gets a raw column by component type index.
RowIndex AllocateRow(Entity entity)
Allocates a new row for an entity without initializing component data.
void Emplace(Entity entity, Args &&... args)
Emplaces (overwrites) a component for an existing entity.
const ArchetypeId & Id() const noexcept
Gets the archetype id.
bool Empty() const noexcept
Returns true if no entities are stored.
bool HasColumn() const noexcept
Checks if this archetype has a column for the given component type.
container::TypedBufferArray * TryColumn(ComponentTypeIndex index) noexcept
Tries to get a raw column by component type index.
Entity EntityAt(RowIndex row) const
Gets the entity at a given row.
bool Contains(Entity entity) const noexcept
Checks if the archetype contains the given entity.
size_type ColumnCount() const noexcept
Gets the number of component columns in this archetype.
static constexpr RowIndex kInvalidRow
Definition archetype.hpp:55
Archetype(ArchetypeId id)
Constructs an archetype for the given archetype id.
T * TryGet(Entity entity)
Tries to get a mutable pointer to a component for an entity.
Entity Remove(Entity entity)
Removes an entity from this archetype using swap-and-pop.
Unique identifier for entities with generation counter to handle recycling.
Definition entity.hpp:22
constexpr bool Valid() const noexcept
Checks if the entity is valid.
Definition entity.hpp:64
constexpr IndexType Index() const noexcept
Gets the index component of the entity.
Definition entity.hpp:82
static constexpr TypeIndex From() noexcept
Constructs a TypeIndex from a type T.
Concept to check if a type can be used as a component.
Definition component.hpp:31
Concept that checks if all types in a pack are unique (after removing cv/ref qualifiers).
constexpr std::string_view ComponentNameOf() noexcept
Component name for debugging and serialization.
Definition component.hpp:76
utils::TypeIndex ComponentTypeIndex
Type index for components.
Definition component.hpp:14
STL namespace.