Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
event_reader.hpp
Go to the documentation of this file.
1#pragma once
2
6
7#include <concepts>
8#include <cstddef>
9#include <iterator>
10#include <optional>
11#include <span>
12#include <tuple>
13#include <type_traits>
14#include <unordered_map>
15#include <utility>
16#include <vector>
17
18namespace helios::ecs {
19
20/**
21 * @brief Simple iterator for EventReader that returns plain events.
22 * @tparam T Event type
23 */
24template <EventTrait T>
26public:
27 using value_type = std::remove_cvref_t<T>;
28 using iterator_category = std::forward_iterator_tag;
30 using pointer = const value_type*;
31 using reference = const value_type&;
32
34 constexpr explicit EventSimpleIterator(typename std::vector<T>::const_iterator iter) noexcept : iter_(iter) {}
35
36 constexpr EventSimpleIterator(const EventSimpleIterator&) noexcept = default;
39
42
44 constexpr pointer operator->() const noexcept { return &(*iter_); }
45
48
51
52 constexpr bool operator==(const EventSimpleIterator& other) const noexcept { return iter_ == other.iter_; }
53 constexpr bool operator!=(const EventSimpleIterator& other) const noexcept { return iter_ != other.iter_; }
54
55private:
56 typename std::vector<value_type>::const_iterator iter_;
57};
58
59template <EventTrait T>
61 ++iter_;
62 return *this;
63}
64
65template <EventTrait T>
67 auto temp = *this;
68 ++iter_;
69 return temp;
70}
71
72template <EventTrait T>
74 --iter_;
75 return *this;
76}
77
78template <EventTrait T>
80 auto temp = *this;
81 --iter_;
82 return temp;
83}
84
85/**
86 * @brief Iterator wrapper for EventReader.
87 * @tparam T Event type
88 */
89template <EventTrait T>
91public:
92 using value_type = std::tuple<std::remove_cvref_t<T>>;
93 using iterator_category = std::forward_iterator_tag;
95 using pointer = const std::tuple<std::remove_cvref_t<T>>*;
96 using reference = std::tuple<std::remove_cvref_t<T>>;
97
99 constexpr explicit EventIterator(typename std::vector<std::remove_cvref_t<T>>::const_iterator iter) noexcept
100 : iter_(iter) {}
101
102 constexpr EventIterator(const EventIterator&) noexcept = default;
105
108
110
111 constexpr EventIterator& operator++() noexcept;
113
116
117 constexpr bool operator==(const EventIterator& other) const noexcept { return iter_ == other.iter_; }
118 constexpr bool operator!=(const EventIterator& other) const noexcept { return iter_ != other.iter_; }
119
120private:
121 typename std::vector<std::remove_cvref_t<T>>::const_iterator iter_;
122};
123
124template <EventTrait T>
126 ++iter_;
127 return *this;
128}
129
130template <EventTrait T>
131constexpr auto EventIterator<T>::operator++(int) noexcept -> EventIterator {
132 auto temp = *this;
133 ++iter_;
134 return temp;
135}
136
137template <EventTrait T>
139 --iter_;
140 return *this;
141}
142
143template <EventTrait T>
144constexpr auto EventIterator<T>::operator--(int) noexcept -> EventIterator {
145 auto temp = *this;
146 --iter_;
147 return temp;
148}
149
150/**
151 * @brief Type-safe reader for events with filtering and query support.
152 * @details Provides a clean, ergonomic API for reading events from the event system.
153 * EventReader supports iteration, filtering, searching, and collection operations.
154 * It uses lazy evaluation with caching to avoid multiple reads from EventManager.
155 * @note EventReader is read-only and uses lazy evaluation with internal caching.
156 * EventReader is intended to be short-lived (function-scoped).
157 * Thread-safe for const operations if EventManager is thread-safe.
158 * @tparam T Event type
159 *
160 * @example
161 * @code
162 * auto reader = world.ReadEvents<MyEvent>();
163 *
164 * // Iterate over events (efficient - no copy)
165 * for (const auto& event : reader) {
166 * ProcessEvent(event);
167 * }
168 *
169 * // Get events as span (efficient - no copy)
170 * auto events = reader.Read();
171 * for (const auto& event : events) {
172 * ProcessEvent(event);
173 * }
174 *
175 * // Collect events into vector (when you need ownership)
176 * auto owned = reader.Collect();
177 *
178 * // Functional operations
179 * auto high_priority = reader.Filter([](auto& e) { return e.priority > 5; });
180 * auto ids = reader.Map([](auto& e) { return e.id; });
181 * for (const auto& [idx, event] : reader.Enumerate()) {
182 * // Process with index
183 * }
184 * @endcode
185 */
186template <EventTrait T>
188public:
189 using AdaptorIterator = EventIterator<T>; // For adapters - returns tuples
191
192 using value_type = std::remove_cvref_t<T>;
194 using iterator = const_iterator; // Read-only access
195
196 /**
197 * @brief Constructs an EventReader.
198 * @param manager Reference to the event manager
199 */
200 explicit constexpr EventReader(const details::EventManager& manager) noexcept : manager_(manager) {}
201 EventReader(const EventReader&) = delete;
204
207
208 /**
209 * @brief Returns events as a read-only span.
210 * @details This is the primary interface for accessing events.
211 * The span remains valid as long as the EventReader is alive and no non-const operations are performed.
212 * @return Span of const events
213 *
214 * @example
215 * @code
216 * auto reader = world.ReadEvents<MyEvent>();
217 * auto events = reader.Read();
218 * for (const auto& event : events) {
219 * ProcessEvent(event);
220 * }
221 * @endcode
222 */
224 EnsureCached();
225 return {cached_events_->data(), cached_events_->size()};
226 }
227
228 /**
229 * @brief Collects all events into a vector.
230 * @details Returns a copy of the events. Use this when you need ownership
231 * or when the events need to outlive the EventReader.
232 * For most cases, prefer using Read() or range-based for loops.
233 * @return Vector containing all events
234 *
235 * @example
236 * @code
237 * // Use when you need a copy
238 * auto events = reader.Collect();
239 * ProcessLater(std::move(events));
240 * @endcode
241 */
242 [[nodiscard]] auto Collect() const -> std::vector<value_type> {
243 EnsureCached();
244 return *cached_events_;
245 }
246
247 /**
248 * @brief Collects all events into a vector using a custom allocator.
249 * @details Returns a copy of the events using the provided allocator.
250 * Useful for temporary allocations with frame allocators.
251 * @warning When using a frame allocator (via SystemContext::MakeFrameAllocator()),
252 * the returned data is only valid for the current frame. All pointers and references
253 * to frame-allocated data become invalid after the frame ends. Do not store
254 * frame-allocated data in components, resources, or any persistent storage.
255 * @tparam Alloc STL-compatible allocator type for value_type
256 * @param alloc Allocator instance to use for the result vector
257 * @return Vector containing all events, using the provided allocator
258 *
259 * @example
260 * @code
261 * void MySystem::Update(app::SystemContext& ctx) {
262 * auto alloc = ctx.MakeFrameAllocator<MyEvent>();
263 * auto reader = ctx.ReadEvents<MyEvent>();
264 * auto events = reader.CollectWith(alloc);
265 * // events uses frame allocator, automatically reclaimed at frame end
266 * // WARNING: Do not store 'events' or pointers to its contents beyond this frame!
267 * }
268 * @endcode
269 */
270 template <typename Alloc>
271 requires std::same_as<typename Alloc::value_type, std::remove_cvref_t<T>>
272 [[nodiscard]] auto CollectWith(Alloc alloc) const -> std::vector<value_type, Alloc>;
273
274 /**
275 * @brief Reads events into an output iterator.
276 * @details Efficiently writes events to an output iterator without materialization.
277 * This method bypasses the cache and reads directly from EventManager for optimal performance.
278 * @tparam OutIt Output iterator type
279 * @param out Output iterator
280 *
281 * @example
282 * @code
283 * std::vector<MyEvent> events;
284 * reader.ReadInto(std::back_inserter(events));
285 * @endcode
286 */
287 template <typename OutIt>
288 requires std::output_iterator<OutIt, value_type>
289 void ReadInto(OutIt out) const {
290 manager_.ReadInto<value_type>(std::move(out));
291 }
292
293 /**
294 * @brief Consumes adapter/iterator and writes events into an output iterator.
295 * @details Terminal operation that writes all events to the provided output iterator.
296 * More efficient than Collect() when you have a destination container.
297 * @tparam OutIt Output iterator type
298 * @param out Output iterator
299 *
300 * @example
301 * @code
302 * std::vector<MyEvent> filtered_events;
303 * reader.Filter([](auto& e) { return e.priority > 5; })
304 * .Into(std::back_inserter(filtered_events));
305 * @endcode
306 */
307 template <typename OutIt>
308 requires std::output_iterator<OutIt, std::remove_cvref_t<T>>
309 void Into(OutIt out) const;
310
311 /**
312 * @brief Returns the first event that matches a predicate.
313 * @details The returned pointer is valid only while EventReader is alive.
314 * @tparam Pred Predicate type
315 * @param predicate Predicate function
316 * @return Pointer to first matching event or nullptr if not found
317 *
318 * @example
319 * @code
320 * if (auto* event = reader.FindFirst([](auto& e) { return e.priority > 5; })) {
321 * ProcessHighPriority(*event);
322 * }
323 * @endcode
324 */
325 template <typename Pred>
327 [[nodiscard]] const value_type* FindFirst(const Pred& predicate) const&;
328
329 /**
330 * @brief Counts events that match a predicate.
331 * @tparam Pred Predicate type
332 * @param predicate Predicate function
333 * @return Number of matching events
334 *
335 * @example
336 * @code
337 * size_t critical_count = reader.CountIf([](auto& e) { return e.is_critical; });
338 * @endcode
339 */
340 template <typename Pred>
342 [[nodiscard]] size_t CountIf(const Pred& predicate) const;
343
344 /**
345 * @brief Filters events based on a predicate.
346 * @details Lazily filters the event results, only yielding elements that satisfy the predicate.
347 * @tparam Pred Predicate function type (const T&) -> bool
348 * @param predicate Function to test each event
349 * @return View that yields only matching events
350 *
351 * @example
352 * @code
353 * auto critical = reader.Filter([](const MyEvent& e) { return e.is_critical; });
354 * for (const auto& event : critical) {
355 * HandleCritical(event);
356 * }
357 * @endcode
358 */
359 template <typename Pred>
362
363 /**
364 * @brief Transforms each event using a mapping function.
365 * @details Lazily transforms event results by applying a function to each element.
366 * @tparam Func Transformation function type (const T&) -> U
367 * @param transform Function to transform each event
368 * @return View that yields transformed elements
369 *
370 * @example
371 * @code
372 * auto ids = reader.Map([](const MyEvent& e) { return e.id; });
373 * for (auto id : ids) {
374 * ProcessId(id);
375 * }
376 * @endcode
377 */
378 template <typename Func>
381
382 /**
383 * @brief Takes only the first N events.
384 * @details Lazily yields at most N elements from the event results.
385 * @param count Maximum number of elements to take
386 * @return View that yields at most count elements
387 *
388 * @example
389 * @code
390 * auto first_five = reader.Take(5);
391 * @endcode
392 */
393 [[nodiscard]] auto Take(size_t count) const& -> utils::TakeAdapter<AdaptorIterator>;
394
395 /**
396 * @brief Skips the first N events.
397 * @details Lazily skips the first N elements and yields the rest.
398 * @param count Number of elements to skip
399 * @return View that yields elements after skipping count elements
400 *
401 * @code
402 * auto after_ten = reader.Skip(10);
403 * @endcode
404 */
405 [[nodiscard]] auto Skip(size_t count) const& -> utils::SkipAdapter<AdaptorIterator>;
406
407 /**
408 * @brief Takes events while a predicate is true.
409 * @details Lazily yields elements until the predicate returns false.
410 * @tparam Pred Predicate function type (const T&) -> bool
411 * @param predicate Function to test each event
412 * @return View that yields elements while predicate is true
413 *
414 * @example
415 * @code
416 * auto while_valid = reader.TakeWhile([](const MyEvent& e) { return e.is_valid; });
417 * @endcode
418 */
419 template <typename Pred>
422
423 /**
424 * @brief Skips events while a predicate is true.
425 * @details Lazily skips elements until the predicate returns false, then yields the rest.
426 * @tparam Pred Predicate function type (const T&) -> bool
427 * @param predicate Function to test each event
428 * @return View that yields elements after predicate becomes false
429 *
430 * @example
431 * @code
432 * auto after_invalid = reader.SkipWhile([](const MyEvent& e) { return !e.is_valid; });
433 * @endcode
434 */
435 template <typename Pred>
438
439 /**
440 * @brief Adds an index to each event.
441 * @details Lazily yields tuples with an index followed by the event.
442 * @return View that yields (index, event) tuples
443 *
444 * @example
445 * @code
446 * for (auto [idx, event] : reader.Enumerate()) {
447 * // idx is 0, 1, 2, ...
448 * ProcessWithIndex(idx, event);
449 * }
450 * @endcode
451 */
452 [[nodiscard]] auto Enumerate() const& -> utils::EnumerateAdapter<AdaptorIterator>;
453
454 /**
455 * @brief Inspects each event without consuming it.
456 * @details Calls a function on each element for side effects, then passes it through.
457 * @tparam Func Inspection function type (const T&) -> void
458 * @param inspector Function to call on each event
459 * @return View that yields the same elements after inspection
460 *
461 * @example
462 * @code
463 * auto result = reader.Inspect([](const MyEvent& e) {
464 * std::cout << "Event: " << e.id << "\n";
465 * })
466 * .Collect();
467 * @endcode
468 */
470 requires utils::InspectorFor<Func, const std::remove_cvref_t<T>&>
471 [[nodiscard]] auto Inspect(Func inspector) const& -> utils::InspectAdapter<AdaptorIterator, Func>;
472
473 /**
474 * @brief Yields every Nth event.
475 * @details Lazily yields elements at regular intervals.
476 * @param step Interval between yielded elements (must be > 0)
477 * @return View that yields every step-th element
478 *
479 * @example
480 * @code
481 * auto every_third = reader.StepBy(3);
482 * @endcode
483 */
484 [[nodiscard]] auto StepBy(size_t step) const& -> utils::StepByAdapter<AdaptorIterator>;
485
486 /**
487 * @brief Reverses the order of events.
488 * @details Iterates through events in reverse order.
489 * @return View that yields events in reverse order
490 * @note Requires bidirectional iterator support
491 *
492 * @example
493 * @code
494 * auto reversed = reader.Reverse();
495 * @endcode
496 */
497 [[nodiscard]] auto Reverse() const& -> utils::ReverseAdapter<AdaptorIterator> { return {begin(), end()}; }
498
499 /**
500 * @brief Creates sliding windows over events.
501 * @details Yields overlapping windows of a fixed size.
502 * @param window_size Size of the sliding window
503 * @return View that yields windows of events
504 * @warning window_size must be greater than 0
505 *
506 * @example
507 * @code
508 * auto windows = reader.Slide(3);
509 * @endcode
510 */
512 return {begin(), end(), window_size};
513 }
514
515 /**
516 * @brief Takes every Nth event.
517 * @details Yields events at regular stride intervals.
518 * @param stride Number of events to skip between yields
519 * @return View that yields every Nth event
520 * @warning stride must be greater than 0
521 *
522 * @example
523 * @code
524 * auto every_third = reader.Stride(3);
525 * @endcode
526 */
528 return {begin(), end(), stride};
529 }
530
531 /**
532 * @brief Zips events with another iterator.
533 * @details Combines events with another range into tuples.
534 * @tparam OtherIter Iterator type to zip with
535 * @param other_begin Beginning of the other range
536 * @param other_end End of the other range
537 * @return View that yields tuples of corresponding elements
538 *
539 * @example
540 * @code
541 * std::vector<int> ids = {1, 2, 3};
542 * auto zipped = reader.Zip(ids.begin(), ids.end());
543 * @endcode
544 */
545 template <typename OtherIter>
549 return {begin(), end(), std::move(other_begin), std::move(other_end)};
550 }
551
552 /**
553 * @brief Executes a function for each event.
554 * @details Calls the provided function with each event for side effects.
555 * @tparam Action Function type (const T&) -> void
556 * @param action Function to execute for each event
557 *
558 * @example
559 * @code
560 * reader.ForEach([](const MyEvent& e) {
561 * ProcessEvent(e);
562 * });
563 * @endcode
564 */
565 template <typename Action>
567 void ForEach(const Action& action) const;
568
569 /**
570 * @brief Folds the events into a single value.
571 * @details Applies a binary function to an initial value and each event.
572 * @tparam Acc Accumulator type
573 * @tparam Folder Function type (Acc, const T&) -> Acc
574 * @param init Initial value
575 * @param folder Function that combines accumulator with each event
576 * @return Final folded value
577 *
578 * @example
579 * @code
580 * int total = reader.Fold(0, [](int acc, const MyEvent& e) { return acc + e.value; });
581 * @endcode
582 */
583 template <typename Acc, typename Folder>
585 [[nodiscard]] Acc Fold(Acc init, const Folder& folder) const;
586
587 /**
588 * @brief Checks if any event matches the predicate.
589 * @details Short-circuits on first match for efficiency.
590 * @tparam Pred Predicate function type (const T&) -> bool
591 * @param predicate Function to test each event
592 * @return True if at least one event matches, false otherwise
593 *
594 * @code
595 * bool has_critical = reader.Any([](const MyEvent& e) { return e.is_critical; });
596 * @endcode
597 */
598 template <typename Pred>
600 [[nodiscard]] bool Any(const Pred& predicate) const;
601
602 /**
603 * @brief Checks if all events match the predicate.
604 * @details Short-circuits on first non-match for efficiency.
605 * @tparam Pred Predicate function type (const T&) -> bool
606 * @param predicate Function to test each event
607 * @return True if all events match, false otherwise
608 *
609 * @example
610 * @code
611 * bool all_valid = reader.All([](const MyEvent& e) { return e.is_valid; });
612 * @endcode
613 */
614 template <typename Pred>
616 [[nodiscard]] bool All(const Pred& predicate) const;
617
618 /**
619 * @brief Finds the first event matching the predicate.
620 * @details Returns an optional containing the first matching event.
621 * @tparam Pred Predicate function type (const T&) -> bool
622 * @param predicate Function to test each event
623 * @return Optional containing the first matching event, or empty if not found
624 *
625 * @example
626 * @code
627 * if (auto event = reader.Find([](const MyEvent& e) { return e.id == 42; })) {
628 * Process(*event);
629 * }
630 * @endcode
631 */
632 template <typename Pred>
634 [[nodiscard]] auto Find(const Pred& predicate) const -> std::optional<value_type>;
635
636 /**
637 * @brief Checks if no events match the predicate.
638 * @details Short-circuits on first match for efficiency.
639 * @tparam Pred Predicate function type (const T&) -> bool
640 * @param predicate Function to test each event
641 * @return True if no events match, false otherwise
642 *
643 * @example
644 * @code
645 * bool none_critical = reader.None([](const MyEvent& e) { return e.is_critical; });
646 * @endcode
647 */
648 template <typename Pred>
650 [[nodiscard]] constexpr bool None(const Pred& predicate) const {
651 return !Any(predicate);
652 }
653
654 /**
655 * @brief Partitions events into two groups based on a predicate.
656 * @tparam Pred Predicate function type (const T&) -> bool
657 * @param predicate Function to test each event
658 * @return Pair of vectors: first contains events matching predicate, second contains non-matching
659 *
660 * @example
661 * @code
662 * auto [critical, normal] = reader.Partition([](const MyEvent& e) { return e.is_critical; });
663 * @endcode
664 */
665 template <typename Pred>
667 [[nodiscard]] auto Partition(const Pred& predicate) const
668 -> std::pair<std::vector<value_type>, std::vector<value_type>>;
669
670 /**
671 * @brief Finds the event with the maximum value using a key function.
672 * @details Finds the event that produces the maximum value when passed to the key function.
673 * @tparam KeyFunc Function type (const T&) -> Comparable
674 * @param key_func Function to extract the comparison value
675 * @return Optional containing the event with maximum key, or empty if no events exist
676 *
677 * @example
678 * @code
679 * auto highest_priority = reader.MaxBy([](const MyEvent& e) { return e.priority; });
680 * @endcode
681 */
682 template <typename KeyFunc>
683 requires std::invocable<KeyFunc, const std::remove_cvref_t<T>&>
684 [[nodiscard]] auto MaxBy(const KeyFunc& key_func) const -> std::optional<value_type>;
685
686 /**
687 * @brief Finds the event with the minimum value using a key function.
688 * @details Finds the event that produces the minimum value when passed to the key function.
689 * @tparam KeyFunc Function type (const T&) -> Comparable
690 * @param key_func Function to extract the comparison value
691 * @return Optional containing the event with minimum key, or empty if no events exist
692 *
693 * @example
694 * @code
695 * auto lowest_priority = reader.MinBy([](const MyEvent& e) { return e.priority; });
696 * @endcode
697 */
698 template <typename KeyFunc>
699 requires std::invocable<KeyFunc, const std::remove_cvref_t<T>&>
700 [[nodiscard]] auto MinBy(const KeyFunc& key_func) const -> std::optional<value_type>;
701
702 /**
703 * @brief Groups events by a key function.
704 * @details Groups events into a map where keys are produced by the key function.
705 * @tparam KeyFunc Function type (const T&) -> Key
706 * @param key_func Function to extract the grouping key
707 * @return Map from keys to vectors of events with that key
708 *
709 * @example
710 * @code
711 * auto by_type = reader.GroupBy([](const MyEvent& e) { return e.type; });
712 * @endcode
713 */
714 template <typename KeyFunc>
715 requires std::invocable<KeyFunc, const std::remove_cvref_t<T>&>
716 [[nodiscard]] auto GroupBy(const KeyFunc& key_func) const
717 -> std::unordered_map<std::invoke_result_t<KeyFunc, const value_type&>, std::vector<value_type>>;
718
719 /**
720 * @brief Checks if there are any events.
721 * @return true if no events exist, false otherwise
722 */
723 [[nodiscard]] bool Empty() const { return !manager_.HasEvents<value_type>(); }
724
725 /**
726 * @brief Returns the number of events.
727 * @return Number of events in current and previous queues
728 */
729 [[nodiscard]] size_t Count() const;
730
731 /**
732 * @brief Returns an iterator to the beginning of events.
733 * @details Triggers lazy initialization of event cache on first call.
734 * @return Const iterator to first event (returns plain T for range-based for loops)
735 */
736 [[nodiscard]] const_iterator begin() const;
737
738 /**
739 * @brief Returns an iterator to the end of events.
740 * @details Triggers lazy initialization of event cache on first call.
741 * @return Const iterator to end
742 */
743 [[nodiscard]] const_iterator end() const;
744
745private:
746 /**
747 * @brief Ensures events are cached.
748 * @details Lazily initializes the event cache on first access.
749 * Subsequent calls are no-ops since the cache persists.
750 */
751 void EnsureCached() const;
752
753 const details::EventManager& manager_; ///< Reference to the event manager
754 mutable std::optional<std::vector<value_type>> cached_events_; ///< Lazy-initialized event cache
755};
756
757template <EventTrait T>
758template <typename OutIt>
759 requires std::output_iterator<OutIt, std::remove_cvref_t<T>>
760inline void EventReader<T>::Into(OutIt out) const {
761 EnsureCached();
762 for (const auto& event : *cached_events_) {
763 *out++ = event;
764 }
765}
766
767template <EventTrait T>
768template <typename Pred>
770inline auto EventReader<T>::FindFirst(const Pred& predicate) const& -> const value_type* {
771 EnsureCached();
772 for (const auto& event : *cached_events_) {
773 if (predicate(event)) {
774 return &event;
775 }
776 }
777 return nullptr;
778}
779
780template <EventTrait T>
781template <typename Pred>
783inline size_t EventReader<T>::CountIf(const Pred& predicate) const {
784 EnsureCached();
785 size_t count = 0;
786 for (const auto& event : *cached_events_) {
787 if (predicate(event)) {
788 ++count;
789 }
790 }
791 return count;
792}
793
794template <EventTrait T>
795inline size_t EventReader<T>::Count() const {
796 EnsureCached();
797 return cached_events_->size();
798}
799
800template <EventTrait T>
801template <typename Alloc>
802 requires std::same_as<typename Alloc::value_type, std::remove_cvref_t<T>>
803inline auto EventReader<T>::CollectWith(Alloc alloc) const -> std::vector<value_type, Alloc> {
804 EnsureCached();
805 std::vector<value_type, Alloc> result{std::move(alloc)};
806 result.reserve(cached_events_->size());
807 for (const auto& event : *cached_events_) {
808 result.push_back(event);
809 }
810 return result;
811}
812
813template <EventTrait T>
814template <typename Pred>
817 EnsureCached();
818 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), std::move(predicate)};
819}
820
821template <EventTrait T>
822template <typename Func>
825 EnsureCached();
826 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), std::move(transform)};
827}
828
829template <EventTrait T>
831 EnsureCached();
832 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), count};
833}
834
835template <EventTrait T>
837 EnsureCached();
838 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), count};
839}
840
841template <EventTrait T>
842template <typename Pred>
845 EnsureCached();
846 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), std::move(predicate)};
847}
848
849template <EventTrait T>
850template <typename Pred>
853 EnsureCached();
854 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), std::move(predicate)};
855}
856
857template <EventTrait T>
858inline auto EventReader<T>::Enumerate() const& -> utils::EnumerateAdapter<AdaptorIterator> {
859 EnsureCached();
860 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end())};
861}
862
863template <EventTrait T>
864template <typename Func>
867 EnsureCached();
868 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), std::move(inspector)};
869}
870
871template <EventTrait T>
873 EnsureCached();
874 return {AdaptorIterator(cached_events_->begin()), AdaptorIterator(cached_events_->end()), step};
875}
876
877template <EventTrait T>
878template <typename Pred>
880inline bool EventReader<T>::Any(const Pred& predicate) const {
881 EnsureCached();
882 for (const auto& event : *cached_events_) {
883 if (predicate(event)) {
884 return true;
885 }
886 }
887 return false;
888}
889
890template <EventTrait T>
891template <typename Pred>
893inline bool EventReader<T>::All(const Pred& predicate) const {
894 EnsureCached();
895 for (const auto& event : *cached_events_) {
896 if (!predicate(event)) {
897 return false;
898 }
899 }
900 return true;
901}
902
903template <EventTrait T>
904template <typename Pred>
906inline auto EventReader<T>::Find(const Pred& predicate) const -> std::optional<value_type> {
907 EnsureCached();
908 for (const auto& event : *cached_events_) {
909 if (predicate(event)) {
910 return event;
911 }
912 }
913 return std::nullopt;
914}
915
916template <EventTrait T>
917template <typename Action>
919inline void EventReader<T>::ForEach(const Action& action) const {
920 EnsureCached();
921 for (const auto& event : *cached_events_) {
922 if constexpr (std::invocable<Action, const value_type&>) {
923 action(event);
924 } else {
925 std::apply(action, event);
926 }
927 }
928}
929
930template <EventTrait T>
931template <typename Acc, typename Folder>
934 EnsureCached();
935 for (const auto& event : *cached_events_) {
936 if constexpr (std::invocable<Folder, Acc, const value_type&>) {
937 init = folder(std::move(init), event);
938 } else {
939 init = std::apply([&folder, &init](const auto&... args) { return folder(std::move(init), args...); }, event);
940 }
941 }
942 return init;
943}
944
945template <EventTrait T>
946template <typename Pred>
948inline auto EventReader<T>::Partition(const Pred& predicate) const
949 -> std::pair<std::vector<value_type>, std::vector<value_type>> {
950 EnsureCached();
951 std::pair<std::vector<value_type>, std::vector<value_type>> result;
952 for (const auto& event : *cached_events_) {
953 if (predicate(event)) {
954 result.first.push_back(event);
955 } else {
956 result.second.push_back(event);
957 }
958 }
959 return result;
960}
961
962template <EventTrait T>
963template <typename KeyFunc>
964 requires std::invocable<KeyFunc, const std::remove_cvref_t<T>&>
965inline auto EventReader<T>::MaxBy(const KeyFunc& key_func) const -> std::optional<value_type> {
966 EnsureCached();
967 if (cached_events_->empty()) {
968 return std::nullopt;
969 }
970
971 auto max_iter = cached_events_->begin();
972 auto max_key = key_func(*max_iter);
973
974 for (auto iter = cached_events_->begin() + 1; iter != cached_events_->end(); ++iter) {
975 auto current_key = key_func(*iter);
976 if (current_key > max_key) {
977 max_key = std::move(current_key);
978 max_iter = iter;
979 }
980 }
981
982 return *max_iter;
983}
984
985template <EventTrait T>
986template <typename KeyFunc>
987 requires std::invocable<KeyFunc, const std::remove_cvref_t<T>&>
988inline auto EventReader<T>::MinBy(const KeyFunc& key_func) const -> std::optional<value_type> {
989 EnsureCached();
990 if (cached_events_->empty()) {
991 return std::nullopt;
992 }
993
994 auto min_iter = cached_events_->begin();
995 auto min_key = key_func(*min_iter);
996
997 for (auto iter = cached_events_->begin() + 1; iter != cached_events_->end(); ++iter) {
998 auto current_key = key_func(*iter);
999 if (current_key < min_key) {
1000 min_key = std::move(current_key);
1001 min_iter = iter;
1002 }
1003 }
1004
1005 return *min_iter;
1006}
1007
1008template <EventTrait T>
1009template <typename KeyFunc>
1010 requires std::invocable<KeyFunc, const std::remove_cvref_t<T>&>
1012 -> std::unordered_map<std::invoke_result_t<KeyFunc, const value_type&>, std::vector<value_type>> {
1013 EnsureCached();
1014 std::unordered_map<std::invoke_result_t<KeyFunc, const value_type&>, std::vector<value_type>> result;
1015 for (const auto& event : *cached_events_) {
1016 result[key_func(event)].push_back(event);
1017 }
1018 return result;
1019}
1020
1021template <EventTrait T>
1023 EnsureCached();
1024 return const_iterator(cached_events_->begin());
1025}
1026
1027template <EventTrait T>
1029 EnsureCached();
1030 return const_iterator(cached_events_->end());
1031}
1032
1033template <EventTrait T>
1034inline void EventReader<T>::EnsureCached() const {
1035 if (!cached_events_.has_value()) {
1036 cached_events_ = manager_.Read<value_type>();
1037 }
1038}
1039
1040} // namespace helios::ecs
iterator begin() const
Gets iterator to first matching entity.
Definition query.hpp:2317
iterator end() const noexcept
Gets iterator past the last matching entity.
Definition query.hpp:1603
Iterator wrapper for EventReader.
constexpr EventIterator(EventIterator &&) noexcept=default
constexpr EventIterator() noexcept=default
std::tuple< std::remove_cvref_t< T > > value_type
std::tuple< std::remove_cvref_t< T > > reference
constexpr EventIterator & operator--() noexcept
constexpr EventIterator(const EventIterator &) noexcept=default
std::forward_iterator_tag iterator_category
const std::tuple< std::remove_cvref_t< T > > * pointer
constexpr bool operator!=(const EventIterator &other) const noexcept
constexpr EventIterator & operator++() noexcept
bool All(const Pred &predicate) const
const_iterator end() const
Returns an iterator to the end of events.
const_iterator begin() const
Returns an iterator to the beginning of events.
AdaptorConstIterator const_iterator
EventSimpleIterator< T > AdaptorConstIterator
EventReader(EventReader &&) noexcept=default
constexpr bool None(const Pred &predicate) const
size_t CountIf(const Pred &predicate) const
auto StepBy(size_t step) const &-> utils::StepByAdapter< AdaptorIterator >
Acc Fold(Acc init, const Folder &folder) const
const value_type * FindFirst(const Pred &predicate) const &
auto Read() const &-> std::span< const value_type >
auto MinBy(const KeyFunc &key_func) const -> std::optional< value_type >
bool Empty() const
Checks if there are any events.
void ReadInto(OutIt out) const
auto Filter(Pred predicate) const &-> utils::FilterAdapter< AdaptorIterator, Pred >
EventReader(const EventReader &)=delete
auto Stride(size_t stride) const &-> utils::StrideAdapter< AdaptorIterator >
auto Reverse() const &-> utils::ReverseAdapter< AdaptorIterator >
auto MaxBy(const KeyFunc &key_func) const -> std::optional< value_type >
auto Find(const Pred &predicate) const -> std::optional< value_type >
auto Map(Func transform) const &-> utils::MapAdapter< AdaptorIterator, Func >
auto Enumerate() const &-> utils::EnumerateAdapter< AdaptorIterator >
auto Skip(size_t count) const &-> utils::SkipAdapter< AdaptorIterator >
Skips the first N events.
constexpr EventReader(const details::EventManager &manager) noexcept
Constructs an EventReader.
size_t Count() const
Returns the number of events.
auto TakeWhile(Pred predicate) const &-> utils::TakeWhileAdapter< AdaptorIterator, Pred >
auto Take(size_t count) const &-> utils::TakeAdapter< AdaptorIterator >
auto Zip(OtherIter other_begin, OtherIter other_end) const &-> utils::ZipAdapter< AdaptorIterator, OtherIter >
void Into(OutIt out) const
auto Inspect(Func inspector) const &-> utils::InspectAdapter< AdaptorIterator, Func >
std::remove_cvref_t< T > value_type
auto Collect() const -> std::vector< value_type >
void ForEach(const Action &action) const
auto Slide(size_t window_size) const &-> utils::SlideAdapter< AdaptorIterator >
auto GroupBy(const KeyFunc &key_func) const -> std::unordered_map< std::invoke_result_t< KeyFunc, const value_type & >, std::vector< value_type > >
bool Any(const Pred &predicate) const
Checks if any event matches the predicate.
auto Partition(const Pred &predicate) const -> std::pair< std::vector< value_type >, std::vector< value_type > >
auto SkipWhile(Pred predicate) const &-> utils::SkipWhileAdapter< AdaptorIterator, Pred >
auto CollectWith(Alloc alloc) const -> std::vector< value_type, Alloc >
Simple iterator for EventReader that returns plain events.
std::remove_cvref_t< T > value_type
constexpr EventSimpleIterator & operator++() noexcept
std::forward_iterator_tag iterator_category
constexpr bool operator!=(const EventSimpleIterator &other) const noexcept
constexpr EventSimpleIterator & operator--() noexcept
constexpr EventSimpleIterator() noexcept=default
constexpr pointer operator->() const noexcept
constexpr EventSimpleIterator(EventSimpleIterator &&) noexcept=default
constexpr EventSimpleIterator(const EventSimpleIterator &) noexcept=default
Manages event lifecycle with double buffering and registration tracking.
void ReadInto(OutIt out) const
Reads events of a specific type into a provided output iterator.
bool HasEvents() const
Checks if events of a specific type exist in either queue.
Concept for action functions that process values.
Concept for folder functions that accumulate values.
Concept for inspection functions that observe but don't modify values.
Concept for types that can be used as base iterators in adapters.
Concept for predicate functions that can be applied to iterator values.
Concept for transformation functions that can be applied to iterator values.
BasicQuery< World, Allocator, Components... > Query
Type alias for query with mutable world access.
Definition query.hpp:2481
STL namespace.