Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
entity.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5#include <format>
6#include <limits>
7
8namespace helios::ecs {
9
10/**
11 * @brief Unique identifier for entities with generation counter to handle
12 * recycling.
13 * @details Entity uses a combination of index and generation to provide stable
14 * references even when entities are destroyed and their indices are recycled.
15 * The generation counter ensures that old entity references become invalid when
16 * the index is reused.
17 *
18 * Memory layout: 32-bit index + 32-bit generation = 64-bit total
19 *
20 * @note This class is thread-safe for all operations.
21 */
22class Entity {
23public:
24 using IndexType = uint32_t;
25 using GenerationType = uint32_t;
26
27 static constexpr IndexType kInvalidIndex =
28 std::numeric_limits<IndexType>::max();
30 std::numeric_limits<GenerationType>::max();
31
32 /**
33 * @brief Constructs an invalid entity.
34 * @details Creates an entity with invalid index and generation values.
35 */
36 constexpr Entity() noexcept = default;
37
38 /**
39 * @brief Constructs entity with specific index and generation.
40 * @details Private constructor used by entity manager to create valid
41 * entities.
42 * @param index The entity index
43 * @param generation The entity generation
44 */
45 constexpr Entity(IndexType index, GenerationType generation) noexcept
46 : index_(index), generation_(generation) {}
47 constexpr Entity(const Entity&) noexcept = default;
48 constexpr Entity(Entity&&) noexcept = default;
49 constexpr ~Entity() noexcept = default;
50
51 constexpr Entity& operator=(const Entity&) noexcept = default;
52 constexpr Entity& operator=(Entity&&) noexcept = default;
53
54 constexpr bool operator==(const Entity&) const noexcept = default;
55 constexpr bool operator!=(const Entity&) const noexcept = default;
56 constexpr bool operator<(const Entity& other) const noexcept;
57
58 /**
59 * @brief Checks if the entity is valid.
60 * @details An entity is valid if both its index and generation are not the
61 * reserved invalid values.
62 * @return True if entity has valid index and generation, false otherwise
63 */
64 [[nodiscard]] constexpr bool Valid() const noexcept {
65 return index_ != kInvalidIndex && generation_ != kInvalidGeneration;
66 }
67
68 /**
69 * @brief Generates a hash value for this entity.
70 * @details Combines index and generation into a 64-bit hash value.
71 * Invalid entities always return hash value of 0.
72 * @return Hash combining generation (high bits) and index (low bits)
73 */
74 [[nodiscard]] constexpr size_t Hash() const noexcept;
75
76 /**
77 * @brief Gets the index component of the entity.
78 * @details The index identifies the entity's storage location in sparse
79 * arrays.
80 * @return Entity index, or `kInvalidIndex` if entity is invalid
81 */
82 [[nodiscard]] constexpr IndexType Index() const noexcept { return index_; }
83
84 /**
85 * @brief Gets the generation component of the entity.
86 * @details The generation counter prevents use of stale entity references
87 * after recycling.
88 * @return Entity generation, or `kInvalidGeneration` if entity is invalid
89 */
90 [[nodiscard]] constexpr GenerationType Generation() const noexcept {
91 return generation_;
92 }
93
94private:
95 IndexType index_ = kInvalidIndex; ///< Entity index for storage lookup
96 GenerationType generation_ =
97 kInvalidGeneration; ///< Generation counter for recycling safety
98};
99
100constexpr bool Entity::operator<(const Entity& other) const noexcept {
101 if (index_ != other.index_) {
102 return index_ < other.index_;
103 }
104 return generation_ < other.generation_;
105}
106
107constexpr size_t Entity::Hash() const noexcept {
108 if (!Valid()) [[unlikely]] {
109 return 0;
110 }
111
112 auto hash = static_cast<size_t>(index_);
113 hash ^= static_cast<size_t>(generation_) +
114 static_cast<size_t>(0x9e3779b97f4a7c15ULL) + (hash << 6) +
115 (hash >> 2);
116 return hash == 0 ? 1 : hash;
117}
118
119} // namespace helios::ecs
120
121namespace std {
122
123template <>
124struct formatter<helios::ecs::Entity> {
125 static constexpr auto parse(std::format_parse_context& ctx) noexcept {
126 return ctx.begin();
127 }
128
129 static constexpr auto format(const helios::ecs::Entity& entity,
130 format_context& ctx) {
131 return format_to(ctx.out(), "Entity{{index: {}, generation: {}}}",
132 entity.Index(), entity.Generation());
133 }
134};
135
136template <>
137struct hash<helios::ecs::Entity> {
138 constexpr size_t operator()(helios::ecs::Entity entity) const noexcept {
139 return entity.Hash();
140 }
141};
142
143} // namespace std
Unique identifier for entities with generation counter to handle recycling.
Definition entity.hpp:22
constexpr bool operator<(const Entity &other) const noexcept
Definition entity.hpp:100
constexpr bool Valid() const noexcept
Checks if the entity is valid.
Definition entity.hpp:64
uint32_t IndexType
Definition entity.hpp:24
constexpr GenerationType Generation() const noexcept
Gets the generation component of the entity.
Definition entity.hpp:90
uint32_t GenerationType
Definition entity.hpp:25
constexpr Entity(const Entity &) noexcept=default
constexpr Entity() noexcept=default
Constructs an invalid entity.
static constexpr GenerationType kInvalidGeneration
Definition entity.hpp:29
constexpr IndexType Index() const noexcept
Gets the index component of the entity.
Definition entity.hpp:82
constexpr Entity(Entity &&) noexcept=default
constexpr size_t Hash() const noexcept
Generates a hash value for this entity.
Definition entity.hpp:107
static constexpr IndexType kInvalidIndex
Definition entity.hpp:27
STL namespace.
static constexpr auto format(const helios::ecs::Entity &entity, format_context &ctx)
Definition entity.hpp:129
static constexpr auto parse(std::format_parse_context &ctx) noexcept
Definition entity.hpp:125
constexpr size_t operator()(helios::ecs::Entity entity) const noexcept
Definition entity.hpp:138