Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
reader.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/assert.hpp>
9
10#include <algorithm>
11#include <cstddef>
12#include <functional>
13#include <iterator>
14#include <memory>
15#include <memory_resource>
16#include <optional>
17#include <span>
18#include <type_traits>
19#include <unordered_map>
20#include <utility>
21#include <vector>
22
23namespace helios::ecs {
24
25/**
26 * @brief Bidirectional iterator that yields `MessageWrapper<T>` instances.
27 * @details Each wrapper carries a const reference to the message and the
28 * global index, enabling the caller to access the message during iteration.
29 *
30 * Derives from `FunctionalAdapterBase` so the iterator itself can be used as a
31 * lazy range, enabling chained adapter calls such as `.Filter(...)`,
32 * `.Map(...)`, `.Take(...)`, etc.
33 *
34 * @note The adapter methods operate on `MessageWrapper<T>` values.
35 * @tparam T Message type satisfying `MessageTrait`
36 */
37template <MessageTrait T>
39 : public utils::FunctionalAdapterBase<MessageWrapperIter<T>> {
40public:
41 using iterator_concept = std::bidirectional_iterator_tag;
42 using iterator_category = std::input_iterator_tag;
45 using pointer = void;
46 using difference_type = ptrdiff_t;
47
48 constexpr MessageWrapperIter() noexcept = default;
49
50 /**
51 * @brief Constructs a wrapper iterator over two contiguous message spans.
52 * @param first Span of messages from the previous frame
53 * @param second Span of messages from the current frame
54 * @param position Logical position in the combined [first | second] sequence
55 */
56 constexpr MessageWrapperIter(std::span<const T> first,
57 std::span<const T> second,
58 size_t position) noexcept
59 : first_(first), second_(second), position_(position) {}
60
61 constexpr MessageWrapperIter(const MessageWrapperIter&) noexcept = default;
62 constexpr MessageWrapperIter(MessageWrapperIter&&) noexcept = default;
63 constexpr ~MessageWrapperIter() noexcept = default;
64
65 constexpr MessageWrapperIter& operator=(const MessageWrapperIter&) noexcept =
66 default;
67 constexpr MessageWrapperIter& operator=(MessageWrapperIter&&) noexcept =
68 default;
69
70 [[nodiscard]] constexpr reference operator*() const noexcept {
71 const T& msg = (position_ < first_.size())
72 ? first_[position_]
73 : second_[position_ - first_.size()];
74 return {msg, position_};
75 }
76
77 pointer operator->() const = delete;
78
79 constexpr MessageWrapperIter& operator++() noexcept {
80 ++position_;
81 return *this;
82 }
83
84 [[nodiscard]] constexpr MessageWrapperIter operator++(int) noexcept {
85 auto copy = *this;
86 ++(*this);
87 return copy;
88 }
89
90 constexpr MessageWrapperIter& operator--() noexcept {
91 --position_;
92 return *this;
93 }
94
95 [[nodiscard]] constexpr MessageWrapperIter operator--(int) noexcept {
96 auto copy = *this;
97 --(*this);
98 return copy;
99 }
100
101 [[nodiscard]] constexpr auto operator<=>(
102 const MessageWrapperIter& other) const noexcept {
103 return position_ <=> other.position_;
104 }
105
106 [[nodiscard]] constexpr bool operator==(
107 const MessageWrapperIter& other) const noexcept {
108 return position_ == other.position_;
109 }
110
111 [[nodiscard]] constexpr bool operator!=(
112 const MessageWrapperIter& other) const noexcept {
113 return position_ != other.position_;
114 }
115
116 /**
117 * @brief Returns the current logical position in the combined sequence.
118 * @return Zero-based position index
119 */
120 [[nodiscard]] constexpr size_t Position() const noexcept { return position_; }
121
122 /**
123 * @brief Returns a copy of this iterator positioned at the beginning of the
124 * sequence.
125 * @details Required so `MessageWrapperIter` can act as a self-contained range
126 * for `FunctionalAdapterBase` adapter methods.
127 * @return Iterator reset to position 0
128 */
129 [[nodiscard]] constexpr MessageWrapperIter begin() const noexcept {
130 return {first_, second_, 0};
131 }
132
133 /**
134 * @brief Returns a copy of this iterator positioned one past the last
135 * element.
136 * @return Iterator at position `first_.size() + second_.size()`
137 */
138 [[nodiscard]] constexpr MessageWrapperIter end() const noexcept {
139 return {first_, second_, first_.size() + second_.size()};
140 }
141
142private:
143 std::span<const T> first_;
144 std::span<const T> second_;
145 size_t position_ = 0;
146};
147
148/**
149 * @brief Bidirectional iterator that yields `ConsumableMessageWrapper<T>`
150 * instances with consume support.
151 * @details Each wrapper carries a const reference to the message, a reference
152 * to `ConsumedMessagesRegistry`, and the global index, enabling the caller to
153 * mark individual messages as consumed during iteration.
154 *
155 * Derives from `FunctionalAdapterBase` so the iterator itself can be used as a
156 * lazy range, enabling chained adapter calls such as `.Filter(...)`,
157 * `.Map(...)`, `.Take(...)`, etc.
158 *
159 * @note The adapter methods operate on `ConsumableMessageWrapper<T>` values.
160 * @tparam T Message type satisfying `ConsumableMessageTrait`
161 */
162template <ConsumableMessageTrait T>
164 : public utils::FunctionalAdapterBase<ConsumableMessageWrapperIter<T>> {
165public:
166 using iterator_concept = std::bidirectional_iterator_tag;
167 using iterator_category = std::input_iterator_tag;
170 using pointer = void;
171 using difference_type = ptrdiff_t;
172
173 constexpr ConsumableMessageWrapperIter() noexcept = default;
174
175 /**
176 * @brief Constructs a wrapper iterator over two contiguous message spans.
177 * @param first Span of messages from the previous frame
178 * @param second Span of messages from the current frame
179 * @param registry Per-system consumed messages registry
180 * @param position Logical position in the combined [first | second] sequence
181 */
183 std::span<const T> first, std::span<const T> second,
184 std::reference_wrapper<ConsumedMessagesRegistry<>> registry,
185 size_t position) noexcept
186 : first_(first),
187 second_(second),
188 position_(position),
189 registry_(&registry.get()) {}
190
192 const ConsumableMessageWrapperIter&) noexcept = default;
194 ConsumableMessageWrapperIter&&) noexcept = default;
195 constexpr ~ConsumableMessageWrapperIter() noexcept = default;
196
197 constexpr ConsumableMessageWrapperIter& operator=(
198 const ConsumableMessageWrapperIter&) noexcept = default;
199 constexpr ConsumableMessageWrapperIter& operator=(
200 ConsumableMessageWrapperIter&&) noexcept = default;
201
202 [[nodiscard]] constexpr reference operator*() const noexcept {
203 const T& msg = (position_ < first_.size())
204 ? first_[position_]
205 : second_[position_ - first_.size()];
206 return {msg, *registry_, position_};
207 }
208
209 pointer operator->() const = delete;
210
212 ++position_;
213 return *this;
214 }
215
217 int) noexcept {
218 auto copy = *this;
219 ++(*this);
220 return copy;
221 }
222
224 --position_;
225 return *this;
226 }
227
229 int) noexcept {
230 auto copy = *this;
231 --(*this);
232 return copy;
233 }
234
235 [[nodiscard]] constexpr auto operator<=>(
236 const ConsumableMessageWrapperIter& other) const noexcept {
237 return position_ <=> other.position_;
238 }
239
240 [[nodiscard]] constexpr bool operator==(
241 const ConsumableMessageWrapperIter& other) const noexcept {
242 return position_ == other.position_;
243 }
244
245 [[nodiscard]] constexpr bool operator!=(
246 const ConsumableMessageWrapperIter& other) const noexcept {
247 return position_ != other.position_;
248 }
249
250 /**
251 * @brief Returns the current logical position in the combined sequence.
252 * @return Zero-based position index
253 */
254 [[nodiscard]] constexpr size_t Position() const noexcept { return position_; }
255
256 /**
257 * @brief Returns a copy of this iterator positioned at the beginning of the
258 * sequence.
259 * @details Required so `ConsumableMessageWrapperIter` can act as a
260 * self-contained range for `FunctionalAdapterBase` adapter methods.
261 * @return Iterator reset to position 0
262 */
263 [[nodiscard]] constexpr ConsumableMessageWrapperIter begin() const noexcept {
264 return {first_, second_, *registry_, 0};
265 }
266
267 /**
268 * @brief Returns a copy of this iterator positioned one past the last
269 * element.
270 * @return Iterator at position `first_.size() + second_.size()`
271 */
272 [[nodiscard]] constexpr ConsumableMessageWrapperIter end() const noexcept {
273 return {first_, second_, *registry_, first_.size() + second_.size()};
274 }
275
276private:
277 std::span<const T> first_;
278 std::span<const T> second_;
279 size_t position_ = 0;
280 ConsumedMessagesRegistry<>* registry_ = nullptr;
281};
282
283/**
284 * @brief CRTP base class for message readers providing common functionality.
285 * @details This base class contains all reader methods except consumption
286 * methods (`ConsumeAll` and `ConsumeIf`) which are only available on
287 * `ConsumableMessageReader`.
288 *
289 * @tparam Derived The derived class (CRTP)
290 * @tparam T Message type
291 * @tparam IterType The iterator type for this reader
292 */
293template <typename Derived, MessageTrait T, typename IterType>
295public:
296 using value_type = typename IterType::value_type;
298 using iterator = IterType;
299 using const_iterator = IterType;
300
301 constexpr MessageReaderBase() noexcept = default;
303 constexpr MessageReaderBase(MessageReaderBase&&) noexcept = default;
304 constexpr ~MessageReaderBase() noexcept = default;
305
306 MessageReaderBase& operator=(const MessageReaderBase&) = delete;
307 constexpr MessageReaderBase& operator=(MessageReaderBase&&) noexcept =
308 default;
309
310 /**
311 * @brief Applies an action to every message (unwrapped `const T&`).
312 * @tparam Action Callable type `(const value_type&) -> void`
313 * @param action Action to apply
314 */
315 template <typename Action>
316 requires std::invocable<Action, const value_type&>
317 constexpr void ForEach(const Action& action) const {
318 return GetDerived().begin().ForEach(action);
319 }
320
321 /**
322 * @brief Collects all messages (previous + current) into a vector of raw `T`
323 * values.
324 * @note This shadows `FunctionalAdapterBase::Collect()`. To collect
325 * wrapper values, chain a lazy adapter first (e.g.,
326 * `reader.Filter(...).Collect()`).
327 * @return Vector containing copies of all messages
328 */
329 [[nodiscard]] constexpr auto Collect() const -> std::vector<T>;
330
331 /**
332 * @brief Collects all messages into a vector of raw `T` values using a custom
333 * allocator.
334 * @tparam Alloc STL-compatible allocator type for `T`
335 * @param alloc Allocator instance
336 * @return Vector containing copies of all messages, using the provided
337 * allocator
338 */
339 template <typename Alloc>
340 requires std::same_as<typename std::allocator_traits<Alloc>::value_type, T>
341 [[nodiscard]] constexpr auto CollectWith(const Alloc& alloc) const
342 -> std::vector<T, Alloc>;
343
344 /**
345 * @brief Collects all messages into a vector of raw `T` values using a memory
346 * resource.
347 * @param resource Memory resource for allocating the vector
348 * @return Vector containing copies of all messages, using the provided
349 * memory resource
350 */
351 [[nodiscard]] constexpr auto CollectWith(
352 std::pmr::memory_resource* resource) const -> std::pmr::vector<T>;
353
354 auto CollectWith(std::nullptr_t) const -> std::pmr::vector<T> = delete;
355
356 /**
357 * @brief Reads all messages into an output iterator.
358 * @tparam OutIt Output iterator type for `T`
359 * @param out Output iterator
360 */
361 template <typename OutIt>
362 requires std::output_iterator<OutIt, T>
363 constexpr void ReadInto(OutIt out) const;
364
365 /**
366 * @brief Returns a lazy filter adapter over the wrapped message sequence.
367 * @details The adapter yields only those wrapper elements for
368 * which `predicate` returns `true`. Chain further adapters or call terminal
369 * operations (`.Collect()`, `.ForEach()`, etc.) on the result.
370 * @tparam Pred Predicate type `(const value_type&) -> bool`
371 * @param predicate Filter predicate
372 * @return `FilterAdapter` over the iterator
373 */
374 template <typename Pred>
375 requires std::predicate<Pred, const value_type&>
376 [[nodiscard]] constexpr auto Filter(Pred predicate) const
377 noexcept(noexcept(GetDerived().begin().Filter(std::move(predicate))))
378 -> utils::FilterAdapter<iterator, Pred> {
379 return GetDerived().begin().Filter(std::move(predicate));
380 }
381
382 /**
383 * @brief Returns a lazy map adapter over the wrapped message sequence.
384 * @details Each wrapper is transformed by `transform`.
385 * @tparam Func Transform type `(const value_type&) -> R`
386 * @param transform Transformation function
387 * @return `MapAdapter` over the iterator
388 */
389 template <typename Func>
390 requires std::invocable<Func, const value_type&>
391 [[nodiscard]] constexpr auto Map(Func transform) const
392 noexcept(noexcept(GetDerived().begin().Map(std::move(transform))))
394 return GetDerived().begin().Map(std::move(transform));
395 }
396
397 /**
398 * @brief Returns a lazy adapter yielding at most `count` wrappers.
399 * @param count Maximum number of elements to yield
400 * @return `TakeAdapter` over the iterator
401 */
402 [[nodiscard]] constexpr auto Take(size_t count) const
403 noexcept(noexcept(GetDerived().begin().Take(count)))
405 return GetDerived().begin().Take(count);
406 }
407
408 /**
409 * @brief Returns a lazy adapter that skips the first `count` wrappers.
410 * @param count Number of elements to skip
411 * @return `SkipAdapter` over the iterator
412 */
413 [[nodiscard]] constexpr auto Skip(size_t count) const
414 noexcept(noexcept(GetDerived().begin().Skip(count)))
416 return GetDerived().begin().Skip(count);
417 }
418
419 /**
420 * @brief Returns a lazy adapter that yields wrappers while `predicate` is
421 * true.
422 * @tparam Pred Predicate type `(const value_type&) -> bool`
423 * @param predicate Stop condition
424 * @return `TakeWhileAdapter` over the iterator
425 */
426 template <typename Pred>
427 requires std::predicate<Pred, const value_type&>
428 [[nodiscard]] constexpr auto TakeWhile(Pred predicate) const
429 noexcept(noexcept(GetDerived().begin().TakeWhile(std::move(predicate))))
431 return GetDerived().begin().TakeWhile(std::move(predicate));
432 }
433
434 /**
435 * @brief Returns a lazy adapter that skips wrappers while `predicate` is
436 * true.
437 * @tparam Pred Predicate type `(const value_type&) -> bool`
438 * @param predicate Skip condition
439 * @return `SkipWhileAdapter` over the iterator
440 */
441 template <typename Pred>
442 requires std::predicate<Pred, const value_type&>
443 [[nodiscard]] constexpr auto SkipWhile(Pred predicate) const
444 noexcept(noexcept(GetDerived().begin().SkipWhile(std::move(predicate))))
446 return GetDerived().begin().SkipWhile(std::move(predicate));
447 }
448
449 /**
450 * @brief Returns a lazy adapter that pairs each wrapper with its zero-based
451 * index.
452 * @return `EnumerateAdapter` over the iterator
453 */
454 [[nodiscard]] constexpr auto Enumerate() const
455 noexcept(noexcept(GetDerived().begin().Enumerate()))
456 -> utils::EnumerateAdapter<iterator> {
457 return GetDerived().begin().Enumerate();
458 }
459
460 /**
461 * @brief Returns a lazy adapter that calls `inspector` on each wrapper as a
462 * side-effect.
463 * @tparam Func Inspector type `(const value_type&) -> void`
464 * @param inspector Side-effect function
465 * @return `InspectAdapter` over the iterator
466 */
467 template <typename Func>
468 requires std::invocable<Func, const value_type&>
469 [[nodiscard]] constexpr auto Inspect(Func inspector) const
470 noexcept(noexcept(GetDerived().begin().Inspect(std::move(inspector))))
472 return GetDerived().begin().Inspect(std::move(inspector));
473 }
474
475 /**
476 * @brief Returns a lazy adapter that yields every `step`-th wrapper.
477 * @param step Step size (must be > 0)
478 * @warning Triggers assertion if `step == 0`.
479 * @return `StepByAdapter` over the iterator
480 */
481 [[nodiscard]] constexpr auto StepBy(size_t step) const
482 noexcept(noexcept(GetDerived().begin().StepBy(step)))
484 return GetDerived().begin().StepBy(step);
485 }
486
487 /**
488 * @brief Returns a lazy adapter that chains another range of wrappers.
489 * @tparam Iter Iterator type of the range
490 * @param first Iterator to the first element of the range
491 * @param last Iterator to the end of the range
492 * @return `ChainAdapter` over the iterator
493 */
494 template <typename Iter>
496 [[nodiscard]] constexpr auto Chain(Iter first, Iter last) const
497 noexcept(noexcept(GetDerived().begin().Chain(std::move(first),
498 std::move(last))))
500 return GetDerived().begin().Chain(std::move(first), std::move(last));
501 }
502
503 /**
504 * @brief Returns a lazy adapter that chains another range of wrappers.
505 * @tparam R Range type
506 * @param range Range to chain
507 * @return `ChainAdapter` over the iterator
508 */
509 template <std::ranges::input_range R>
511 std::ranges::iterator_t<R>>
512 [[nodiscard]] constexpr auto Chain(const R& range) const
513 noexcept(noexcept(GetDerived().begin().Chain(range)))
514 -> utils::ChainAdapter<iterator, std::ranges::iterator_t<R>> {
515 return GetDerived().begin().Chain(range);
516 }
517
518 /**
519 * @brief Returns a lazy adapter that yields wrappers in reverse order.
520 * @return `ReverseAdapter` over the iterator
521 */
522 [[nodiscard]] constexpr auto Reverse() const
523 noexcept(noexcept(GetDerived().begin().Reverse()))
524 -> utils::ReverseAdapter<iterator> {
525 return GetDerived().begin().Reverse();
526 }
527
528 /**
529 * @brief Returns a lazy adapter that yields windows of `window_size`
530 * wrappers.
531 * @param window_size Number of wrappers to include in each window
532 * @return `SlideAdapter` over the iterator
533 */
534 [[nodiscard]] constexpr auto Slide(size_t window_size) const
535 noexcept(noexcept(GetDerived().begin().Slide(window_size)))
537 return GetDerived().begin().Slide(window_size);
538 }
539
540 /**
541 * @brief Returns a lazy adapter that yields every `stride`-th wrapper.
542 * @param stride Number of wrappers to skip between each yield
543 * @return `StrideAdapter` over the iterator
544 */
545 [[nodiscard]] constexpr auto Stride(size_t stride) const
546 noexcept(noexcept(GetDerived().begin().Stride(stride)))
548 return GetDerived().begin().Stride(stride);
549 }
550
551 /**
552 * @brief Returns a lazy adapter that yields pairs of wrappers from two
553 * ranges.
554 * @tparam Iter Type of the iterator for the second range
555 * @param first Iterator to the first element of the second range
556 * @param last Iterator to the end of the second range
557 * @return `ZipAdapter` over the iterator
558 */
559 template <typename Iter>
561 [[nodiscard]] constexpr auto Zip(Iter first, Iter last) const
562 noexcept(noexcept(GetDerived().begin().Zip(std::move(first),
563 std::move(last))))
565 return GetDerived().begin().Zip(std::move(first), std::move(last));
566 }
567
568 /**
569 * @brief Returns a lazy adapter that yields pairs of wrappers from two
570 * ranges.
571 * @tparam R Type of the range for the second range
572 * @param range The range to zip with the first range
573 * @return `ZipAdapter` over the iterator
574 */
575 template <typename R>
577 [[nodiscard]] constexpr auto Zip(const R& range) const
578 noexcept(noexcept(GetDerived().begin().Zip(range)))
579 -> utils::ZipAdapter<iterator, std::ranges::iterator_t<R>> {
580 return GetDerived().begin().Zip(range);
581 }
582
583 /**
584 * @brief Left-folds all messages with an accumulator.
585 * @tparam Acc Accumulator type
586 * @tparam Folder Callable type `(Acc, const value_type&) -> Acc`
587 * @param init Initial accumulator value
588 * @param folder Folding function
589 * @return Final accumulated value
590 */
591 template <typename Acc, typename Folder>
592 requires std::invocable<Folder, Acc, const value_type&>
593 [[nodiscard]] constexpr Acc Fold(Acc init, const Folder& folder) const {
594 return GetDerived().begin().Fold(init, folder);
595 }
596
597 /**
598 * @brief Returns a pointer to the first message matching a predicate.
599 * @tparam Pred Predicate type `(const value_type&) -> bool`
600 * @param predicate Predicate function
601 * @return Optional containing the first matching message, or `std::nullopt`
602 * if none found
603 */
604 template <typename Pred>
605 requires std::predicate<Pred, const value_type&>
606 [[nodiscard]] constexpr auto Find(const Pred& predicate) const
607 -> std::optional<value_type> {
608 return GetDerived().begin().Find(predicate);
609 }
610
611 /**
612 * @brief Counts messages matching a predicate.
613 * @tparam Pred Predicate type `(const value_type&) -> bool`
614 * @param predicate Predicate function
615 * @return Number of matching messages
616 */
617 template <typename Pred>
618 requires std::predicate<Pred, const value_type&>
619 [[nodiscard]] constexpr size_type CountIf(const Pred& predicate) const {
620 return GetDerived().begin().CountIf(predicate);
621 }
622
623 /**
624 * @brief Partitions wrapped messages into matching and non-matching groups.
625 * @tparam Pred Predicate type `(const value_type&) -> bool`
626 * @param predicate Predicate function
627 * @return Pair of vectors: first contains matching wrappers, second contains
628 * non-matching wrappers
629 */
630 template <typename Pred>
631 requires std::predicate<Pred, const value_type&>
632 [[nodiscard]] constexpr auto Partition(const Pred& predicate) const
633 -> std::pair<std::vector<value_type>, std::vector<value_type>> {
634 return GetDerived().begin().Partition(predicate);
635 }
636
637 /**
638 * @brief Finds the wrapped message with the maximum extracted key.
639 * @tparam KeyFunc Key extractor type `(const value_type&) -> Key`
640 * @param key_func Key extraction function
641 * @return Matching wrapper, or `std::nullopt` if the reader is empty
642 */
643 template <typename KeyFunc>
644 requires std::invocable<KeyFunc, const value_type&>
645 [[nodiscard]] constexpr auto MaxBy(const KeyFunc& key_func) const
646 -> std::optional<value_type> {
647 return GetDerived().begin().MaxBy(key_func);
648 }
649
650 /**
651 * @brief Finds the wrapped message with the minimum extracted key.
652 * @tparam KeyFunc Key extractor type `(const value_type&) -> Key`
653 * @param key_func Key extraction function
654 * @return Matching wrapper, or `std::nullopt` if the reader is empty
655 */
656 template <typename KeyFunc>
657 requires std::invocable<KeyFunc, const value_type&>
658 [[nodiscard]] constexpr auto MinBy(const KeyFunc& key_func) const
659 -> std::optional<value_type> {
660 return GetDerived().begin().MinBy(key_func);
661 }
662
663 /**
664 * @brief Groups wrapped messages by a key extracted from each wrapper.
665 * @tparam KeyFunc Key extractor type `(const value_type&) -> Key`
666 * @param key_func Key extraction function
667 * @return Hash map from key to grouped wrappers
668 */
669 template <typename KeyFunc>
670 requires std::invocable<KeyFunc, const value_type&>
671 [[nodiscard]] constexpr auto GroupBy(const KeyFunc& key_func) const
672 -> std::unordered_map<
673 std::decay_t<std::invoke_result_t<KeyFunc, const value_type&>>,
674 std::vector<value_type>> {
675 return GetDerived().begin().GroupBy(key_func);
676 }
677
678 /**
679 * @brief Checks if any message matches a predicate.
680 * @tparam Pred Predicate type `(const value_type&) -> bool`
681 * @param predicate Predicate function
682 * @return `true` if at least one message matches
683 */
684 template <typename Pred>
685 requires std::predicate<Pred, const value_type&>
686 [[nodiscard]] constexpr bool Any(const Pred& predicate) const {
687 return GetDerived().begin().Any(predicate);
688 }
689
690 /**
691 * @brief Checks if all messages match a predicate.
692 * @tparam Pred Predicate type `(const value_type&) -> bool`
693 * @param predicate Predicate function
694 * @return `true` if all messages match (vacuously true if empty)
695 */
696 template <typename Pred>
697 requires std::predicate<Pred, const value_type&>
698 [[nodiscard]] constexpr bool All(const Pred& predicate) const {
699 return GetDerived().begin().All(predicate);
700 }
701
702 /**
703 * @brief Checks if no messages match a predicate.
704 * @tparam Pred Predicate type `(const value_type&) -> bool`
705 * @param predicate Predicate function
706 * @return `true` if no messages match (vacuously true if empty)
707 */
708 template <typename Pred>
709 requires std::predicate<Pred, const value_type&>
710 [[nodiscard]] constexpr bool None(const Pred& predicate) const {
711 return GetDerived().begin().None(predicate);
712 }
713
714 /**
715 * @brief Checks if there are no messages.
716 * @return `true` if both previous and current spans are empty
717 */
718 [[nodiscard]] constexpr bool Empty() const noexcept {
719 return GetDerived().PreviousMessages().empty() &&
720 GetDerived().CurrentMessages().empty();
721 }
722
723 /**
724 * @brief Returns the total number of messages (previous + current).
725 * @return Total message count
726 */
727 [[nodiscard]] constexpr size_type Count() const noexcept {
728 return GetDerived().PreviousMessages().size() +
729 GetDerived().CurrentMessages().size();
730 }
731
732private:
733 [[nodiscard]] constexpr Derived& GetDerived() noexcept {
734 return static_cast<Derived&>(*this);
735 }
736
737 [[nodiscard]] constexpr const Derived& GetDerived() const noexcept {
738 return static_cast<const Derived&>(*this);
739 }
740};
741
742/**
743 * @brief Type-safe, zero-copy reader for regular messages.
744 * @details Provides a read-only view over the combined (previous + current)
745 * message queues for a specific message type. Messages are accessed via spans
746 * directly into the underlying `TypedBuffer` storage — no copying is performed.
747 *
748 * For regular (non-consumable) messages, no consumption support is available.
749 *
750 * @note Thread-safe.
751 * @tparam T Message type satisfying `MessageTrait`
752 *
753 * @code
754 * // Wrapper iteration
755 * for (auto wrapper : reader) {
756 * // Use wrapper
757 * }
758 *
759 * // Lazy adapter chaining
760 * reader.Filter([](const auto& w) { return (*w).amount > 10; })
761 * .ForEach([](const auto& w) { ... });
762 *
763 * // Direct span access
764 * auto prev = reader.PreviousMessages();
765 * auto curr = reader.CurrentMessages();
766 * @endcode
767 */
768template <MessageTrait T>
769 requires(!ConsumableMessageTrait<T>)
770class MessageReader final
772 friend class MessageReaderBase<MessageReader<T>, T, MessageWrapperIter<T>>;
773
774public:
779
780 /**
781 * @brief Constructs a `MessageReader` from explicit spans.
782 * @param previous Span of messages from the previous frame
783 * @param current Span of messages from the current frame
784 */
785 constexpr MessageReader(std::span<const T> previous,
786 std::span<const T> current) noexcept
787 : previous_(previous), current_(current) {}
788
789 /**
790 * @brief Constructs a `MessageReader` from the message manager.
791 * @param manager Const reference to the message manager
792 */
793 explicit constexpr MessageReader(const MessageManager& manager) noexcept
794 : MessageReader(manager.PreviousMessages<T>(),
795 manager.CurrentMessages<T>()) {}
796
798 constexpr MessageReader(MessageReader&&) noexcept = default;
799 constexpr ~MessageReader() noexcept = default;
800
801 MessageReader& operator=(MessageReader&) = delete;
802 constexpr MessageReader& operator=(MessageReader&&) noexcept = default;
803
804 /**
805 * @brief Gets the messages from the previous frame.
806 * @return Span of const messages from the previous queue
807 */
808 [[nodiscard]] constexpr auto PreviousMessages() const noexcept
809 -> std::span<const T> {
810 return previous_;
811 }
812
813 /**
814 * @brief Gets the messages from the current frame.
815 * @return Span of const messages from the current queue
816 */
817 [[nodiscard]] constexpr auto CurrentMessages() const noexcept
818 -> std::span<const T> {
819 return current_;
820 }
821
822 /**
823 * @brief Returns a const iterator to the first message in the combined view.
824 * @return Const iterator to the beginning
825 */
826 [[nodiscard]] constexpr const_iterator begin() const noexcept {
827 return {previous_, current_, 0};
828 }
829
830 /**
831 * @brief Returns a const iterator past the last message in the combined view.
832 * @return Const iterator to the end
833 */
834 [[nodiscard]] constexpr const_iterator end() const noexcept {
835 return {previous_, current_, previous_.size() + current_.size()};
836 }
837
838private:
839 std::span<const T> previous_;
840 std::span<const T> current_;
841};
842
843/**
844 * @brief Type-safe, zero-copy reader for consumable messages with consume
845 * support.
846 * @details Provides a read-only view over the combined (previous + current)
847 * message queues for a specific message type. Messages are accessed via spans
848 * directly into the underlying `TypedBuffer` storage — no copying is performed.
849 *
850 * Consumed messages are not filtered during iteration within the same frame.
851 * They are removed at the next `MessageManager::Update` call.
852 *
853 * @note Thread-safe, but beware that `ConsumableMessageWrapper`'s `Consume()`
854 * method is NOT thread-safe.
855 * @tparam T Message type satisfying `ConsumableMessageTrait`
856 *
857 * @code
858 * // Wrapper iteration — with consume support
859 * for (auto wrapper : reader) {
860 * if ((*wrapper).priority > 5) {
861 * wrapper.Consume();
862 * }
863 * }
864 *
865 * // Lazy adapter chaining — operates on ConsumableMessageWrapper<T>
866 * reader.Filter([](const auto& w) { return (*w).amount > 10; })
867 * .ForEach([](const auto& w) { w.Consume(); });
868 *
869 * // Direct span access
870 * auto prev = reader.PreviousMessages();
871 * auto curr = reader.CurrentMessages();
872 * @endcode
873 */
874template <ConsumableMessageTrait T>
876 : public MessageReaderBase<ConsumableMessageReader<T>, T,
877 ConsumableMessageWrapperIter<T>> {
880
881public:
886
887 /**
888 * @brief Constructs a `ConsumableMessageReader` from explicit spans and a
889 * consumed registry.
890 * @param previous Span of messages from the previous frame
891 * @param current Span of messages from the current frame
892 * @param consumed_registry Mutable reference to the per-system consumed
893 * messages registry
894 */
896 std::span<const T> previous, std::span<const T> current,
897 ConsumedMessagesRegistry<>& consumed_registry) noexcept
898 : previous_(previous), current_(current), registry_(consumed_registry) {}
899
900 /**
901 * @brief Constructs a `ConsumableMessageReader` from the message manager and
902 * a per-system consumed registry.
903 * @param manager Const reference to the message manager
904 * @param consumed_registry Mutable reference to the per-system consumed
905 * messages registry
906 */
908 const MessageManager& manager,
909 ConsumedMessagesRegistry<>& consumed_registry) noexcept
910 : ConsumableMessageReader(manager.PreviousMessages<T>(),
911 manager.CurrentMessages<T>(),
912 consumed_registry) {}
913
916 default;
917 constexpr ~ConsumableMessageReader() noexcept = default;
918
920 constexpr ConsumableMessageReader& operator=(
921 ConsumableMessageReader&&) noexcept = default;
922
923 /// @brief Marks all messages as consumed.
924 constexpr void ConsumeAll() const;
925
926 /**
927 * @brief Marks all messages matching a predicate as consumed.
928 * @tparam Pred Predicate type `(const T&) -> bool`
929 * @param predicate Predicate function
930 * @return Number of messages marked as consumed
931 */
932 template <typename Pred>
933 requires std::predicate<Pred, const T&>
934 constexpr size_type ConsumeIf(const Pred& predicate) const;
935
936 /**
937 * @brief Gets the messages from the previous frame.
938 * @return Span of const messages from the previous queue
939 */
940 [[nodiscard]] constexpr auto PreviousMessages() const noexcept
941 -> std::span<const T> {
942 return previous_;
943 }
944
945 /**
946 * @brief Gets the messages from the current frame.
947 * @return Span of const messages from the current queue
948 */
949 [[nodiscard]] constexpr auto CurrentMessages() const noexcept
950 -> std::span<const T> {
951 return current_;
952 }
953
954 /**
955 * @brief Returns a const iterator to the first message in the combined view.
956 * @return Const iterator to the beginning
957 */
958 [[nodiscard]] constexpr const_iterator begin() const noexcept {
959 return {previous_, current_, registry_, 0};
960 }
961
962 /**
963 * @brief Returns a const iterator past the last message in the combined view.
964 * @return Const iterator to the end
965 */
966 [[nodiscard]] constexpr const_iterator end() const noexcept {
967 return {previous_, current_, registry_, previous_.size() + current_.size()};
968 }
969
970private:
971 std::span<const T> previous_;
972 std::span<const T> current_;
973 std::reference_wrapper<ConsumedMessagesRegistry<>> registry_;
974};
975
976template <typename Derived, MessageTrait T, typename IterType>
978 const -> std::vector<T> {
979 std::vector<T> result;
980 result.reserve(Count());
981 const auto& derived = GetDerived();
982 std::ranges::copy(derived.PreviousMessages(), std::back_inserter(result));
983 std::ranges::copy(derived.CurrentMessages(), std::back_inserter(result));
984 return result;
985}
986
987template <typename Derived, MessageTrait T, typename IterType>
988template <typename Alloc>
989 requires std::same_as<typename std::allocator_traits<Alloc>::value_type, T>
990[[nodiscard]] constexpr auto
992 -> std::vector<T, Alloc> {
993 std::vector<T, Alloc> result{alloc};
994 result.reserve(Count());
995 const auto& derived = GetDerived();
996 std::ranges::copy(derived.PreviousMessages(), std::back_inserter(result));
997 std::ranges::copy(derived.CurrentMessages(), std::back_inserter(result));
998 return result;
999}
1000
1001template <typename Derived, MessageTrait T, typename IterType>
1002[[nodiscard]] constexpr auto
1004 std::pmr::memory_resource* resource) const -> std::pmr::vector<T> {
1005 std::pmr::vector<T> result{resource};
1006 result.reserve(Count());
1007 const auto& derived = GetDerived();
1008 std::ranges::copy(derived.PreviousMessages(), std::back_inserter(result));
1009 std::ranges::copy(derived.CurrentMessages(), std::back_inserter(result));
1010 return result;
1011}
1012
1013template <typename Derived, MessageTrait T, typename IterType>
1014template <typename OutIt>
1015 requires std::output_iterator<OutIt, T>
1017 OutIt out) const {
1018 const auto& derived = GetDerived();
1019 std::ranges::copy(derived.PreviousMessages(), out);
1020 std::ranges::copy(derived.CurrentMessages(), out);
1021}
1022
1023template <ConsumableMessageTrait T>
1025 auto& registry = registry_.get();
1026 const auto total = this->Count();
1027 for (size_type i = 0; i < total; ++i) {
1028 registry.template MarkConsumed<T>(i);
1029 }
1030}
1031
1032template <ConsumableMessageTrait T>
1033template <typename Pred>
1034 requires std::predicate<Pred, const T&>
1036 const Pred& predicate) const -> size_type {
1037 size_type consumed_count = 0;
1038 auto& registry = registry_.get();
1039 size_type global_index = 0;
1040
1041 for (const auto& message : previous_) {
1042 if (predicate(message)) {
1043 registry.template MarkConsumed<T>(global_index);
1044 ++consumed_count;
1045 }
1046 ++global_index;
1047 }
1048 for (const auto& message : current_) {
1049 if (predicate(message)) {
1050 registry.template MarkConsumed<T>(global_index);
1051 ++consumed_count;
1052 }
1053 ++global_index;
1054 }
1055 return consumed_count;
1056}
1057
1058} // namespace helios::ecs
constexpr size_type ConsumeIf(const Pred &predicate) const
Marks all messages matching a predicate as consumed.
MessageManager::size_type size_type
Definition reader.hpp:883
constexpr ConsumableMessageReader(std::span< const T > previous, std::span< const T > current, ConsumedMessagesRegistry<> &consumed_registry) noexcept
Constructs a ConsumableMessageReader from explicit spans and a consumed registry.
Definition reader.hpp:895
ConsumableMessageWrapperIter< T > const_iterator
Definition reader.hpp:884
constexpr auto PreviousMessages() const noexcept -> std::span< const T >
Gets the messages from the previous frame.
Definition reader.hpp:940
ConsumableMessageWrapper< T > value_type
Definition reader.hpp:882
constexpr auto CurrentMessages() const noexcept -> std::span< const T >
Gets the messages from the current frame.
Definition reader.hpp:949
constexpr ConsumableMessageReader(const MessageManager &manager, ConsumedMessagesRegistry<> &consumed_registry) noexcept
Constructs a ConsumableMessageReader from the message manager and a per-system consumed registry.
Definition reader.hpp:907
constexpr ConsumableMessageReader(ConsumableMessageReader &&) noexcept=default
constexpr void ConsumeAll() const
Marks all messages as consumed.
Definition reader.hpp:1024
constexpr const_iterator begin() const noexcept
Returns a const iterator to the first message in the combined view.
Definition reader.hpp:958
constexpr const_iterator end() const noexcept
Returns a const iterator past the last message in the combined view.
Definition reader.hpp:966
ConsumableMessageReader(ConsumableMessageReader &)=delete
Bidirectional iterator that yields ConsumableMessageWrapper<T> instances with consume support.
Definition reader.hpp:164
constexpr ConsumableMessageWrapperIter & operator++() noexcept
Definition reader.hpp:211
constexpr auto operator<=>(const ConsumableMessageWrapperIter &other) const noexcept
Definition reader.hpp:235
constexpr ConsumableMessageWrapperIter end() const noexcept
Returns a copy of this iterator positioned one past the last element.
Definition reader.hpp:272
constexpr bool operator==(const ConsumableMessageWrapperIter &other) const noexcept
Definition reader.hpp:240
constexpr ConsumableMessageWrapperIter operator++(int) noexcept
Definition reader.hpp:216
constexpr ConsumableMessageWrapperIter begin() const noexcept
Returns a copy of this iterator positioned at the beginning of the sequence.
Definition reader.hpp:263
std::bidirectional_iterator_tag iterator_concept
Definition reader.hpp:166
constexpr ConsumableMessageWrapperIter() noexcept=default
constexpr ConsumableMessageWrapperIter operator--(int) noexcept
Definition reader.hpp:228
ConsumableMessageWrapper< T > value_type
Definition reader.hpp:168
constexpr ConsumableMessageWrapperIter & operator--() noexcept
Definition reader.hpp:223
constexpr ConsumableMessageWrapperIter(const ConsumableMessageWrapperIter &) noexcept=default
constexpr bool operator!=(const ConsumableMessageWrapperIter &other) const noexcept
Definition reader.hpp:245
constexpr size_t Position() const noexcept
Returns the current logical position in the combined sequence.
Definition reader.hpp:254
constexpr ConsumableMessageWrapperIter(ConsumableMessageWrapperIter &&) noexcept=default
std::input_iterator_tag iterator_category
Definition reader.hpp:167
A wrapper around a message that provides convenient access to the message's data, type information,...
Definition wrapper.hpp:29
Per-system registry for tracking consumed message indices.
Central coordinator for message lifecycle with double buffering and consumed message removal.
Definition manager.hpp:54
constexpr bool Empty() const noexcept
Checks if there are no messages.
Definition reader.hpp:718
constexpr size_type CountIf(const Pred &predicate) const
Counts messages matching a predicate.
Definition reader.hpp:619
constexpr auto Enumerate() const noexcept(noexcept(GetDerived().begin().Enumerate())) -> utils::EnumerateAdapter< iterator >
Returns a lazy adapter that pairs each wrapper with its zero-based index.
Definition reader.hpp:454
constexpr auto Chain(Iter first, Iter last) const noexcept(noexcept(GetDerived().begin().Chain(std::move(first), std::move(last)))) -> utils::ChainAdapter< iterator, Iter >
Returns a lazy adapter that chains another range of wrappers.
Definition reader.hpp:496
constexpr void ForEach(const Action &action) const
Applies an action to every message (unwrapped const T&).
Definition reader.hpp:317
constexpr bool All(const Pred &predicate) const
Checks if all messages match a predicate.
Definition reader.hpp:698
constexpr bool None(const Pred &predicate) const
Checks if no messages match a predicate.
Definition reader.hpp:710
constexpr auto StepBy(size_t step) const noexcept(noexcept(GetDerived().begin().StepBy(step))) -> utils::StepByAdapter< iterator >
Returns a lazy adapter that yields every step-th wrapper.
Definition reader.hpp:481
constexpr auto Stride(size_t stride) const noexcept(noexcept(GetDerived().begin().Stride(stride))) -> utils::StrideAdapter< iterator >
Returns a lazy adapter that yields every stride-th wrapper.
Definition reader.hpp:545
constexpr auto GroupBy(const KeyFunc &key_func) const -> std::unordered_map< std::decay_t< std::invoke_result_t< KeyFunc, const value_type & > >, std::vector< value_type > >
Groups wrapped messages by a key extracted from each wrapper.
Definition reader.hpp:671
constexpr auto Zip(const R &range) const noexcept(noexcept(GetDerived().begin().Zip(range))) -> utils::ZipAdapter< iterator, std::ranges::iterator_t< R > >
Returns a lazy adapter that yields pairs of wrappers from two ranges.
Definition reader.hpp:577
constexpr bool Any(const Pred &predicate) const
Checks if any message matches a predicate.
Definition reader.hpp:686
constexpr auto Find(const Pred &predicate) const -> std::optional< value_type >
Returns a pointer to the first message matching a predicate.
Definition reader.hpp:606
constexpr Acc Fold(Acc init, const Folder &folder) const
Left-folds all messages with an accumulator.
Definition reader.hpp:593
constexpr auto Collect() const -> std::vector< T >
Collects all messages (previous + current) into a vector of raw T values.
Definition reader.hpp:977
constexpr auto Filter(Pred predicate) const noexcept(noexcept(GetDerived().begin().Filter(std::move(predicate)))) -> utils::FilterAdapter< iterator, Pred >
Returns a lazy filter adapter over the wrapped message sequence.
Definition reader.hpp:376
constexpr size_type Count() const noexcept
Returns the total number of messages (previous + current).
Definition reader.hpp:727
constexpr auto Map(Func transform) const noexcept(noexcept(GetDerived().begin().Map(std::move(transform)))) -> utils::MapAdapter< iterator, Func >
Returns a lazy map adapter over the wrapped message sequence.
Definition reader.hpp:391
typename IterType::value_type value_type
Definition reader.hpp:296
constexpr auto Reverse() const noexcept(noexcept(GetDerived().begin().Reverse())) -> utils::ReverseAdapter< iterator >
Returns a lazy adapter that yields wrappers in reverse order.
Definition reader.hpp:522
constexpr auto TakeWhile(Pred predicate) const noexcept(noexcept(GetDerived().begin().TakeWhile(std::move(predicate)))) -> utils::TakeWhileAdapter< iterator, Pred >
Returns a lazy adapter that yields wrappers while predicate is true.
Definition reader.hpp:428
constexpr auto Chain(const R &range) const noexcept(noexcept(GetDerived().begin().Chain(range))) -> utils::ChainAdapter< iterator, std::ranges::iterator_t< R > >
Returns a lazy adapter that chains another range of wrappers.
Definition reader.hpp:512
constexpr MessageReaderBase() noexcept=default
constexpr auto Take(size_t count) const noexcept(noexcept(GetDerived().begin().Take(count))) -> utils::TakeAdapter< iterator >
Returns a lazy adapter yielding at most count wrappers.
Definition reader.hpp:402
constexpr auto SkipWhile(Pred predicate) const noexcept(noexcept(GetDerived().begin().SkipWhile(std::move(predicate)))) -> utils::SkipWhileAdapter< iterator, Pred >
Returns a lazy adapter that skips wrappers while predicate is true.
Definition reader.hpp:443
MessageManager::size_type size_type
Definition reader.hpp:297
constexpr auto Skip(size_t count) const noexcept(noexcept(GetDerived().begin().Skip(count))) -> utils::SkipAdapter< iterator >
Returns a lazy adapter that skips the first count wrappers.
Definition reader.hpp:413
constexpr auto Inspect(Func inspector) const noexcept(noexcept(GetDerived().begin().Inspect(std::move(inspector)))) -> utils::InspectAdapter< iterator, Func >
Returns a lazy adapter that calls inspector on each wrapper as a side-effect.
Definition reader.hpp:469
constexpr auto Slide(size_t window_size) const noexcept(noexcept(GetDerived().begin().Slide(window_size))) -> utils::SlideAdapter< iterator >
Returns a lazy adapter that yields windows of window_size wrappers.
Definition reader.hpp:534
constexpr auto Partition(const Pred &predicate) const -> std::pair< std::vector< value_type >, std::vector< value_type > >
Partitions wrapped messages into matching and non-matching groups.
Definition reader.hpp:632
constexpr auto MaxBy(const KeyFunc &key_func) const -> std::optional< value_type >
Finds the wrapped message with the maximum extracted key.
Definition reader.hpp:645
constexpr auto CollectWith(const Alloc &alloc) const -> std::vector< T, Alloc >
Definition reader.hpp:991
constexpr auto MinBy(const KeyFunc &key_func) const -> std::optional< value_type >
Finds the wrapped message with the minimum extracted key.
Definition reader.hpp:658
constexpr auto Zip(Iter first, Iter last) const noexcept(noexcept(GetDerived().begin().Zip(std::move(first), std::move(last)))) -> utils::ZipAdapter< iterator, Iter >
Returns a lazy adapter that yields pairs of wrappers from two ranges.
Definition reader.hpp:561
const_iterator iterator
Definition reader.hpp:778
constexpr MessageReader(const MessageManager &manager) noexcept
Constructs a MessageReader from the message manager.
Definition reader.hpp:793
MessageManager::size_type size_type
Definition reader.hpp:776
constexpr MessageReader(MessageReader &&) noexcept=default
MessageWrapperIter< T > const_iterator
Definition reader.hpp:777
constexpr const_iterator end() const noexcept
Returns a const iterator past the last message in the combined view.
Definition reader.hpp:834
constexpr auto CurrentMessages() const noexcept -> std::span< const T >
Gets the messages from the current frame.
Definition reader.hpp:817
constexpr const_iterator begin() const noexcept
Returns a const iterator to the first message in the combined view.
Definition reader.hpp:826
constexpr MessageReader(std::span< const T > previous, std::span< const T > current) noexcept
Constructs a MessageReader from explicit spans.
Definition reader.hpp:785
MessageReader(MessageReader &)=delete
constexpr auto PreviousMessages() const noexcept -> std::span< const T >
Gets the messages from the previous frame.
Definition reader.hpp:808
MessageWrapper< T > value_type
Definition reader.hpp:775
Bidirectional iterator that yields MessageWrapper<T> instances.
Definition reader.hpp:39
constexpr MessageWrapperIter() noexcept=default
constexpr bool operator==(const MessageWrapperIter &other) const noexcept
Definition reader.hpp:106
constexpr bool operator!=(const MessageWrapperIter &other) const noexcept
Definition reader.hpp:111
constexpr MessageWrapperIter operator--(int) noexcept
Definition reader.hpp:95
constexpr MessageWrapperIter end() const noexcept
Returns a copy of this iterator positioned one past the last element.
Definition reader.hpp:138
constexpr auto operator<=>(const MessageWrapperIter &other) const noexcept
Definition reader.hpp:101
MessageWrapper< T > value_type
Definition reader.hpp:43
constexpr MessageWrapperIter(MessageWrapperIter &&) noexcept=default
constexpr MessageWrapperIter begin() const noexcept
Returns a copy of this iterator positioned at the beginning of the sequence.
Definition reader.hpp:129
constexpr MessageWrapperIter(const MessageWrapperIter &) noexcept=default
constexpr MessageWrapperIter operator++(int) noexcept
Definition reader.hpp:84
constexpr MessageWrapperIter & operator--() noexcept
Definition reader.hpp:90
std::input_iterator_tag iterator_category
Definition reader.hpp:42
constexpr size_t Position() const noexcept
Returns the current logical position in the combined sequence.
Definition reader.hpp:120
constexpr MessageWrapperIter & operator++() noexcept
Definition reader.hpp:79
pointer operator->() const =delete
std::bidirectional_iterator_tag iterator_concept
Definition reader.hpp:41
A wrapper around a message that provides convenient access to the message's data and type information...
Definition wrapper.hpp:143
Iterator adapter that chains two sequences together.
CRTP base class providing common adapter operations.
Iterator adapter that applies a function to each element for observation.
Iterator adapter that transforms each element using a function.
Iterator adapter that skips the first N elements.
Iterator adapter that skips elements while a predicate returns true.
Adapter that yields sliding windows of elements.
Iterator adapter that steps through elements by a specified stride.
Adapter that yields every Nth element from the range.
Iterator adapter that yields only the first N elements.
Iterator adapter that takes elements while a predicate returns true.
Adapter that combines two ranges into pairs.
Concept to validate ChainAdapter requirements.
Concept to validate ZipAdapter requirements.
STL namespace.