Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
entity_buffer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/assert.hpp>
9
10#include <concepts>
11#include <memory_resource>
12#include <type_traits>
13
14namespace helios::ecs {
15
16/**
17 * @brief Command buffer for deferred entity operations.
18 * @details Collects commands and then pushes them into a queue.
19 * Commands are enqueued in the order they were added, ensuring predictable
20 * behavior.
21 * @note Not thread-safe.
22 * @tparam Allocator Allocator type for command storage (default:
23 * `std::allocator<std::byte>`)
24 */
25template <typename Allocator = std::allocator<std::byte>>
27public:
30
31 /**
32 * @brief Constructs aa entity command buffer with a custom allocator.
33 * @warning Triggers assertion if entity is invalid.
34 * @param entity Entity associated with this buffer
35 * @param queue Queue to push commands into
36 * @param allocator Allocator instance
37 */
38 constexpr EntityCmdBuffer(Entity entity, CmdQueue<Allocator>& queue,
39 allocator_type allocator = allocator_type{});
40
41 /**
42 * @brief Constructs an entity command buffer from a PMR memory resource.
43 * @details Enabled only when `allocator_type` is constructible from
44 * `std::pmr::memory_resource*`.
45 * @param entity Entity associated with this buffer
46 * @param queue Queue to push commands into
47 * @param resource Memory resource used to construct allocator
48 */
49 constexpr EntityCmdBuffer(Entity entity, CmdQueue<Allocator>& queue,
50 std::pmr::memory_resource* resource)
51 requires std::constructible_from<allocator_type, std::pmr::memory_resource*>
52 : EntityCmdBuffer(entity, queue, allocator_type{resource}) {}
53
55 std::nullptr_t) = delete;
56
59 ~EntityCmdBuffer() { queue_.Merge(std::move(commands_)); }
60
63
64 /**
65 * @brief Clears all pending commands from the buffer.
66 * @details Removes all commands currently in the buffer.
67 */
68 void Clear() noexcept { commands_.Clear(); }
69
70 /**
71 * @brief Reserves capacity for commands.
72 * @details Pre-allocates memory to avoid reallocations during enqueue
73 * operations.
74 * @param capacity Number of commands to reserve space for
75 */
76 constexpr void Reserve(size_type capacity) { commands_.Reserve(capacity); }
77
78 /**
79 * @brief Enqueues a command to destroy entity and removes it from the world.
80 * @note Not thread-safe.
81 * @warning Triggers assertion in next cases:
82 * - Entity is invalid.
83 * - World does not own entity.
84 */
85 auto Destroy(this auto&& self)
86 -> decltype(std::forward<decltype(self)>(self));
87
88 /**
89 * @brief Enqueues a command to try destroy entity if it exists in the world.
90 * @note Not thread-safe.
91 * @warning Triggers assertion if entity is invalid.
92 */
93 auto TryDestroy(this auto&& self)
94 -> decltype(std::forward<decltype(self)>(self));
95
96 /**
97 * @brief Enqueues a command to add components to the entity.
98 * @details If entity already has component of provided type then it will be
99 * replaced.
100 * @note Not thread-safe.
101 * @warning Triggers assertion in next cases:
102 * - Entity is invalid.
103 * - World does not own entity.
104 * @tparam Ts Components types to add
105 * @param components Components to add
106 */
107 template <ComponentTrait... Ts>
108 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
109 auto AddComponents(this auto&& self, Ts&&... components)
110 -> decltype(std::forward<decltype(self)>(self));
111
112 /**
113 * @brief Enqueues a command to try to add components to the entity if they
114 * don't exist.
115 * @note Not thread-safe.
116 * @warning Triggers assertion in next cases:
117 * - Entity is invalid.
118 * - World does not own entity.
119 * @tparam Ts Components types to add
120 * @param components Components to add
121 */
122 template <ComponentTrait... Ts>
123 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
124 auto TryAddComponents(this auto&& self, Ts&&... components)
125 -> decltype(std::forward<decltype(self)>(self));
126
127 /**
128 * @brief Enqueues a command to remove components from the entity.
129 * @note Not thread-safe.
130 * @warning Triggers assertion in next cases:
131 * - Entity is invalid.
132 * - World does not own entity.
133 * - Entity does not have any of the components.
134 * @tparam Ts Components types to remove
135 */
136 template <ComponentTrait... Ts>
137 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
138 auto RemoveComponents(this auto&& self)
139 -> decltype(std::forward<decltype(self)>(self));
140
141 /**
142 * @brief Enqueues a command to try to remove components from the entity if
143 * they exist.
144 * @note Not thread-safe.
145 * @warning Triggers assertion in next cases:
146 * - Entity is invalid.
147 * - World does not own entity.
148 * @tparam Ts Components types to remove
149 */
150 template <ComponentTrait... Ts>
151 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
152 auto TryRemoveComponents(this auto&& self)
153 -> decltype(std::forward<decltype(self)>(self));
154
155 /**
156 * @brief Enqueues a command to remove all components from the entity.
157 * @note Not thread-safe.
158 * @warning Triggers assertion in next cases:
159 * - Entity is invalid.
160 * - World does not own entity.
161 */
162 auto ClearComponents(this auto&& self)
163 -> decltype(std::forward<decltype(self)>(self));
164
165 /**
166 * @brief Checks if the buffer is empty.
167 * @return True if buffer is empty, false otherwise
168 */
169 [[nodiscard]] constexpr bool Empty() const noexcept {
170 return commands_.Empty();
171 }
172
173 /**
174 * @brief Gets the entity associated with this buffer.
175 * @return Entity instance
176 */
177 [[nodiscard]] constexpr Entity GetEntity() const noexcept { return entity_; }
178
179 /**
180 * @brief Gets the number of commands in the buffer.
181 * @return Number of commands in buffer
182 */
183 [[nodiscard]] constexpr size_type Size() const noexcept {
184 return commands_.Size();
185 }
186
187 /**
188 * @brief Gets the allocator used by the command storage.
189 * @return Allocator instance
190 */
191 [[nodiscard]] constexpr allocator_type GetAllocator() const
192 noexcept(std::is_nothrow_copy_constructible_v<allocator_type>) {
193 return commands_.GetAllocator();
194 }
195
196private:
197 Entity entity_;
198 CmdQueue<Allocator> commands_;
199 CmdQueue<Allocator>& queue_;
200};
201
202template <typename Allocator>
204 Entity entity, CmdQueue<Allocator>& queue, allocator_type allocator)
205 : entity_(entity), commands_(allocator), queue_(queue) {
206 HELIOS_ASSERT(entity_.Valid(), "Entity '{}' is not valid!", entity_);
207}
208
209template <typename Allocator>
210inline auto EntityCmdBuffer<Allocator>::Destroy(this auto&& self)
211 -> decltype(std::forward<decltype(self)>(self)) {
212 self.commands_.Enqueue(DestroyEntityCmd(self.entity_));
213 return std::forward<decltype(self)>(self);
214}
215
216template <typename Allocator>
217inline auto EntityCmdBuffer<Allocator>::TryDestroy(this auto&& self)
218 -> decltype(std::forward<decltype(self)>(self)) {
219 self.commands_.Enqueue(TryDestroyEntityCmd(self.entity_));
220 return std::forward<decltype(self)>(self);
221}
222
223template <typename Allocator>
224template <ComponentTrait... Ts>
225 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
226inline auto EntityCmdBuffer<Allocator>::AddComponents(this auto&& self,
227 Ts&&... components)
228 -> decltype(std::forward<decltype(self)>(self)) {
229 self.commands_.Enqueue(
230 AddComponentsCmd(self.entity_, std::forward<Ts>(components)...));
231 return std::forward<decltype(self)>(self);
232}
233
234template <typename Allocator>
235template <ComponentTrait... Ts>
236 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
238 Ts&&... components)
239 -> decltype(std::forward<decltype(self)>(self)) {
240 self.commands_.Enqueue(
241 TryAddComponentsCmd(self.entity_, std::forward<Ts>(components)...));
242 return std::forward<decltype(self)>(self);
243}
244
245template <typename Allocator>
246template <ComponentTrait... Ts>
247 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
249 -> decltype(std::forward<decltype(self)>(self)) {
250 self.commands_.Enqueue(RemoveComponentsCmd<Ts...>(self.entity_));
251 return std::forward<decltype(self)>(self);
252}
253
254template <typename Allocator>
255template <ComponentTrait... Ts>
256 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
258 -> decltype(std::forward<decltype(self)>(self)) {
259 self.commands_.Enqueue(TryRemoveComponentsCmd<Ts...>(self.entity_));
260 return std::forward<decltype(self)>(self);
261}
262
263template <typename Allocator>
265 -> decltype(std::forward<decltype(self)>(self)) {
266 self.commands_.Enqueue(ClearComponentsCmd(self.entity_));
267 return std::forward<decltype(self)>(self);
268}
269
270/**
271 * @brief Command buffer for deferred entity operations that uses a polymorphic
272 * allocator.
273 * @details Collects commands and then pushes them into a queue.
274 * Commands are enqueued in the order they were added, ensuring predictable
275 * behavior.
276 * @note Not thread-safe.
277 * @tparam Allocator Allocator type for command storage (default:
278 * `std::allocator<std::byte>`)
279 */
282
283} // namespace helios::ecs
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:259
Command to clear all components from an entity.
Command queue for deferred ECS operations.
Definition queue.hpp:26
CommandStorage::size_type size_type
Definition queue.hpp:32
CommandStorage::allocator_type allocator_type
Definition queue.hpp:33
Command to destroy a single entity.
Command buffer for deferred entity operations.
constexpr size_type Size() const noexcept
Gets the number of commands in the buffer.
auto AddComponents(this auto &&self, Ts &&... components) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to add components to the entity.
constexpr bool Empty() const noexcept
Checks if the buffer is empty.
auto ClearComponents(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to remove all components from the entity.
constexpr Entity GetEntity() const noexcept
Gets the entity associated with this buffer.
EntityCmdBuffer(EntityCmdBuffer &&)=delete
constexpr EntityCmdBuffer(Entity entity, CmdQueue< Allocator > &queue, std::pmr::memory_resource *resource)
Constructs an entity command buffer from a PMR memory resource.
CmdQueue< Allocator >::size_type size_type
EntityCmdBuffer & operator=(const EntityCmdBuffer &)=delete
auto TryDestroy(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to try destroy entity if it exists in the world.
auto Destroy(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to destroy entity and removes it from the world.
auto RemoveComponents(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to remove components from the entity.
EntityCmdBuffer(const EntityCmdBuffer &)=delete
constexpr EntityCmdBuffer(Entity entity, CmdQueue< Allocator > &queue, allocator_type allocator=allocator_type{})
Constructs aa entity command buffer with a custom allocator.
constexpr void Reserve(size_type capacity)
Reserves capacity for commands.
auto TryAddComponents(this auto &&self, Ts &&... components) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to try to add components to the entity if they don't exist.
void Clear() noexcept
Clears all pending commands from the buffer.
EntityCmdBuffer(Entity entity, CmdQueue< Allocator > &queue, std::nullptr_t)=delete
CmdQueue< Allocator >::allocator_type allocator_type
constexpr allocator_type GetAllocator() const noexcept(std::is_nothrow_copy_constructible_v< allocator_type >)
Gets the allocator used by the command storage.
EntityCmdBuffer & operator=(EntityCmdBuffer &&)=delete
auto TryRemoveComponents(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Enqueues a command to try to remove components from the entity if they exist.
Unique identifier for entities with generation counter to handle recycling.
Definition entity.hpp:22
Command to remove multiple components from an entity.
Command to try destroy a single entity.
Command to try remove multiple components (only those present).
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).
AddComponentsCmd(Entity, Us &&...) -> AddComponentsCmd< std::remove_cvref_t< Us >... >
EntityCmdBuffer< std::pmr::polymorphic_allocator< std::byte > > PmrEntityCmdBuffer
Command buffer for deferred entity operations that uses a polymorphic allocator.
TryAddComponentsCmd(Entity, Us &&...) -> TryAddComponentsCmd< std::remove_cvref_t< Us >... >
STL namespace.