Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
async_reader.hpp
Go to the documentation of this file.
1#pragma once
2
7
8#include <functional>
9#include <iterator>
10#include <limits>
11#include <utility>
12
13namespace helios::ecs {
14
15/**
16 * @brief Type-safe, move-based reader for async messages.
17 * @details Drains all async messages of type `T` from the shared
18 * `AsyncMessageQueue` into a local buffer on construction. After draining, the
19 * messages are owned by the reader and can be iterated over, moved out, or
20 * queried.
21 * @note Thread-safe.
22 * @tparam T Async message type satisfying `AsyncMessageTrait`
23 *
24 * @code
25 * for (auto& message : reader) {
26 * Process(std::move(message));
27 * }
28 *
29 * // Or move all messages out:
30 * auto messages = reader.TakeAll();
31 * @endcode
32 */
33template <AsyncMessageTrait T>
35public:
37
38 /**
39 * @brief Constructs an `AsyncMessageReader` from the message manager.
40 * @param manager Reference to the message manager
41 */
42 explicit AsyncMessageReader(MessageManager& manager) noexcept
43 : AsyncMessageReader(manager.AsyncQueue()) {}
44
45 /**
46 * @brief Constructs an `AsyncMessageReader` by draining messages from the
47 * async queue.
48 * @warning Triggers assertion if type 'T' is not registered.
49 * @param async_queue Reference to the async message queue
50 */
52 : messages_(async_queue.TypedStorage<T>()),
53 token_(messages_.get().MakeConsumerToken()) {}
56 ~AsyncMessageReader() noexcept = default;
57
58 AsyncMessageReader& operator=(const AsyncMessageReader&) = delete;
59 AsyncMessageReader& operator=(AsyncMessageReader&&) noexcept = default;
60
61 /**
62 * @brief Dequeues a single message from the queue.
63 * @return Dequeued message or default-constructed `T` if the queue is empty
64 */
65 T Dequeue() const { return messages_.get().Dequeue(token_); }
66
67 /**
68 * @brief Dequeues a single message from the queue.
69 * @param dest Reference to store the dequeued message
70 * @return True if an message was dequeued and stored in dest, false if the
71 * queue was empty (`dest` is unchanged)
72 */
73 bool Dequeue(T& dest) const { return messages_.get().Dequeue(token_, dest); }
74
75 /**
76 * @brief Moves messages into an output iterator (dequeues them).
77 * @tparam It Output iterator type
78 * @param out Output iterator to receive messages
79 * @param max_count Maximum number of messages to move (default: all messages)
80 * @return Number of messages actually dequeued
81 */
82 template <std::output_iterator<T> It>
83 size_type Into(It out, size_type max_count =
84 std::numeric_limits<size_type>::max()) const {
85 return messages_.get().Into(token_, std::move(out), max_count);
86 }
87
88 /**
89 * @brief Applies an action to every message in the queue (dequeues them).
90 * @note It is possible that the queue is modified by other writers while this
91 * method is executing, so the number of messages processed may be less than
92 * the total number of messages at the time of calling.
93 * @tparam Action Callable type `(const T&) -> void`
94 * @param action Action to apply
95 */
96 template <typename Action>
97 requires std::invocable<Action, T&>
98 void ForEach(const Action& action) const;
99
100 /**
101 * @brief Checks if there are no messages.
102 * @return True if the reader holds no messages, false otherwise
103 */
104 [[nodiscard]] bool Empty() const noexcept { return messages_.get().Empty(); }
105
106 /**
107 * @brief Returns an approximate count of messages.
108 * @return Message count
109 */
110 [[nodiscard]] size_type CountApprox() const noexcept {
111 return messages_.get().SizeApprox();
112 }
113
114private:
115 std::reference_wrapper<TypedAsyncMessageStorage<T>>
116 messages_; ///< Message storage
118 token_; ///< Per-reader consumer token for improved throughput
119};
120
121template <AsyncMessageTrait T>
122template <typename Action>
123 requires std::invocable<Action, T&>
124inline void AsyncMessageReader<T>::ForEach(const Action& action) const {
125 T temp;
126 while (Dequeue(temp)) {
127 action(temp);
128 }
129}
130
131} // namespace helios::ecs
Async queue for managing multiple message types via lock-free concurrent queues.
AsyncMessageReader(AsyncMessageQueue &async_queue)
Constructs an AsyncMessageReader by draining messages from the async queue.
AsyncMessageReader(MessageManager &manager) noexcept
Constructs an AsyncMessageReader from the message manager.
size_type CountApprox() const noexcept
Returns an approximate count of messages.
AsyncMessageReader(AsyncMessageReader &&) noexcept=default
bool Dequeue(T &dest) const
Dequeues a single message from the queue.
T Dequeue() const
Dequeues a single message from the queue.
AsyncMessageQueue::size_type size_type
void ForEach(const Action &action) const
Applies an action to every message in the queue (dequeues them).
AsyncMessageReader(const AsyncMessageReader &)=delete
bool Empty() const noexcept
Checks if there are no messages.
size_type Into(It out, size_type max_count=std::numeric_limits< size_type >::max()) const
Moves messages into an output iterator (dequeues them).
Central coordinator for message lifecycle with double buffering and consumed message removal.
Definition manager.hpp:54
moodycamel::ConsumerToken AsyncMessageQueueConsumerToken