Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
event_queue.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/core_pch.hpp>
4
9
10#include <algorithm>
11#include <cstddef>
12#include <iterator>
13#include <ranges>
14#include <span>
15#include <unordered_map>
16#include <utility>
17
18namespace helios::ecs::details {
19
20/**
21 * @brief Queue for managing multiple event types.
22 * @details Uses an unordered_map to store EventStorage for each event type,
23 * allowing efficient type-based event management.
24 * Events can be written and read in batches for better performance.
25 * @note Not thread-safe.
26 */
28public:
29 EventQueue() = default;
30 EventQueue(const EventQueue&) = delete;
33
36
37 /**
38 * @brief Registers an event type with the queue.
39 * @tparam T Event type
40 */
42 void Register();
43
44 /**
45 * @brief Clears all events from the queue and removes registrations.
46 */
47 void Clear() noexcept { storages_.clear(); }
48
49 /**
50 * @brief Clears all event data but preserves registrations.
51 * @details Use this when you want to clear events without losing type registrations.
52 */
53 void ClearData() noexcept;
54
55 /**
56 * @brief Clears events of a specific type.
57 * @warning Triggers assertion if event type is not registered.
58 * @tparam T Event type
59 */
61 void Clear();
62
63 /**
64 * @brief Clears events of a specific type by type ID (runtime).
65 * @warning Triggers assertion if event type does not exist.
66 * @param type_id Type identifier of events to clear
67 */
68 void ClearByTypeId(EventTypeId type_id);
69
70 /**
71 * @brief Merges events from another EventQueue into this one.
72 * @param other EventQueue to merge from
73 */
74 void Merge(EventQueue& other);
75
76 /**
77 * @brief Writes a single event to the queue.
78 * @warning Triggers assertion if event type is not registered.
79 * @tparam T Event type
80 * @param event Event to store
81 */
83 void Write(const T& event);
84
85 /**
86 * @brief Writes multiple events to the queue in bulk.
87 * @warning Triggers assertion if event type is not registered.
88 * @tparam R Range of events
89 * @param events Range of events to store
90 */
93 void WriteBulk(const R& events);
94
95 /**
96 * @brief Reads all events of a specific type from the queue.
97 * @warning Span gets invalidated if storage is modified.
98 * @tparam T Event type
99 * @return Span containing all events of type T
100 */
102 [[nodiscard]] auto Read() const -> std::span<const T>;
103
104 /**
105 * @brief Reads events of a specific type into a provided output iterator.
106 * @warning Triggers assertion if event type is not registered.
107 * @tparam T Event type
108 * @tparam OutIt Output iterator type
109 * @param out Output iterator to write events into
110 */
113 void ReadInto(OutIt out) const;
114
115 /**
116 * @brief Checks if an event type is registered.
117 * @tparam T Event type
118 * @return True if the event type is registered, false otherwise
119 */
121 [[nodiscard]] bool IsRegistered() const;
122
123 /**
124 * @brief Checks if events of a specific type exist in the queue.
125 * @tparam T Event type
126 * @return True if events of type T exist, false otherwise
127 */
129 [[nodiscard]] bool HasEvents() const;
130
131 /**
132 * @brief Checks if the queue is empty.
133 * @return True if no events are stored, false otherwise
134 */
136 return std::ranges::all_of(storages_, [](const auto& pair) { return pair.second.Empty(); });
137 }
138
139 /**
140 * @brief Gets the number of event types stored.
141 * @return Number of distinct event types
142 */
143 [[nodiscard]] size_t TypeCount() const noexcept { return storages_.size(); }
144
145 /**
146 * @brief Gets the total size of all stored events in bytes.
147 * @return Total size in bytes
148 */
150
151private:
152 std::unordered_map<EventTypeId, EventStorage> storages_;
153};
154
157 constexpr EventTypeId type_id = EventTypeIdOf<T>();
158 if (!storages_.contains(type_id)) {
159 storages_.emplace(type_id, EventStorage::FromEvent<T>());
160 }
161}
162
163template <EventTrait T>
164inline void EventQueue::Clear() {
165 constexpr EventTypeId type_id = EventTypeIdOf<T>();
166 HELIOS_ASSERT(IsRegistered<T>(), "Failed to clear events: Event type '{}' is not registered!", EventNameOf<T>());
167 storages_.at(type_id).Clear();
168}
169
171 for (auto& [_, storage] : storages_) {
172 storage.Clear();
173 }
174}
175
177 if (const auto it = storages_.find(type_id); it != storages_.end()) {
178 it->second.Clear();
179 }
180}
181
182inline void EventQueue::Merge(EventQueue& other) {
183 for (auto& [type_id, other_storage] : other.storages_) {
184 if (other_storage.Empty()) {
185 continue;
186 }
187
188 if (const auto it = storages_.find(type_id); it == storages_.end()) {
189 // If we don't have this type registered, move the entire storage
190 storages_.emplace(type_id, std::move(other_storage));
191 } else {
192 auto& this_storage = it->second;
193 if (this_storage.Empty()) {
194 // If our storage is empty, just move the other storage
195 this_storage = std::move(other_storage);
196 } else {
197 // Append raw bytes from other storage to this storage
198 this_storage.AppendRawBytes(other_storage.Data());
199 }
200 }
201 }
202}
203
204template <EventTrait T>
205inline void EventQueue::Write(const T& event) {
206 constexpr EventTypeId type_id = EventTypeIdOf<T>();
207 HELIOS_ASSERT(IsRegistered<T>(), "Failed to write event: Event type '{}' is not registered!", EventNameOf<T>());
208 storages_.at(type_id).Write(event);
209}
210
211template <std::ranges::sized_range R>
213inline void EventQueue::WriteBulk(const R& events) {
214 using EventType = std::ranges::range_value_t<R>;
215 constexpr EventTypeId type_id = EventTypeIdOf<EventType>();
216 HELIOS_ASSERT(IsRegistered<EventType>(), "Failed to write events bulk: Event type '{}' is not registered!",
218 storages_.at(type_id).WriteBulk(events);
219}
220
221template <EventTrait T>
222inline auto EventQueue::Read() const -> std::span<const T> {
223 constexpr EventTypeId type_id = EventTypeIdOf<T>();
224 const auto it = storages_.find(type_id);
225 if (it == storages_.end()) {
226 return {};
227 }
228
229 return it->second.ReadAll<T>();
230}
231
232template <EventTrait T, typename OutIt>
233 requires std::output_iterator<OutIt, T>
234inline void EventQueue::ReadInto(OutIt out) const {
235 constexpr EventTypeId type_id = EventTypeIdOf<T>();
236 const auto it = storages_.find(type_id);
237 if (it == storages_.end()) {
238 return;
239 }
240
241 it->second.ReadInto<T>(std::move(out));
242}
243
244template <EventTrait T>
245inline bool EventQueue::HasEvents() const {
246 constexpr EventTypeId type_id = EventTypeIdOf<T>();
247 const auto it = storages_.find(type_id);
248 return it != storages_.end() && !it->second.Empty();
249}
250
251template <EventTrait T>
252inline bool EventQueue::IsRegistered() const {
253 constexpr EventTypeId type_id = EventTypeIdOf<T>();
254 return storages_.contains(type_id);
255}
256
258 size_t total = 0;
259 for (const auto& [_, storage] : storages_) {
260 total += storage.SizeBytes();
261 }
262 return total;
263}
264
265} // namespace helios::ecs::details
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:140
bool Empty() const noexcept
Checks if any entities match the query.
Definition query.hpp:2299
Queue for managing multiple event types.
EventQueue(EventQueue &&) noexcept=default
void Merge(EventQueue &other)
Merges events from another EventQueue into this one.
void WriteBulk(const R &events)
Writes multiple events to the queue in bulk.
void ClearByTypeId(EventTypeId type_id)
Clears events of a specific type by type ID (runtime).
auto Read() const -> std::span< const T >
Reads all events of a specific type from the queue.
EventQueue(const EventQueue &)=delete
void ClearData() noexcept
Clears all event data but preserves registrations.
bool Empty() const noexcept
Checks if the queue is empty.
void Clear() noexcept
Clears all events from the queue and removes registrations.
void Register()
Registers an event type with the queue.
bool HasEvents() const
Checks if events of a specific type exist in the queue.
void ReadInto(OutIt out) const
Reads events of a specific type into a provided output iterator.
void Write(const T &event)
Writes a single event to the queue.
bool IsRegistered() const
Checks if an event type is registered.
size_t TotalSizeBytes() const noexcept
Gets the total size of all stored events in bytes.
size_t TypeCount() const noexcept
Gets the number of event types stored.
Type-erased storage for events using a byte vector.
Concept for valid event types.
Definition event.hpp:44
size_t EventTypeId
Type ID for events.
Definition event.hpp:18
BasicQuery< World, Allocator, Components... > Query
Type alias for query with mutable world access.
Definition query.hpp:2481
STL namespace.