Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
query.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/core_pch.hpp>
4
16
17#include <algorithm>
18#include <array>
19#include <concepts>
20#include <cstddef>
21#include <functional>
22#include <iterator>
23#include <memory>
24#include <optional>
25#include <span>
26#include <tuple>
27#include <type_traits>
28#include <unordered_map>
29#include <utility>
30#include <vector>
31
32namespace helios::ecs {
33
34namespace details {
35
36/**
37 * @brief Type trait to extract the underlying component type from const/reference wrappers.
38 * @details Handles cases like:
39 * - const Position& -> Position
40 * - Position& -> Position
41 * - Position -> Position
42 * @tparam T Type to extract from (may be const-qualified or reference type)
43 */
44template <typename T>
46 using type = std::remove_cvref_t<T>;
47};
48
49template <typename T>
51
52/**
53 * @brief Helper to check if a type represents a const-qualified component access.
54 * @details Determines if the requested access is const-qualified for read-only operations.
55 * @tparam T Type to check for const qualification
56 */
57template <typename T>
58constexpr bool IsConstComponent = std::is_const_v<std::remove_reference_t<T>>;
59
60/**
61 * @brief Helper to check if all component types are const-qualified.
62 * @details Used to determine if an iterator can work with const Components.
63 * @tparam Components Component types to check
64 */
65template <typename... Components>
67
68/**
69 * @brief Helper to detect if World type is const.
70 * @details Used for compile-time validation of const World access.
71 * @tparam T World type
72 */
73template <typename T>
74constexpr bool IsConstWorld = WorldType<T> && std::is_const_v<std::remove_reference_t<T>>;
75
76/**
77 * @brief Concept for valid World/Component access combinations.
78 * @details Ensures that:
79 * - Non-const World allows any component access (const or mutable)
80 * - Const World only allows const component access
81 * @tparam WorldT World type (World or const World)
82 * @tparam Components Component access types to validate
83 */
84template <typename WorldT, typename... Components>
86 WorldType<WorldT> && (!IsConstWorld<WorldT> || // Non-const World allows anything
87 (IsConstComponent<Components> && ...)); // Const World requires all const Components
88
89/**
90 * @brief Helper to determine the proper return type for component access.
91 * @details Returns appropriate reference type based on const qualification:
92 * - const T& for const-qualified access
93 * - T& for mutable access
94 * - T for value types (copy)
95 * @tparam T Requested component access type
96 */
97template <typename T>
99 std::conditional_t<std::is_reference_v<T>,
100 T, // Keep reference as-is (const T& or T&)
101 std::conditional_t<std::is_const_v<T>,
102 const ComponentTypeExtractor_t<T>&, // const T -> const T&
104 >>;
105
106/**
107 * @brief Concept for STL-compatible allocators.
108 * @tparam Alloc Allocator type to check
109 * @tparam T Value type for the allocator
110 */
111template <typename Alloc, typename T>
112concept AllocatorFor = requires(Alloc alloc, size_t n) {
113 { alloc.allocate(n) } -> std::same_as<T*>;
114 { alloc.deallocate(std::declval<T*>(), n) };
115 typename Alloc::value_type;
116 requires std::same_as<typename Alloc::value_type, T>;
117};
118
119/**
120 * @brief Iterator for query results without entity information.
121 * @details Provides forward iteration over entities matching the query criteria,
122 * returning tuples of requested component references. Supports const-qualified
123 * component access for read-only operations.
124 * @note Not thread-safe.
125 * @tparam Components Requested component access types (may include const qualifiers)
126 */
127template <ComponentTrait... Components>
128 requires utils::UniqueTypes<Components...>
129class QueryIterator : public utils::FunctionalAdapterBase<QueryIterator<Components...>> {
130public:
131 /// Components manager type based on whether all components are const-qualified
134
135 // Standard iterator type aliases required by C++20 concepts
136 using iterator_category = std::forward_iterator_tag;
137 using value_type = std::tuple<ComponentAccessType<Components>...>;
141
142 /**
143 * @brief Constructs iterator for query results.
144 * @details Initializes iterator to point to the first matching entity.
145 * @param archetypes Span of archetypes matching the query
146 * @param components Component manager for accessing component data
147 * @param archetype_index Starting archetype index (default: 0)
148 * @param entity_index Starting entity index within archetype (default: 0)
149 */
150 QueryIterator(std::span<const std::reference_wrapper<const Archetype>> archetypes, ComponentsType& components,
151 size_t archetype_index = 0, size_t entity_index = 0);
152 QueryIterator(const QueryIterator&) noexcept = default;
155
158
159 /**
160 * @brief Advances iterator to next matching entity.
161 * @return Reference to this iterator after advancement
162 */
164
165 /**
166 * @brief Advances iterator to next matching entity.
167 * @return Copy of iterator before advancement
168 */
169 QueryIterator operator++(int);
170
171 /**
172 * @brief Moves iterator to previous matching entity.
173 * @return Reference to this iterator after moving backward
174 */
176
177 /**
178 * @brief Moves iterator to previous matching entity.
179 * @return Copy of iterator before moving backward
180 */
181 QueryIterator operator--(int);
182
183 /**
184 * @brief Dereferences iterator to get component tuple.
185 * @details Returns tuple of component references for the current entity.
186 * Handles const-qualified access appropriately.
187 * @warning Triggers assertion if iterator is at end or in invalid state.
188 * @return Tuple of component references with appropriate const qualifiers
189 */
191
192 /**
193 * @brief Compares iterators for equality.
194 * @details Two iterators are equal if they point to the same archetype and entity indices.
195 * @param other Iterator to compare with
196 * @return True if iterators are equal, false otherwise
197 */
199 return archetype_index_ == other.archetype_index_ && entity_index_ == other.entity_index_;
200 }
201
202 /**
203 * @brief Compares iterators for inequality.
204 * @param other Iterator to compare with
205 * @return True if iterators are not equal, false otherwise
206 */
207 [[nodiscard]] bool operator!=(const QueryIterator& other) const noexcept { return !(*this == other); }
208
209 /**
210 * @brief Returns iterator to the beginning.
211 * @return Copy of this iterator
212 */
214
215 /**
216 * @brief Returns iterator to the end.
217 * @return End iterator
218 */
219 [[nodiscard]] QueryIterator end() const noexcept { return {archetypes_, components_.get(), archetypes_.size(), 0}; }
220
221private:
222 /**
223 * @brief Advances iterator position to next valid entity.
224 * @details Skips empty archetypes and moves to valid entity positions.
225 */
226 void AdvanceToValidEntity();
227
228 /**
229 * @brief Checks if iterator has reached the end.
230 * @return True if iterator is past the last valid entity, false otherwise
231 */
232 [[nodiscard]] bool IsAtEnd() const noexcept { return archetype_index_ >= archetypes_.size(); }
233
234 std::span<const std::reference_wrapper<const Archetype>> archetypes_; ///< Archetypes matching the query
235 std::reference_wrapper<ComponentsType> components_; ///< Component manager for data access
236 size_t archetype_index_ = 0; ///< Current archetype index
237 size_t entity_index_ = 0; ///< Current entity index within archetype
238};
239
240/**
241 * @brief Iterator for query results with entity information.
242 * @details Provides forward iteration over entities matching the query criteria,
243 * returning tuples that include the entity followed by requested component references.
244 * @note Not thread-safe.
245 * @tparam Components Requested component access types (may include const qualifiers)
246 */
247template <ComponentTrait... Components>
248 requires utils::UniqueTypes<Components...>
249class QueryWithEntityIterator : public utils::FunctionalAdapterBase<QueryWithEntityIterator<Components...>> {
250public:
251 /// Components manager type based on whether all components are const-qualified
254
255 // Standard iterator type aliases required by C++20 concepts
256 using iterator_category = std::forward_iterator_tag;
257 using value_type = std::tuple<Entity, ComponentAccessType<Components>...>;
261
262 /**
263 * @brief Constructs iterator for query results with entity.
264 * @details Initializes iterator to point to the first matching entity.
265 * @param archetypes Span of archetypes matching the query
266 * @param components Component manager for accessing component data
267 * @param archetype_index Starting archetype index (default: 0)
268 * @param entity_index Starting entity index within archetype (default: 0)
269 */
270 QueryWithEntityIterator(std::span<const std::reference_wrapper<const Archetype>> archetypes,
271 ComponentsType& components, size_t archetype_index = 0, size_t entity_index = 0);
275
278
279 /**
280 * @brief Advances iterator to next matching entity.
281 * @return Reference to this iterator after advancement
282 */
284
285 /**
286 * @brief Advances iterator to next matching entity.
287 * @return Copy of iterator before advancement
288 */
290
291 /**
292 * @brief Moves iterator to previous matching entity.
293 * @return Reference to this iterator after moving backward
294 */
296
297 /**
298 * @brief Moves iterator to previous matching entity.
299 * @return Copy of iterator before moving backward
300 */
302
303 /**
304 * @brief Dereferences iterator to get entity and component tuple.
305 * @details Returns tuple starting with entity followed by component references.
306 * @warning Triggers assertion if iterator is at end or in invalid state.
307 * @return Tuple of entity and component references
308 */
310
311 /**
312 * @brief Compares iterators for equality.
313 * @param other Iterator to compare with
314 * @return True if iterators are equal, false otherwise
315 */
317 return archetype_index_ == other.archetype_index_ && entity_index_ == other.entity_index_;
318 }
319
320 /**
321 * @brief Compares iterators for inequality.
322 * @param other Iterator to compare with
323 * @return True if iterators are not equal, false otherwise
324 */
325 [[nodiscard]] bool operator!=(const QueryWithEntityIterator& other) const noexcept { return !(*this == other); }
326
327 /**
328 * @brief Returns iterator to the beginning.
329 * @return Copy of this iterator
330 */
332
333 /**
334 * @brief Returns iterator to the end.
335 * @return End iterator
336 */
338 return {archetypes_, components_.get(), archetypes_.size(), 0};
339 }
340
341private:
342 /**
343 * @brief Advances iterator position to next valid entity.
344 * @details Skips empty archetypes and moves to valid entity positions.
345 */
346 void AdvanceToValidEntity();
347
348 /**
349 * @brief Checks if iterator has reached the end.
350 * @return True if iterator is past the last valid entity, false otherwise
351 */
352 [[nodiscard]] bool IsAtEnd() const noexcept { return archetype_index_ >= archetypes_.size(); }
353
354 std::span<const std::reference_wrapper<const Archetype>> archetypes_; ///< Archetypes matching the query
355 std::reference_wrapper<ComponentsType> components_; ///< Component manager for data access
356 size_t archetype_index_ = 0; ///< Current archetype index
357 size_t entity_index_ = 0; ///< Current entity index within archetype
358};
359
360template <ComponentTrait... Components>
361 requires utils::UniqueTypes<Components...>
362QueryIterator<Components...>::QueryIterator(std::span<const std::reference_wrapper<const Archetype>> archetypes,
364 : archetypes_(archetypes), components_(components), archetype_index_(archetype_index), entity_index_(entity_index) {
365 AdvanceToValidEntity();
366}
367
368template <ComponentTrait... Components>
369 requires utils::UniqueTypes<Components...>
371 ++entity_index_;
372 AdvanceToValidEntity();
373 return *this;
374}
375
376template <ComponentTrait... Components>
377 requires utils::UniqueTypes<Components...>
379 auto copy = *this;
380 ++(*this);
381 return copy;
382}
383
384template <ComponentTrait... Components>
385 requires utils::UniqueTypes<Components...>
387 // If at end or beginning of current archetype, need to go back
388 while (true) {
389 if (entity_index_ > 0) {
390 --entity_index_;
391 return *this;
392 }
393
394 // Need to move to previous archetype
395 if (archetype_index_ == 0) {
396 // Already at beginning, can't go back further
397 return *this;
398 }
399
400 --archetype_index_;
401 // Move to last entity in previous archetype
402 if (archetype_index_ < archetypes_.size()) {
403 entity_index_ = archetypes_[archetype_index_].get().EntityCount();
404 if (entity_index_ > 0) {
405 --entity_index_;
406 return *this;
407 }
408 }
409 }
410}
411
412template <ComponentTrait... Components>
413 requires utils::UniqueTypes<Components...>
415 auto copy = *this;
416 --(*this);
417 return copy;
418}
419
420template <ComponentTrait... Components>
421 requires utils::UniqueTypes<Components...>
423 HELIOS_ASSERT(!IsAtEnd(), "Cannot dereference end iterator!");
424 HELIOS_ASSERT(archetype_index_ < archetypes_.size(), "Archetype index out of bounds!");
425 HELIOS_ASSERT(entity_index_ < archetypes_[archetype_index_].get().Entities().size(), "Entity index out of bounds!");
426
427 const auto& archetype = archetypes_[archetype_index_].get();
428 const Entity entity = archetype.Entities()[entity_index_];
429
431 return static_cast<ComponentAccessType<Components>>(components_.get().template GetComponent<ComponentType>(entity));
432 }()...};
433}
434
435template <ComponentTrait... Components>
436 requires utils::UniqueTypes<Components...>
438 while (!IsAtEnd()) {
439 if (archetype_index_ < archetypes_.size() &&
440 entity_index_ < archetypes_[archetype_index_].get().Entities().size()) {
441 // Found valid entity
442 return;
443 }
444
445 // Move to next archetype
446 ++archetype_index_;
447 entity_index_ = 0;
448 }
449}
450
451template <ComponentTrait... Components>
452 requires utils::UniqueTypes<Components...>
454 std::span<const std::reference_wrapper<const Archetype>> archetypes, ComponentsType& components,
455 size_t archetype_index, size_t entity_index)
456 : archetypes_(archetypes), components_(components), archetype_index_(archetype_index), entity_index_(entity_index) {
457 AdvanceToValidEntity();
458}
459
460template <ComponentTrait... Components>
461 requires utils::UniqueTypes<Components...>
463 ++entity_index_;
464 AdvanceToValidEntity();
465 return *this;
466}
467
468template <ComponentTrait... Components>
469 requires utils::UniqueTypes<Components...>
471 auto copy = *this;
472 ++(*this);
473 return copy;
474}
475
476template <ComponentTrait... Components>
477 requires utils::UniqueTypes<Components...>
479 // If at end or beginning of current archetype, need to go back
480 while (true) {
481 if (entity_index_ > 0) {
482 --entity_index_;
483 return *this;
484 }
485
486 // Need to move to previous archetype
487 if (archetype_index_ == 0) {
488 // Already at beginning, can't go back further
489 return *this;
490 }
491
492 --archetype_index_;
493 // Move to last entity in previous archetype
494 if (archetype_index_ < archetypes_.size()) {
495 entity_index_ = archetypes_[archetype_index_].get().EntityCount();
496 if (entity_index_ > 0) {
497 --entity_index_;
498 return *this;
499 }
500 }
501 }
502}
503
504template <ComponentTrait... Components>
505 requires utils::UniqueTypes<Components...>
507 auto copy = *this;
508 --(*this);
509 return copy;
510}
511
512template <ComponentTrait... Components>
513 requires utils::UniqueTypes<Components...>
515 HELIOS_ASSERT(!IsAtEnd(), "Cannot dereference end iterator!");
516 HELIOS_ASSERT(archetype_index_ < archetypes_.size(), "Archetype index out of bounds!");
517 HELIOS_ASSERT(entity_index_ < archetypes_[archetype_index_].get().Entities().size(), "Entity index out of bounds!");
518
519 const auto& archetype = archetypes_[archetype_index_].get();
520 const Entity entity = archetype.Entities()[entity_index_];
521
522 return {entity,
524 return static_cast<ComponentAccessType<Components>>(
525 components_.get().template GetComponent<ComponentType>(entity));
526 }()...};
527}
528
529template <ComponentTrait... Components>
530 requires utils::UniqueTypes<Components...>
532 while (!IsAtEnd()) {
533 if (archetype_index_ < archetypes_.size() &&
534 entity_index_ < archetypes_[archetype_index_].get().Entities().size()) {
535 // Found valid entity
536 return;
537 }
538
539 // Move to next archetype
540 ++archetype_index_;
541 entity_index_ = 0;
542 }
543}
544
545} // namespace details
546
547// Forward declarations
548
549template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
550 requires utils::UniqueTypes<Components...>
551class BasicQuery;
552
553template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
554 requires utils::UniqueTypes<Components...>
555class BasicQueryWithEntity;
556
557/**
558 * @brief Wrapper for queries that include entity in iteration.
559 * @details Provides iteration interface that returns both entity and components.
560 * Supports const-qualified component access for read-only operations.
561 * @note Not thread-safe.
562 * @tparam WorldT World type (World or const World), must satisfy WorldType concept
563 * @tparam Allocator Allocator type for internal storage
564 * @tparam Components Requested component access types (may include const qualifiers)
565 */
566template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
567 requires utils::UniqueTypes<Components...>
569public:
571 using value_type = std::iter_value_t<details::QueryWithEntityIterator<Components...>>;
572 using difference_type = std::iter_difference_t<details::QueryWithEntityIterator<Components...>>;
573 using pointer = typename iterator::pointer;
574 using reference = std::iter_reference_t<details::QueryWithEntityIterator<Components...>>;
575 using allocator_type = Allocator;
576
577 /**
578 * @brief Constructs entity-aware query wrapper.
579 * @param query Reference to the underlying query
580 */
585
588
589 /**
590 * @brief Collects all results into a vector.
591 * @return Vector of tuples containing entity and components
592 *
593 * @example
594 * @code
595 * auto all_results = query.WithEntity().Collect();
596 * @endcode
597 */
598 [[nodiscard]] auto Collect() const -> std::vector<value_type>;
599
600 /**
601 * @brief Collects all results into a vector using a custom allocator.
602 * @details Eagerly evaluates the query and returns all matching results using the provided allocator.
603 * Useful for temporary allocations with frame allocators.
604 * @warning When using a frame allocator (via SystemContext::MakeFrameAllocator()),
605 * the returned data is only valid for the current frame. All pointers and references
606 * to frame-allocated data become invalid after the frame ends.
607 * Do not store frame-allocated data in components, resources, or any persistent storage.
608 * @tparam ResultAlloc STL-compatible allocator type for value_type
609 * @param alloc Allocator instance to use for the result vector
610 * @return Vector of tuples containing entity and components, using the provided allocator
611 *
612 * @example
613 * @code
614 * void MySystem::Update(app::SystemContext& ctx) {
615 * auto query = ctx.Query().Get<Position&>();
616 * auto alloc = ctx.MakeFrameAllocator<decltype(query)::value_type>();
617 * auto results = query.WithEntity().CollectWith(alloc);
618 * // WARNING: Do not store 'results' or pointers to its contents beyond this frame!
619 * }
620 * @endcode
621 */
624 std::iter_value_t<details::QueryWithEntityIterator<Components...>>>
626
627 /**
628 * @brief Collects all entities into a vector.
629 * @return Vector of Entity objects
630 *
631 * @example
632 * @code
633 * std::vector<Entity> all_entities = query.WithEntity().CollectEntities();
634 * @endcode
635 */
636 [[nodiscard]] auto CollectEntities() const -> std::vector<Entity>;
637
638 /**
639 * @brief Collects all entities into a vector using a custom allocator.
640 * @warning When using a frame allocator (via SystemContext::MakeFrameAllocator()),
641 * the returned data is only valid for the current frame. All pointers and references
642 * to frame-allocated data become invalid after the frame ends.
643 * Do not store frame-allocated data in components, resources, or any persistent storage.
644 * @tparam ResultAlloc STL-compatible allocator type for Entity
645 * @param alloc Allocator instance to use for the result vector
646 * @return Vector of Entity objects using the provided allocator
647 */
651
652 /**
653 * @brief Writes all query results into an output iterator.
654 * @details Terminal operation that writes each (entity, components...) tuple to the provided output iterator.
655 * More efficient than Collect() when you have a destination container.
656 * @tparam OutIt Output iterator type
657 * @param out Output iterator
658 *
659 * @example
660 * @code
661 * std::vector<std::tuple<Entity, const Position&, Health&>> results;
662 * query.Into(std::back_inserter(results));
663 * @endcode
664 */
666 requires std::output_iterator<OutIt, std::iter_value_t<details::QueryWithEntityIterator<Components...>>>
667 void Into(OutIt out);
668
669 /**
670 * @brief Executes an action for each matching entity and components.
671 * @details Convenience method for side-effect operations.
672 * @tparam Action Function type (Entity, Components...) -> void
673 * @param action Function to execute for each result
674 *
675 * @example
676 * @code
677 * query.WithEntity()
678 * .ForEach([](Entity entity, Health& health) { health.Regenerate(1.0F); });
679 * @endcode
680 */
682 requires utils::ActionFor<Action, std::tuple<Entity, details::ComponentAccessType<Components>...>>
683 void ForEach(const Action& action);
684
685 /**
686 * @brief Calculates the maximum value using a key function.
687 * @details Finds the element that produces the maximum value when passed to the key function.
688 * @tparam KeyFunc Function type (Entity, Components...) -> Comparable
689 * @param key_func Function to extract the comparison value
690 * @return Optional containing the element with maximum key, or empty if query is empty
691 *
692 * @example
693 * @code
694 * auto strongest = query.WithEntity()
695 * .MaxBy([](Entity e, const Stats& s) { return s.strength; });
696 * @endcode
697 */
699 requires utils::TransformFor<KeyFunc, std::tuple<Entity, details::ComponentAccessType<Components>...>>
701
702 /**
703 * @brief Calculates the minimum value using a key function.
704 * @details Finds the element that produces the minimum value when passed to the key function.
705 * @tparam KeyFunc Function type (Entity, Components...) -> Comparable
706 * @param key_func Function to extract the comparison value
707 * @return Optional containing the element with minimum key, or empty if query is empty
708 *
709 * @example
710 * @code
711 * auto weakest = query.WithEntity()
712 * .MinBy([](Entity e, const Stats& s) { return s.strength; });
713 * @endcode
714 */
716 requires utils::TransformFor<KeyFunc, std::tuple<Entity, details::ComponentAccessType<Components>...>>
718
719 /**
720 * @brief Filters entities based on a predicate.
721 * @details Lazily filters the query results, only yielding elements that satisfy the predicate.
722 * @tparam Pred Predicate function type (Entity, Components...) -> bool
723 * @param predicate Function to test each result
724 * @return View that yields only matching elements
725 *
726 * @example
727 * @code
728 * auto low_health = query.WithEntity()
729 * .Filter([](Entity e, const Health& h) { return h.current < 20.0F; });
730 * @endcode
731 */
733 requires utils::PredicateFor<Pred, std::tuple<Entity, details::ComponentAccessType<Components>...>>
734 [[nodiscard]] auto Filter(Pred predicate) const& -> utils::FilterAdapter<iterator, Pred>;
735
736 /**
737 * @brief Transforms each element using a mapping function.
738 * @details Lazily transforms query results by applying a function to each element.
739 * @tparam Func Transformation function type (Entity, Components...) -> U
740 * @param transform Function to transform each result
741 * @return View that yields transformed elements
742 *
743 * @example
744 * @code
745 * auto positions = query.WithEntity()
746 * .Map([](Entity e, const Transform& t) { return t.position; });
747 * @endcode
748 */
750 requires utils::TransformFor<Func, std::tuple<Entity, details::ComponentAccessType<Components>...>>
751 [[nodiscard]] auto Map(Func transform) const& -> utils::MapAdapter<iterator, Func>;
752
753 /**
754 * @brief Takes only the first N elements.
755 * @details Lazily yields at most N elements from the query results.
756 * @param count Maximum number of elements to take
757 * @return View that yields at most count elements
758 *
759 * @example
760 * @code
761 * auto first_five = query.WithEntity().Take(5);
762 * @endcode
763 */
764 [[nodiscard]] auto Take(size_t count) const& -> utils::TakeAdapter<iterator>;
765
766 /**
767 * @brief Skips the first N elements.
768 * @details Lazily skips the first N elements and yields the rest.
769 * @param count Number of elements to skip
770 * @return View that yields elements after skipping count elements
771 *
772 * @example
773 * @code
774 * auto after_ten = query.WithEntity().Skip(10);
775 * @endcode
776 */
777 [[nodiscard]] auto Skip(size_t count) const& -> utils::SkipAdapter<iterator>;
778
779 /**
780 * @brief Takes elements while a predicate is true.
781 * @details Lazily yields elements until the predicate returns false.
782 * @tparam Pred Predicate function type (Entity, Components...) -> bool
783 * @param predicate Function to test each result
784 * @return View that yields elements while predicate is true
785 *
786 * @example
787 * @code
788 * auto while_healthy = query.WithEntity()
789 * .TakeWhile([](Entity e, const Health& h) { return !h.IsDead(); });
790 * @endcode
791 */
793 requires utils::PredicateFor<Pred, std::tuple<Entity, details::ComponentAccessType<Components>...>>
794 [[nodiscard]] auto TakeWhile(Pred predicate) const& -> utils::TakeWhileAdapter<iterator, Pred>;
795
796 /**
797 * @brief Skips elements while a predicate is true.
798 * @details Lazily skips elements until the predicate returns false, then yields the rest.
799 * @tparam Pred Predicate function type (Entity, Components...) -> bool
800 * @param predicate Function to test each result
801 * @return View that yields elements after predicate becomes false
802 *
803 * @example
804 * @code
805 * auto after_full_health = query.WithEntity()
806 * .SkipWhile([](Entity e, const Health& h) { return h.current == h.max; });
807 * @endcode
808 */
810 requires utils::PredicateFor<Pred, std::tuple<Entity, details::ComponentAccessType<Components>...>>
811 [[nodiscard]] auto SkipWhile(Pred predicate) const& -> utils::SkipWhileAdapter<iterator, Pred>;
812
813 /**
814 * @brief Adds an index to each element.
815 * @details Lazily yields tuples with an index followed by the original elements.
816 * @return View that yields (index, entity, components...) tuples
817 *
818 * @example
819 * @code
820 * for (auto [idx, entity, health] : query.WithEntity().Enumerate()) {
821 * // idx is 0, 1, 2, ...
822 * }
823 * @endcode
824 */
825 [[nodiscard]] auto Enumerate() const& -> utils::EnumerateAdapter<iterator>;
826
827 /**
828 * @brief Inspects each element without consuming it.
829 * @details Calls a function on each element for side effects, then passes it through.
830 * @tparam Func Inspection function type (Entity, Components...) -> void
831 * @param inspector Function to call on each result
832 * @return View that yields the same elements after inspection
833 *
834 * @example
835 * @code
836 * auto result = query.WithEntity()
837 * .Inspect([](Entity e, const Health& h) {
838 * std::cout << "Entity " << e.Index() << " health: " << h.current << "\n";
839 * })
840 * .Collect();
841 * @endcode
842 */
844 requires utils::InspectorFor<Func, std::tuple<Entity, details::ComponentAccessType<Components>...>>
845 [[nodiscard]] auto Inspect(Func inspector) const& -> utils::InspectAdapter<iterator, Func>;
846
847 /**
848 * @brief Yields every Nth element.
849 * @details Lazily yields elements at regular intervals.
850 * @param step Interval between yielded elements (must be > 0)
851 * @return View that yields every step-th element
852 *
853 * @example
854 * @code
855 * auto every_third = query.WithEntity().StepBy(3);
856 * @endcode
857 */
858 [[nodiscard]] auto StepBy(size_t step) const& -> utils::StepByAdapter<iterator>;
859
860 /**
861 * @brief Reverses the order of iteration.
862 * @details Iterates through query results in reverse order.
863 * @return View that yields elements in reverse order
864 * @note Requires bidirectional iterator support
865 *
866 * @example
867 * @code
868 * auto reversed = query.WithEntity().Reverse();
869 * @endcode
870 */
871 [[nodiscard]] auto Reverse() const& -> utils::ReverseAdapter<iterator> { return {begin(), end()}; }
872
873 /**
874 * @brief Creates sliding windows over query results.
875 * @details Yields overlapping windows of a fixed size.
876 * @param window_size Size of the sliding window
877 * @return View that yields windows of elements
878 * @warning window_size must be greater than 0
879 *
880 * @example
881 * @code
882 * auto windows = query.WithEntity().Slide(3);
883 * @endcode
884 */
886 return {begin(), end(), window_size};
887 }
888
889 /**
890 * @brief Takes every Nth element from the query results.
891 * @details Yields elements at regular stride intervals.
892 * @param stride Number of elements to skip between yields
893 * @return View that yields every Nth element
894 * @warning stride must be greater than 0
895 *
896 * @example
897 * @code
898 * auto every_third = query.WithEntity().Stride(3);
899 * @endcode
900 */
901 [[nodiscard]] auto Stride(size_t stride) const& -> utils::StrideAdapter<iterator> { return {begin(), end(), stride}; }
902
903 /**
904 * @brief Zips this query with another iterator.
905 * @details Combines query results with another range into tuples.
906 * @tparam OtherIter Iterator type to zip with
907 * @param other_begin Beginning of the other range
908 * @param other_end End of the other range
909 * @return View that yields tuples of corresponding elements
910 *
911 * @example
912 * @code
913 * std::vector<int> scores = {1, 2, 3};
914 * auto zipped = query.WithEntity().Zip(scores.begin(), scores.end());
915 * @endcode
916 */
917 template <typename OtherIter>
920 return {begin(), end(), std::move(other_begin), std::move(other_end)};
921 }
922
923 /**
924 * @brief Checks if any entity matches the predicate.
925 * @tparam Pred Predicate type (Entity, Components...) -> bool
926 * @param predicate Function to test each result
927 * @return True if at least one result matches, false otherwise
928 *
929 * @example
930 * @code
931 * bool has_low_health = query.WithEntity().Any([](Entity entity, const Health& health) {
932 * return health.current < 10.0F;
933 * });
934 * @endcode
935 */
936 template <typename Pred>
938 [[nodiscard]] bool Any(const Pred& predicate) {
939 return FindFirst(predicate).has_value();
940 }
941
942 /**
943 * @brief Checks if all entities match the predicate.
944 * @tparam Pred Predicate type (Entity, Components...) -> bool
945 * @param predicate Function to test each result
946 * @return True if all results match, false otherwise
947 *
948 * @example
949 * @code
950 * bool all_alive = query.WithEntity().All([](Entity entity, const Health& health) {
951 * return !health.IsDead();
952 * });
953 * @endcode
954 */
955 template <typename Pred>
957 [[nodiscard]] bool All(const Pred& predicate);
958
959 /**
960 * @brief Checks if no entities match the predicate.
961 * @tparam Pred Predicate type (Entity, Components...) -> bool
962 * @param predicate Function to test each result
963 * @return True if no results match, false otherwise
964 *
965 * @example
966 * @code
967 * bool not_dead = query.WithEntity().None([](Entity entity, const Health& health) {
968 * return health.IsDead();
969 * });
970 * @endcode
971 */
972 template <typename Pred>
974 [[nodiscard]] bool None(const Pred& predicate) {
975 return !Any(predicate);
976 }
977
978 /**
979 * @brief Finds the first entity matching a predicate.
980 * @tparam Pred Predicate type (Entity, Components...) -> bool
981 * @param predicate Function to test each result
982 * @return Optional containing the first matching tuple, or empty if none found
983 *
984 * @example
985 * @code
986 * auto boss = query.WithEntity().FindFirst([](Entity entity, const Enemy& enemy) {
987 * return enemy.type == EnemyType::Boss;
988 * });
989 * @endcode
990 */
991 template <typename Pred>
993 [[nodiscard]] auto FindFirst(const Pred& predicate) -> std::optional<value_type>;
994
995 /**
996 * @brief Counts entities matching a predicate.
997 * @tparam Pred Predicate type (Entity, Components...) -> bool
998 * @param predicate Function to test each result
999 * @return Number of matching entities
1000 *
1001 * @example
1002 * @code
1003 * size_t low_health_count = query.WithEntity().CountIf(
1004 * [](Entity entity, const Health& health) { return health.current < 20.0F; }
1005 * );
1006 * @endcode
1007 */
1008 template <typename Pred>
1010 [[nodiscard]] size_t CountIf(const Pred& predicate);
1011
1012 /**
1013 * @brief Partitions entities into two groups based on a predicate.
1014 * @tparam Pred Predicate type (Entity, Components...) -> bool
1015 * @param predicate Function to test each result
1016 * @return Pair of vectors: first contains entities matching predicate, second contains non-matching
1017 *
1018 * @example
1019 * @code
1020 * auto [alive, dead] = query.WithEntity().Partition(
1021 * [](Entity entity, const Health& health) { return !health.IsDead(); }
1022 * );
1023 * @endcode
1024 */
1025 template <typename Pred>
1027 [[nodiscard]] auto Partition(const Pred& predicate) -> std::pair<std::vector<Entity>, std::vector<Entity>>;
1028
1029 /**
1030 * @brief Groups entities by a key extracted from components.
1031 * @tparam KeyExtractor Function type (Entity, Components...) -> Key
1032 * @param key_extractor Function that extracts the grouping key
1033 * @return Map from keys to vectors of entities with that key
1034 *
1035 * @example
1036 * @code
1037 * auto by_team = query.WithEntity().GroupBy(
1038 * [](Entity entity, const Team& team) { return team.id; }
1039 * );
1040 * @endcode
1041 */
1042 template <typename KeyExtractor>
1045 -> std::unordered_map<std::invoke_result_t<KeyExtractor, Entity, details::ComponentAccessType<Components>...>,
1046 std::vector<Entity>>;
1047
1048 /**
1049 * @brief Gets iterator to first matching entity and components.
1050 * @return Iterator pointing to first result
1051 */
1052 [[nodiscard]] iterator begin() const;
1053
1054 /**
1055 * @brief Gets iterator past the last matching entity.
1056 * @return End iterator
1057 */
1058 [[nodiscard]] iterator end() const;
1059
1060private:
1061 BasicQuery<WorldT, Allocator, Components...>& query_; ///< Reference to underlying query
1062};
1063
1064/**
1065 * @brief Query result object for iterating over matching entities and components.
1066 * @details BasicQuery provides iteration and functional operations over entities
1067 * matching specified component criteria.
1068 * Supports const-qualified component access for read-only operations and custom allocators for internal storage.
1069 * @note Not thread-safe.
1070 * @tparam WorldT World type (World or const World), must satisfy WorldType concept
1071 * @tparam Allocator Allocator type for internal storage
1072 * @tparam Components Requested component access types with optional const qualifiers
1073 *
1074 * @example
1075 * @code
1076 * // Mutable access to both components
1077 * auto query = QueryBuilder(world).Get<Position&, Velocity&>();
1078 *
1079 * // Const access to Position, mutable access to Velocity
1080 * auto query = QueryBuilder(world).Get<const Position&, Velocity&>();
1081 *
1082 * // Copy Position, mutable access to Velocity
1083 * auto query = QueryBuilder(world).Get<Position, Velocity&>();
1084 * @endcode
1085 */
1086template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1087 requires utils::UniqueTypes<Components...>
1089public:
1090 /// Components manager type based on whether all components are const-qualified
1092 std::conditional_t<details::AllComponentsConst<Components...>, const details::Components, details::Components>;
1093
1095
1096 using iterator = details::QueryIterator<Components...>;
1097 using value_type = std::iter_value_t<details::QueryIterator<Components...>>;
1098 using difference_type = std::iter_difference_t<details::QueryIterator<Components...>>;
1099 using pointer = typename iterator::pointer;
1100 using reference = std::iter_reference_t<details::QueryIterator<Components...>>;
1101 using allocator_type = Allocator;
1102
1103 /// Rebind allocator for archetype references
1104 using ArchetypeAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<
1105 std::reference_wrapper<const details::Archetype>>;
1106
1107 /**
1108 * @brief Constructs query with specified filtering criteria.
1109 * @details Creates query that matches entities with required components and without forbidden ones.
1110 * @param world Reference to ECS world
1111 * @param with_components Component types that entities must have
1112 * @param without_components Component types that entities must not have
1113 * @param alloc Allocator instance for internal storage
1114 */
1115 BasicQuery(WorldT& world, std::vector<ComponentTypeId, Allocator> with_components,
1116 std::vector<ComponentTypeId, Allocator> without_components = {}, Allocator alloc = {});
1117
1118 BasicQuery(const BasicQuery&) = delete;
1121
1124
1125 /**
1126 * @brief Creates wrapper for entity-aware iteration.
1127 * @details Returns a wrapper that provides iterators returning entity + components.
1128 * @note Only callable on lvalue queries to prevent dangling references.
1129 * @warning Calling on rvalue query results in undefined behavior. Create a named query variable first.
1130 * @return BasicQueryWithEntity wrapper for this query
1131 */
1132 [[nodiscard]] auto WithEntity() & noexcept -> BasicQueryWithEntity<WorldT, Allocator, Components...> {
1133 return BasicQueryWithEntity<WorldT, Allocator, Components...>(*this);
1134 }
1135
1136 /**
1137 * @brief Collects all results into a vector.
1138 * @details Eagerly evaluates the query and returns all matching results.
1139 * @return Vector of tuples containing components
1140 *
1141 * @example
1142 * @code
1143 * auto all_results = query.Collect();
1144 * @endcode
1145 */
1146 [[nodiscard]] auto Collect() const -> std::vector<value_type>;
1147
1148 /**
1149 * @brief Collects all results into a vector using a custom allocator.
1150 * @details Eagerly evaluates the query and returns all matching results using the provided allocator.
1151 * Useful for temporary allocations with frame allocators.
1152 * @warning When using a frame allocator (via SystemContext::MakeFrameAllocator()),
1153 * the returned data is only valid for the current frame.
1154 * All pointers and references to frame-allocated data become invalid after the frame ends.
1155 * Do not store frame-allocated data in components, resources, or any persistent storage.
1156 * @tparam ResultAlloc STL-compatible allocator type for value_type
1157 * @param alloc Allocator instance to use for the result vector
1158 * @return Vector of tuples containing components, using the provided allocator
1159 *
1160 * @example
1161 * @code
1162 * void MySystem::Update(app::SystemContext& ctx) {
1163 * auto query = ctx.Query().Get<Position&, Velocity&>();
1164 * auto alloc = ctx.MakeFrameAllocator<decltype(query)::value_type>();
1165 * auto results = query.CollectWith(alloc);
1166 * // results uses frame allocator, automatically reclaimed at frame end
1167 * // WARNING: Do not store 'results' or pointers to its contents beyond this frame!
1168 * }
1169 * @endcode
1170 */
1172 requires std::same_as<typename ResultAlloc::value_type, std::iter_value_t<details::QueryIterator<Components...>>>
1174
1175 /**
1176 * @brief Writes all query results into an output iterator.
1177 * @details Terminal operation that writes each result tuple to the provided output iterator.
1178 * More efficient than Collect() when you have a destination container.
1179 * @tparam OutIt Output iterator type
1180 * @param out Output iterator
1181 *
1182 * @example
1183 * @code
1184 * std::vector<std::tuple<const Position&, Health&>> results;
1185 * query.Into(std::back_inserter(results));
1186 * @endcode
1187 */
1189 requires std::output_iterator<OutIt, std::iter_value_t<details::QueryIterator<Components...>>>
1191
1192 /**
1193 * @brief Executes an action for each matching entity and components.
1194 * @details Convenience method for side-effect operations.
1195 * @tparam Action Function type (Components...) -> void
1196 * @param action Function to execute for each result
1197 *
1198 * @example
1199 * @code
1200 * query.ForEach([](Position& pos, const Velocity& vel) {
1201 * pos.x += vel.dx;
1202 * pos.y += vel.dy;
1203 * });
1204 * @endcode
1205 */
1207 requires utils::ActionFor<Action, std::tuple<details::ComponentAccessType<Components>...>>
1209
1210 /**
1211 * @brief Executes an action for each entity and its components.
1212 * @details Variant that also provides the entity as the first argument.
1213 * @tparam Action Function type (Entity, Components...) -> void
1214 * @param action Function to execute for each result
1215 *
1216 * @example
1217 * @code
1218 * query.ForEachWithEntity([](Entity entity, Position& pos) {
1219 * HELIOS_INFO("Entity {} at ({}, {})", entity.Index(), pos.x, pos.y);
1220 * });
1221 * @endcode
1222 */
1224 requires utils::ActionFor<Action, std::tuple<Entity, details::ComponentAccessType<Components>...>>
1226
1227 /**
1228 * @brief Filters entities based on a predicate.
1229 * @details Lazily filters the query results, only yielding elements that satisfy the predicate.
1230 * @tparam Pred Predicate function type (Components...) -> bool
1231 * @param predicate Function to test each result
1232 * @return View that yields only matching elements
1233 *
1234 * @example
1235 * @code
1236 * auto moving = query.Filter([](const Position&, const Velocity& vel) {
1237 * return vel.dx != 0.0F || vel.dy != 0.0F;
1238 * });
1239 * @endcode
1240 */
1242 requires utils::PredicateFor<Pred, std::tuple<details::ComponentAccessType<Components>...>>
1243 [[nodiscard]] auto Filter(Pred predicate) const& -> utils::FilterAdapter<iterator, Pred>;
1244
1245 /**
1246 * @brief Transforms each element using a mapping function.
1247 * @details Lazily transforms query results by applying a function to each element.
1248 * @tparam Func Transformation function type (Components...) -> U
1249 * @param transform Function to transform each result
1250 * @return View that yields transformed elements
1251 *
1252 * @example
1253 * @code
1254 * auto x_positions = query.Map([](const Position& pos, const Velocity&) {
1255 * return pos.x;
1256 * });
1257 * @endcode
1258 */
1260 requires utils::TransformFor<Func, std::tuple<details::ComponentAccessType<Components>...>>
1261 [[nodiscard]] auto Map(Func transform) const& -> utils::MapAdapter<iterator, Func>;
1262
1263 /**
1264 * @brief Takes only the first N elements.
1265 * @details Lazily yields at most N elements from the query results.
1266 * @param count Maximum number of elements to take
1267 * @return View that yields at most count elements
1268 *
1269 * @example
1270 * @code
1271 * auto first_ten = query.Take(10);
1272 * @endcode
1273 */
1274 [[nodiscard]] auto Take(size_t count) const& -> utils::TakeAdapter<iterator>;
1275
1276 /**
1277 * @brief Skips the first N elements.
1278 * @details Lazily skips the first N elements and yields the rest.
1279 * @param count Number of elements to skip
1280 * @return View that yields elements after skipping count elements
1281 *
1282 * @example
1283 * @code
1284 * auto after_five = query.Skip(5);
1285 * @endcode
1286 */
1287 [[nodiscard]] auto Skip(size_t count) const& -> utils::SkipAdapter<iterator>;
1288
1289 /**
1290 * @brief Reverses the order of iteration.
1291 * @details Iterates through query results in reverse order.
1292 * @return View that yields elements in reverse order
1293 * @note Requires bidirectional iterator support
1294 *
1295 * @example
1296 * @code
1297 * auto reversed = query.Reverse();
1298 * @endcode
1299 */
1300 [[nodiscard]] auto Reverse() const& -> utils::ReverseAdapter<iterator> { return {begin(), end()}; }
1301
1302 /**
1303 * @brief Creates sliding windows over query results.
1304 * @details Yields overlapping windows of a fixed size.
1305 * @param window_size Size of the sliding window
1306 * @return View that yields windows of elements
1307 * @warning window_size must be greater than 0
1308 *
1309 * @example
1310 * @code
1311 * auto windows = query.Slide(3);
1312 * @endcode
1313 */
1315 return {begin(), end(), window_size};
1316 }
1317
1318 /**
1319 * @brief Takes every Nth element from the query results.
1320 * @details Yields elements at regular stride intervals.
1321 * @param stride Number of elements to skip between yields
1322 * @return View that yields every Nth element
1323 * @warning stride must be greater than 0
1324 *
1325 * @example
1326 * @code
1327 * auto every_third = query.Stride(3);
1328 * @endcode
1329 */
1330 [[nodiscard]] auto Stride(size_t stride) const& -> utils::StrideAdapter<iterator> { return {begin(), end(), stride}; }
1331
1332 /**
1333 * @brief Zips this query with another iterator.
1334 * @details Combines query results with another range into tuples.
1335 * @tparam OtherIter Iterator type to zip with
1336 * @param other_begin Beginning of the other range
1337 * @param other_end End of the other range
1338 * @return View that yields tuples of corresponding elements
1339 *
1340 * @example
1341 * @code
1342 * std::vector<int> indices = {0, 1, 2};
1343 * auto zipped = query.Zip(indices.begin(), indices.end());
1344 * @endcode
1345 */
1346 template <typename OtherIter>
1349 return {begin(), end(), std::move(other_begin), std::move(other_end)};
1350 }
1351
1352 /**
1353 * @brief Takes elements while a predicate is true.
1354 * @details Lazily yields elements until the predicate returns false.
1355 * @tparam Pred Predicate function type (Components...) -> bool
1356 * @param predicate Function to test each result
1357 * @return View that yields elements while predicate is true
1358 *
1359 * @example
1360 * @code
1361 * auto while_positive = query.TakeWhile([](const Health& h) { return h.points > 0; });
1362 * @endcode
1363 */
1364 template <typename Pred>
1367
1368 /**
1369 * @brief Skips elements while a predicate is true.
1370 * @details Lazily skips elements until the predicate returns false, then yields the rest.
1371 * @tparam Pred Predicate function type (Components...) -> bool
1372 * @param predicate Function to test each result
1373 * @return View that yields elements after predicate becomes false
1374 *
1375 * @example
1376 * @code
1377 * auto after_full = query.SkipWhile([](const Health& h) { return h.points == h.max; });
1378 * @endcode
1379 */
1380 template <typename Pred>
1383
1384 /**
1385 * @brief Adds an index to each element.
1386 * @details Lazily yields tuples with an index followed by the original elements.
1387 * @return View that yields (index, components...) tuples
1388 *
1389 * @example
1390 * @code
1391 * for (auto [idx, pos, vel] : query.Enumerate()) {
1392 * // idx is 0, 1, 2, ...
1393 * }
1394 * @endcode
1395 */
1396 [[nodiscard]] auto Enumerate() const& -> utils::EnumerateAdapter<iterator>;
1397
1398 /**
1399 * @brief Inspects each element without consuming it.
1400 * @details Calls a function on each element for side effects, then passes it through.
1401 * @tparam Func Inspection function type (Components...) -> void
1402 * @param inspector Function to call on each result
1403 * @return View that yields the same elements after inspection
1404 *
1405 * @example
1406 * @code
1407 * auto result = query.Inspect([](const Position& p) {
1408 * std::cout << "Position: " << p.x << ", " << p.y << "\n";
1409 * }).Collect();
1410 * @endcode
1411 */
1413 requires utils::InspectorFor<Func, std::tuple<details::ComponentAccessType<Components>...>>
1414 [[nodiscard]] auto Inspect(Func inspector) const& -> utils::InspectAdapter<iterator, Func>;
1415
1416 /**
1417 * @brief Yields every Nth element.
1418 * @details Lazily yields elements at regular intervals.
1419 * @param step Interval between yielded elements (must be > 0)
1420 * @return View that yields every step-th element
1421 *
1422 * @example
1423 * @code
1424 * auto every_other = query.StepBy(2);
1425 * @endcode
1426 */
1427 [[nodiscard]] auto StepBy(size_t step) const& -> utils::StepByAdapter<iterator>;
1428
1429 /**
1430 * @brief Checks if any element matches the predicate.
1431 * @details Short-circuits on first match for efficiency.
1432 * @tparam Pred Predicate function type (Components...) -> bool
1433 * @param predicate Function to test each result
1434 * @return True if at least one result matches, false otherwise
1435 *
1436 * @example
1437 * @code
1438 * bool has_low_health = query.Any([](const Health& h) { return h.current < 10.0F; });
1439 * @endcode
1440 */
1442 requires utils::PredicateFor<Pred, std::tuple<details::ComponentAccessType<Components>...>>
1443 [[nodiscard]] bool Any(const Pred& predicate) const {
1444 return FindFirst(predicate).has_value();
1445 }
1446
1447 /**
1448 * @brief Checks if all elements match the predicate.
1449 * @details Short-circuits on first non-match for efficiency.
1450 * @tparam Pred Predicate function type (Components...) -> bool
1451 * @param predicate Function to test each result
1452 * @return True if all results match, false otherwise
1453 *
1454 * @example
1455 * @code
1456 * bool all_alive = query.All([](const Health& h) { return !h.IsDead(); });
1457 * @endcode
1458 */
1459 template <typename Pred>
1461 [[nodiscard]] bool All(const Pred& predicate) const;
1462
1463 /**
1464 * @brief Checks if no elements match the predicate.
1465 * @details Short-circuits on first match for efficiency.
1466 * @tparam Pred Predicate function type (Components...) -> bool
1467 * @param predicate Function to test each result
1468 * @return True if no results match, false otherwise
1469 *
1470 * @example
1471 * @code
1472 * bool none_dead = query.None([](const Health& h) { return h.IsDead(); });
1473 * @endcode
1474 */
1475 template <typename Pred>
1477 [[nodiscard]] bool None(const Pred& predicate) const {
1478 return !Any(predicate);
1479 }
1480
1481 /**
1482 * @brief Counts elements matching a predicate.
1483 * @tparam Pred Predicate function type (Components...) -> bool
1484 * @param predicate Function to test each result
1485 * @return Number of matching elements
1486 *
1487 * @example
1488 * @code
1489 * size_t low_health_count = query.CountIf([](const Health& h) { return h.current < 20.0F; });
1490 * @endcode
1491 */
1492 template <typename Pred>
1494 [[nodiscard]] size_t CountIf(const Pred& predicate) const;
1495
1496 /**
1497 * @brief Folds the query results into a single value.
1498 * @details Applies a binary function to an initial value and each result.
1499 * @tparam T Accumulator type
1500 * @tparam Func Function type (T, Components...) -> T
1501 * @param init Initial value
1502 * @param folder Function that combines accumulator with each result
1503 * @return Final folded value
1504 *
1505 * @example
1506 * @code
1507 * float total_mass = query.Fold(0.0F, [](float acc, const Physics& p) { return acc + p.mass; });
1508 * @endcode
1509 */
1510 template <typename T, typename Func>
1512 [[nodiscard]] T Fold(T init, const Func& folder) const;
1513
1514 /**
1515 * @brief Finds the first element matching a predicate.
1516 * @details Searches through query results until finding one that satisfies the predicate.
1517 * @tparam Pred Predicate function type (Components...) -> bool
1518 * @param predicate Function to test each result
1519 * @return Optional containing the first matching tuple, or empty if none found
1520 *
1521 * @example
1522 * @code
1523 * auto low_health = query.FindFirst([](const Health& h) { return h.current < 10.0F; });
1524 * @endcode
1525 */
1526 template <typename Pred>
1528 [[nodiscard]] auto FindFirst(const Pred& predicate) const -> std::optional<value_type>;
1529
1530 /**
1531 * @brief Partitions elements into two groups based on a predicate.
1532 * @tparam Pred Predicate function type (Components...) -> bool
1533 * @param predicate Function to test each result
1534 * @return Pair of vectors: first contains tuples matching predicate, second contains non-matching
1535 *
1536 * @example
1537 * @code
1538 * auto [alive, dead] = query.Partition([](const Health& h) { return !h.IsDead(); });
1539 * @endcode
1540 */
1541 template <typename Pred>
1543 [[nodiscard]] auto Partition(const Pred& predicate) const
1544 -> std::pair<std::vector<value_type>, std::vector<value_type>>;
1545
1546 /**
1547 * @brief Calculates the maximum value using a key function.
1548 * @details Finds the element that produces the maximum value when passed to the key function.
1549 * @tparam KeyFunc Function type (Components...) -> Comparable
1550 * @param key_func Function to extract the comparison value
1551 * @return Optional containing the element with maximum key, or empty if query is empty
1552 *
1553 * @example
1554 * @code
1555 * auto strongest = query.MaxBy([](const Stats& s) { return s.strength; });
1556 * @endcode
1557 */
1558 template <typename KeyFunc>
1560 [[nodiscard]] auto MaxBy(const KeyFunc& key_func) const -> std::optional<value_type>;
1561
1562 /**
1563 * @brief Calculates the minimum value using a key function.
1564 * @details Finds the element that produces the minimum value when passed to the key function.
1565 * @tparam KeyFunc Function type (Components...) -> Comparable
1566 * @param key_func Function to extract the comparison value
1567 * @return Optional containing the element with minimum key, or empty if query is empty
1568 *
1569 * @example
1570 * @code
1571 * auto weakest = query.MinBy([](const Stats& s) { return s.strength; });
1572 * @endcode
1573 */
1574 template <typename KeyFunc>
1576 [[nodiscard]] auto MinBy(const KeyFunc& key_func) const -> std::optional<value_type>;
1577
1578 /**
1579 * @brief Checks if any entities match the query.
1580 * @details Fast check for query result emptiness without full iteration.
1581 * @return True if at least one entity matches, false otherwise
1582 */
1584
1585 /**
1586 * @brief Gets the number of matching entities.
1587 * @details Counts entities across all matching archetypes.
1588 * Time complexity: O(A) where A is the number of matching archetypes.
1589 * @return Total count of entities that match the query
1590 */
1592
1593 /**
1594 * @brief Gets iterator to first matching entity.
1595 * @return Iterator pointing to first result
1596 */
1598
1599 /**
1600 * @brief Gets iterator past the last matching entity.
1601 * @return End iterator
1602 */
1604 return {matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0};
1605 }
1606
1607 /**
1608 * @brief Gets the allocator used by this query.
1609 * @return Copy of the allocator
1610 */
1612
1613private:
1614 /**
1615 * @brief Refreshes the list of matching archetypes.
1616 * @details Updates cached archetype list based on current world state.
1617 */
1618 void RefreshArchetypes() const {
1619 auto result = world_.get().GetArchetypes().FindMatchingArchetypes(with_components_, without_components_);
1620 matching_archetypes_.clear();
1621 matching_archetypes_.reserve(result.size());
1622 for (auto& archetype : result) {
1623 matching_archetypes_.push_back(archetype);
1624 }
1625 }
1626
1627 [[nodiscard]] WorldT& GetWorld() noexcept { return world_.get(); }
1628 [[nodiscard]] const WorldT& GetWorld() const noexcept { return world_.get(); }
1629
1630 [[nodiscard]] ComponentsType& GetComponents() const noexcept;
1631
1632 [[nodiscard]] auto GetMatchingArchetypes() const noexcept
1633 -> std::span<const std::reference_wrapper<const details::Archetype>> {
1634 return {matching_archetypes_.data(), matching_archetypes_.size()};
1635 }
1636
1637 std::reference_wrapper<WorldT> world_; ///< Reference to ECS world
1638 std::vector<ComponentTypeId, Allocator> with_components_; ///< Required component types
1639 std::vector<ComponentTypeId, Allocator> without_components_; ///< Forbidden component types
1640 mutable std::vector<std::reference_wrapper<const details::Archetype>, ArchetypeAllocator>
1641 matching_archetypes_; ///< Cached matching archetypes
1642 [[no_unique_address]] Allocator alloc_; ///< Allocator instance
1643
1644 friend class BasicQueryWithEntity<WorldT, Allocator, Components...>;
1645};
1646
1647// ================================================================================================
1648// BasicQueryWithEntity implementation
1649// ================================================================================================
1650
1651template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1652 requires utils::UniqueTypes<Components...>
1654 std::vector<value_type> result;
1655 result.reserve(query_.Count());
1656 for (auto&& tuple : *this) {
1657 result.push_back(tuple);
1658 }
1659 return result;
1660}
1661
1662template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1663 requires utils::UniqueTypes<Components...>
1664template <typename ResultAlloc>
1665 requires std::same_as<typename ResultAlloc::value_type,
1666 std::iter_value_t<details::QueryWithEntityIterator<Components...>>>
1668 -> std::vector<value_type, ResultAlloc> {
1669 std::vector<value_type, ResultAlloc> result{std::move(alloc)};
1670 result.reserve(query_.Count());
1671 for (auto&& tuple : *this) {
1672 result.push_back(tuple);
1673 }
1674 return result;
1675}
1676
1677template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1678 requires utils::UniqueTypes<Components...>
1680 std::vector<Entity> result;
1681 result.reserve(query_.Count());
1682 for (auto&& tuple : *this) {
1683 result.push_back(std::get<0>(tuple));
1684 }
1685 return result;
1686}
1687
1688template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1689 requires utils::UniqueTypes<Components...>
1690template <typename ResultAlloc>
1691 requires std::same_as<typename ResultAlloc::value_type, Entity>
1693 -> std::vector<Entity, ResultAlloc> {
1694 std::vector<Entity, ResultAlloc> result{std::move(alloc)};
1695 result.reserve(query_.Count());
1696 for (auto&& tuple : *this) {
1697 result.push_back(std::get<0>(tuple));
1698 }
1699 return result;
1700}
1701
1702template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1703 requires utils::UniqueTypes<Components...>
1704template <typename OutIt>
1705 requires std::output_iterator<OutIt, std::iter_value_t<details::QueryWithEntityIterator<Components...>>>
1707 for (auto&& result : *this) {
1708 *out++ = std::forward<decltype(result)>(result);
1709 }
1710}
1711
1712template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1713 requires utils::UniqueTypes<Components...>
1714template <typename Action>
1717 for (auto&& result : *this) {
1718 std::apply(action, result);
1719 }
1720}
1721
1722template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1723 requires utils::UniqueTypes<Components...>
1724template <typename Pred>
1728 query_.RefreshArchetypes();
1729 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1730 auto end_iter =
1731 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1732 return {begin_iter, end_iter, std::move(predicate)};
1733}
1734
1735template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1736 requires utils::UniqueTypes<Components...>
1737template <typename Func>
1741 query_.RefreshArchetypes();
1742 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1743 auto end_iter =
1744 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1745 return {begin_iter, end_iter, std::move(transform)};
1746}
1747
1748template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1749 requires utils::UniqueTypes<Components...>
1751 size_t count) const& -> utils::TakeAdapter<iterator> {
1752 query_.RefreshArchetypes();
1753 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1754 auto end_iter =
1755 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1756 return {begin_iter, end_iter, count};
1757}
1758
1759template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1760 requires utils::UniqueTypes<Components...>
1762 size_t count) const& -> utils::SkipAdapter<iterator> {
1763 query_.RefreshArchetypes();
1764 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1765 auto end_iter =
1766 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1767 return {begin_iter, end_iter, count};
1768}
1769
1770template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1771 requires utils::UniqueTypes<Components...>
1772template <typename Pred>
1776 query_.RefreshArchetypes();
1777 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1778 auto end_iter =
1779 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1780 return {begin_iter, end_iter, std::move(predicate)};
1781}
1782
1783template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1784 requires utils::UniqueTypes<Components...>
1785template <typename Pred>
1789 query_.RefreshArchetypes();
1790 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1791 auto end_iter =
1792 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1793 return {begin_iter, end_iter, std::move(predicate)};
1794}
1795
1796template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1797 requires utils::UniqueTypes<Components...>
1799 const& -> utils::EnumerateAdapter<iterator> {
1800 query_.RefreshArchetypes();
1801 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1802 auto end_iter =
1803 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1804 return {begin_iter, end_iter};
1805}
1806
1807template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1808 requires utils::UniqueTypes<Components...>
1809template <typename Func>
1813 query_.RefreshArchetypes();
1814 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1815 auto end_iter =
1816 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1817 return {begin_iter, end_iter, std::move(inspector)};
1818}
1819
1820template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1821 requires utils::UniqueTypes<Components...>
1823 size_t step) const& -> utils::StepByAdapter<iterator> {
1824 query_.RefreshArchetypes();
1825 auto begin_iter = iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0);
1826 auto end_iter =
1827 iterator(query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0);
1828 return {begin_iter, end_iter, step};
1829}
1830
1831template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1832 requires utils::UniqueTypes<Components...>
1833template <typename Pred>
1836 -> std::optional<value_type> {
1837 for (auto&& result : *this) {
1838 if (std::apply(predicate, result)) {
1839 return result;
1840 }
1841 }
1842 return std::nullopt;
1843}
1844
1845template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1846 requires utils::UniqueTypes<Components...>
1847template <typename KeyFunc>
1850 -> std::optional<value_type> {
1851 auto iter = begin();
1852 const auto end_iter = end();
1853
1854 if (iter == end_iter) {
1855 return std::nullopt;
1856 }
1857
1858 std::optional<value_type> max_element;
1859 max_element.emplace(*iter);
1860 auto max_key = std::apply(key_func, *max_element);
1861 ++iter;
1862
1863 while (iter != end_iter) {
1864 auto current = *iter;
1865 auto current_key = std::apply(key_func, current);
1866 if (current_key > max_key) {
1868 max_element.emplace(current);
1869 }
1870 ++iter;
1871 }
1872
1873 return max_element;
1874}
1875
1876template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1877 requires utils::UniqueTypes<Components...>
1878template <typename KeyFunc>
1881 -> std::optional<value_type> {
1882 auto iter = begin();
1883 const auto end_iter = end();
1884
1885 if (iter == end_iter) {
1886 return std::nullopt;
1887 }
1888
1889 std::optional<value_type> min_element;
1890 min_element.emplace(*iter);
1891 auto min_key = std::apply(key_func, *min_element);
1892 ++iter;
1893
1894 while (iter != end_iter) {
1895 auto current = *iter;
1896 auto current_key = std::apply(key_func, current);
1897 if (current_key < min_key) {
1899 min_element.emplace(current);
1900 }
1901 ++iter;
1902 }
1903
1904 return min_element;
1905}
1906
1907template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1908 requires utils::UniqueTypes<Components...>
1909template <typename Pred>
1912 size_t count = 0;
1913 for (auto&& tuple : *this) {
1914 if (std::apply(predicate, tuple)) {
1915 ++count;
1916 }
1917 }
1918 return count;
1919}
1920
1921template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1922 requires utils::UniqueTypes<Components...>
1923template <typename Pred>
1926 for (auto&& result : *this) {
1927 if (!std::apply(predicate, result)) {
1928 return false;
1929 }
1930 }
1931 return true;
1932}
1933
1934template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1935 requires utils::UniqueTypes<Components...>
1936template <typename Pred>
1939 -> std::pair<std::vector<Entity>, std::vector<Entity>> {
1940 std::vector<Entity> matched;
1941 std::vector<Entity> not_matched;
1942
1943 for (auto&& tuple : *this) {
1944 if (std::apply(predicate, tuple)) {
1945 matched.push_back(std::get<0>(tuple));
1946 } else {
1947 not_matched.push_back(std::get<0>(tuple));
1948 }
1949 }
1950
1951 return {std::move(matched), std::move(not_matched)};
1952}
1953
1954template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1955 requires utils::UniqueTypes<Components...>
1956template <typename KeyExtractor>
1959 -> std::unordered_map<std::invoke_result_t<KeyExtractor, Entity, details::ComponentAccessType<Components>...>,
1960 std::vector<Entity>> {
1961 using KeyType = std::invoke_result_t<KeyExtractor, Entity, details::ComponentAccessType<Components>...>;
1962 std::unordered_map<KeyType, std::vector<Entity>> groups;
1963
1964 for (auto&& tuple : *this) {
1965 auto key = std::apply(key_extractor, tuple);
1966 groups[key].push_back(std::get<0>(tuple));
1967 }
1968
1969 return groups;
1970}
1971
1972template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1973 requires utils::UniqueTypes<Components...>
1975 query_.RefreshArchetypes();
1976 return {query_.GetMatchingArchetypes(), query_.GetComponents(), 0, 0};
1977}
1978
1979template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1980 requires utils::UniqueTypes<Components...>
1982 return {query_.GetMatchingArchetypes(), query_.GetComponents(), query_.GetMatchingArchetypes().size(), 0};
1983}
1984
1985// ================================================================================================
1986// BasicQuery implementation
1987// ================================================================================================
1988
1989template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
1990 requires utils::UniqueTypes<Components...>
1992 std::vector<ComponentTypeId, Allocator> with_components,
1993 std::vector<ComponentTypeId, Allocator> without_components,
1994 Allocator alloc)
1995 : world_(world),
1996 with_components_(std::move(with_components)),
1997 without_components_(std::move(without_components)),
1998 matching_archetypes_(ArchetypeAllocator(alloc)),
1999 alloc_(alloc) {
2000 static_assert(details::ValidWorldComponentAccess<WorldT, Components...>,
2001 "Cannot request mutable component access from const World! "
2002 "Use const-qualified components (e.g., 'const Position&') or pass mutable World.");
2003}
2004
2005template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2006 requires utils::UniqueTypes<Components...>
2007template <typename OutIt>
2008 requires std::output_iterator<OutIt, std::iter_value_t<details::QueryIterator<Components...>>>
2010 for (auto&& result : *this) {
2011 *out++ = std::forward<decltype(result)>(result);
2012 }
2013}
2014
2015template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2016 requires utils::UniqueTypes<Components...>
2017template <typename Action>
2020 for (auto&& result : *this) {
2021 std::apply(action, result);
2022 }
2023}
2024
2025template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2026 requires utils::UniqueTypes<Components...>
2027template <typename Action>
2030 RefreshArchetypes();
2031 auto begin_iter = WithEntityIterator(matching_archetypes_, GetComponents(), 0, 0);
2032 auto end_iter = WithEntityIterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2033 for (auto iter = begin_iter; iter != end_iter; ++iter) {
2034 std::apply([&action](Entity entity, auto&&... components) { action(entity, components...); }, *iter);
2035 }
2036}
2037
2038template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2039 requires utils::UniqueTypes<Components...>
2040template <typename Pred>
2044 RefreshArchetypes();
2045 auto begin_iter = iterator(matching_archetypes_, GetComponents(), 0, 0);
2046 auto end_iter = iterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2047 return {begin_iter, end_iter, std::move(predicate)};
2048}
2049
2050template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2051 requires utils::UniqueTypes<Components...>
2052template <typename Func>
2056 RefreshArchetypes();
2057 auto begin_iter = iterator(GetMatchingArchetypes(), GetComponents(), 0, 0);
2058 auto end_iter = iterator(GetMatchingArchetypes(), GetComponents(), GetMatchingArchetypes().size(), 0);
2059 return {begin_iter, end_iter, std::move(transform)};
2060}
2061
2062template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2063 requires utils::UniqueTypes<Components...>
2065 RefreshArchetypes();
2066 auto begin_iter = iterator(matching_archetypes_, GetComponents(), 0, 0);
2067 auto end_iter = iterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2068 return {begin_iter, end_iter, count};
2069}
2070
2071template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2072 requires utils::UniqueTypes<Components...>
2074 RefreshArchetypes();
2075 auto begin_iter = iterator(matching_archetypes_, GetComponents(), 0, 0);
2076 auto end_iter = iterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2077 return {begin_iter, end_iter, count};
2078}
2079
2080template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2081 requires utils::UniqueTypes<Components...>
2082template <typename Pred>
2086 RefreshArchetypes();
2087 auto begin_iter = iterator(matching_archetypes_, GetComponents(), 0, 0);
2088 auto end_iter = iterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2089 return {begin_iter, end_iter, std::move(predicate)};
2090}
2091
2092template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2093 requires utils::UniqueTypes<Components...>
2094template <typename Pred>
2098 RefreshArchetypes();
2099 auto begin_iter = iterator(matching_archetypes_, GetComponents(), 0, 0);
2100 auto end_iter = iterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2101 return {begin_iter, end_iter, std::move(predicate)};
2102}
2103
2104template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2105 requires utils::UniqueTypes<Components...>
2107 RefreshArchetypes();
2108 auto begin_iter = iterator(GetMatchingArchetypes(), GetComponents(), 0, 0);
2109 auto end_iter = iterator(GetMatchingArchetypes(), GetComponents(), GetMatchingArchetypes().size(), 0);
2110 return {begin_iter, end_iter};
2111}
2112
2113template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2114 requires utils::UniqueTypes<Components...>
2115template <typename Func>
2119 RefreshArchetypes();
2120 auto begin_iter = iterator(GetMatchingArchetypes(), GetComponents(), 0, 0);
2121 auto end_iter = iterator(GetMatchingArchetypes(), GetComponents(), GetMatchingArchetypes().size(), 0);
2122 return {begin_iter, end_iter, std::move(inspector)};
2123}
2124
2125template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2126 requires utils::UniqueTypes<Components...>
2128 RefreshArchetypes();
2129 auto begin_iter = iterator(matching_archetypes_, GetComponents(), 0, 0);
2130 auto end_iter = iterator(matching_archetypes_, GetComponents(), matching_archetypes_.size(), 0);
2131 return {begin_iter, end_iter, step};
2132}
2133
2134template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2135 requires utils::UniqueTypes<Components...>
2137 std::vector<value_type> result;
2138 result.reserve(Count());
2139 for (auto&& tuple : *this) {
2140 result.push_back(tuple);
2141 }
2142 return result;
2143}
2144
2145template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2146 requires utils::UniqueTypes<Components...>
2147template <typename ResultAlloc>
2148 requires std::same_as<typename ResultAlloc::value_type, std::iter_value_t<details::QueryIterator<Components...>>>
2150 -> std::vector<value_type, ResultAlloc> {
2151 std::vector<value_type, ResultAlloc> result{std::move(alloc)};
2152 result.reserve(Count());
2153 for (auto&& tuple : *this) {
2154 result.push_back(tuple);
2155 }
2156 return result;
2157}
2158
2159template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2160 requires utils::UniqueTypes<Components...>
2161template <typename T, typename Func>
2164 for (auto&& tuple : *this) {
2165 init = std::apply(
2166 [&init, &folder](auto&&... components) {
2167 return folder(std::move(init), std::forward<decltype(components)>(components)...);
2168 },
2169 tuple);
2170 }
2171 return init;
2172}
2173
2174template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2175 requires utils::UniqueTypes<Components...>
2176template <typename Pred>
2179 -> std::optional<value_type> {
2180 for (auto&& result : *this) {
2181 if (std::apply(predicate, result)) {
2182 return result;
2183 }
2184 }
2185 return std::nullopt;
2186}
2187
2188template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2189 requires utils::UniqueTypes<Components...>
2190template <typename Pred>
2193 for (auto&& result : *this) {
2194 if (!std::apply(predicate, result)) {
2195 return false;
2196 }
2197 }
2198 return true;
2199}
2200
2201template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2202 requires utils::UniqueTypes<Components...>
2203template <typename Pred>
2206 size_t count = 0;
2207 for (auto&& tuple : *this) {
2208 if (std::apply(predicate, tuple)) {
2209 ++count;
2210 }
2211 }
2212 return count;
2213}
2214
2215template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2216 requires utils::UniqueTypes<Components...>
2217template <typename Pred>
2220 -> std::pair<std::vector<value_type>, std::vector<value_type>> {
2221 std::vector<value_type> matched;
2222 std::vector<value_type> not_matched;
2223
2224 for (auto&& tuple : *this) {
2225 if (std::apply(predicate, tuple)) {
2226 matched.push_back(tuple);
2227 } else {
2228 not_matched.push_back(tuple);
2229 }
2230 }
2231
2232 return {std::move(matched), std::move(not_matched)};
2233}
2234
2235template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2236 requires utils::UniqueTypes<Components...>
2237template <typename KeyFunc>
2240 -> std::optional<value_type> {
2241 auto iter = begin();
2242 const auto end_iter = end();
2243
2244 if (iter == end_iter) {
2245 return std::nullopt;
2246 }
2247
2248 std::optional<value_type> max_element;
2249 max_element.emplace(*iter);
2250 auto max_key = std::apply(key_func, *max_element);
2251 ++iter;
2252
2253 while (iter != end_iter) {
2254 auto current = *iter;
2255 auto current_key = std::apply(key_func, current);
2256 if (current_key > max_key) {
2258 max_element.emplace(current);
2259 }
2260 ++iter;
2261 }
2262
2263 return max_element;
2264}
2265
2266template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2267 requires utils::UniqueTypes<Components...>
2268template <typename KeyFunc>
2271 -> std::optional<value_type> {
2272 auto iter = begin();
2273 const auto end_iter = end();
2274
2275 if (iter == end_iter) {
2276 return std::nullopt;
2277 }
2278
2279 std::optional<value_type> min_element;
2280 min_element.emplace(*iter);
2281 auto min_key = std::apply(key_func, *min_element);
2282 ++iter;
2283
2284 while (iter != end_iter) {
2285 auto current = *iter;
2286 auto current_key = std::apply(key_func, current);
2287 if (current_key < min_key) {
2289 min_element.emplace(current);
2290 }
2291 ++iter;
2292 }
2293
2294 return min_element;
2295}
2296
2297template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2298 requires utils::UniqueTypes<Components...>
2300 RefreshArchetypes();
2301 return matching_archetypes_.empty() || Count() == 0;
2302}
2303
2304template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2305 requires utils::UniqueTypes<Components...>
2307 RefreshArchetypes();
2308 size_t count = 0;
2309 for (const auto& archetype_ref : matching_archetypes_) {
2310 count += archetype_ref.get().EntityCount();
2311 }
2312 return count;
2313}
2314
2315template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2316 requires utils::UniqueTypes<Components...>
2318 RefreshArchetypes();
2319 return {matching_archetypes_, GetComponents(), 0, 0};
2320}
2321
2322template <WorldType WorldT, typename Allocator, ComponentTrait... Components>
2323 requires utils::UniqueTypes<Components...>
2325 typename BasicQuery<WorldT, Allocator, Components...>::ComponentsType& {
2326 if constexpr (details::AllComponentsConst<Components...> || details::IsConstWorld<WorldT>) {
2327 return std::as_const(world_.get()).GetComponents();
2328 } else {
2329 return world_.get().GetComponents();
2330 }
2331}
2332
2333// ================================================================================================
2334// BasicQueryBuilder
2335// ================================================================================================
2336
2337/**
2338 * @brief Query builder for filtering entities by components with fluent interface.
2339 * @details Provides a fluent API for constructing queries with required and forbidden component types.
2340 * Supports const-qualified World access for read-only queries and custom allocators for internal storage.
2341 * @note Not thread-safe.
2342 * @tparam WorldT World type (World or const World), must satisfy WorldType concept
2343 * @tparam Allocator Allocator type for internal storage
2344 *
2345 * @example
2346 * @code
2347 * // Query with mutable access
2348 * auto query = QueryBuilder(world)
2349 * .Without<Frozen>()
2350 * .Get<Position&, Velocity&>();
2351 *
2352 * // Query with mixed const/mutable access
2353 * auto query = QueryBuilder(world)
2354 * .With<Player>()
2355 * .Get<const Position&, Velocity&>();
2356 *
2357 * // Read-only query from const World
2358 * auto query = ReadOnlyQueryBuilder(const_world)
2359 * .Get<const Position&>(); // Only const access allowed
2360 * @endcode
2361 */
2362template <WorldType WorldT = World, typename Allocator = std::allocator<ComponentTypeId>>
2364public:
2365 using allocator_type = Allocator;
2366
2367 /**
2368 * @brief Constructs query builder for the specified world.
2369 * @param world Reference to ECS world to query
2370 * @param alloc Allocator for internal storage
2371 */
2372 explicit BasicQueryBuilder(WorldT& world, Allocator alloc = {}) noexcept
2373 : world_(world), with_components_(alloc), without_components_(alloc), alloc_(alloc) {}
2374
2375 /**
2376 * @brief Constructs query builder for the specified world with access validation.
2377 * @param world Reference to ECS world to query
2378 * @param policy Access policy for validation
2379 * @param alloc Allocator for internal storage
2380 */
2382 : world_(world), policy_(&policy), with_components_(alloc), without_components_(alloc), alloc_(alloc) {}
2383
2387
2390
2391 /**
2392 * @brief Adds required component types to the query.
2393 * @details Entities must have ALL specified component types to match the query.
2394 * @tparam Comps Component types that entities must have
2395 * @return Reference to this builder for method chaining
2396 */
2398 requires utils::UniqueTypes<Comps...>
2400
2401 /**
2402 * @brief Adds forbidden component types to the query.
2403 * @details Entities must NOT have ANY of the specified component types to match the query.
2404 * @tparam Comps Component types that entities must not have
2405 * @return Reference to this builder for method chaining
2406 */
2408 requires utils::UniqueTypes<Comps...>
2410
2411 /**
2412 * @brief Builds and executes the query, returning components with specified access.
2413 * @details Creates query object with the specified component access types.
2414 * Supports const-qualified access for read-only operations and mixed access patterns.
2415 *
2416 * Access type examples:
2417 * - `T&` - Mutable reference to component T
2418 * - `const T&` - Const reference to component T
2419 * - `T` - Copy of component T
2420 *
2421 * Const World Restriction:
2422 * - When BasicQueryBuilder is constructed with `const World&`, only const component access is allowed
2423 * - Attempting to use mutable component access (e.g., `Get<Position&>()`) will fail at compile time
2424 *
2425 * @tparam Comps Component access types (may include const qualifiers and references)
2426 * @return BasicQuery object for iteration over matching entities
2427 */
2429 requires(sizeof...(Comps) > 0 && utils::UniqueTypes<details::ComponentTypeExtractor_t<Comps>...>)
2430 [[nodiscard]] auto Get(this auto&& self) -> BasicQuery<WorldT, Allocator, Comps...>;
2431
2432 /**
2433 * @brief Builds and executes the query, returning no components.
2434 * @details Creates query object that only filters entities based on presence/absence
2435 * of specified components, without returning any component data.
2436 * Useful for existence checks or counting entities.
2437 * @return BasicQuery object for iteration over matching entities
2438 */
2440 return {self.world_.get(), std::forward_like<decltype(self)>(self.with_components_),
2441 std::forward_like<decltype(self)>(self.without_components_), self.alloc_};
2442 }
2443
2444 /**
2445 * @brief Gets the allocator used by this builder.
2446 * @return Copy of the allocator
2447 */
2449
2450private:
2451 std::reference_wrapper<WorldT> world_; ///< Reference to ECS world
2452 const app::AccessPolicy* policy_ = nullptr; ///< Access policy for Get() check
2453 std::vector<ComponentTypeId, Allocator> with_components_; ///< Required component type IDs
2454 std::vector<ComponentTypeId, Allocator> without_components_; ///< Forbidden component type IDs
2455 [[no_unique_address]] Allocator alloc_; ///< Allocator instance
2456};
2457
2458// Deduction guides for BasicQueryBuilder
2459template <WorldType WorldT>
2461
2462template <WorldType WorldT>
2464
2465template <WorldType WorldT, typename Allocator>
2467
2468template <WorldType WorldT, typename Allocator>
2470
2471/// Type alias for query builder with mutable world access
2472template <typename Allocator = std::allocator<ComponentTypeId>>
2474
2475/// Type alias for query builder with read-only world access
2476template <typename Allocator = std::allocator<ComponentTypeId>>
2478
2479/// Type alias for query with mutable world access
2480template <typename Allocator, ComponentTrait... Components>
2481using Query = BasicQuery<World, Allocator, Components...>;
2482
2483/// Type alias for query with read-only world access
2484template <typename Allocator, ComponentTrait... Components>
2485using ReadOnlyQuery = BasicQuery<const World, Allocator, Components...>;
2486
2487/// Type alias for query with entity with mutable world access
2488template <typename Allocator, ComponentTrait... Components>
2489using QueryWithEntity = BasicQueryWithEntity<World, Allocator, Components...>;
2490
2491/// Type alias for query with entity with read-only world access
2492template <typename Allocator, ComponentTrait... Components>
2493using ReadOnlyQueryWithEntity = BasicQueryWithEntity<const World, Allocator, Components...>;
2494
2495template <WorldType WorldT, typename Allocator>
2496template <ComponentTrait... Comps>
2497 requires utils::UniqueTypes<Comps...>
2499 -> decltype(std::forward<decltype(self)>(self)) {
2500 (self.with_components_.insert(self.with_components_.end(), {ComponentTypeIdOf<Comps>()...}));
2501 return std::forward<decltype(self)>(self);
2502}
2503
2504template <WorldType WorldT, typename Allocator>
2505template <ComponentTrait... Comps>
2506 requires utils::UniqueTypes<Comps...>
2508 -> decltype(std::forward<decltype(self)>(self)) {
2509 (self.without_components_.insert(self.without_components_.end(), {ComponentTypeIdOf<Comps>()...}));
2510 return std::forward<decltype(self)>(self);
2511}
2512
2513template <WorldType WorldT, typename Allocator>
2514template <ComponentTrait... Comps>
2515 requires(sizeof...(Comps) > 0 && utils::UniqueTypes<details::ComponentTypeExtractor_t<Comps>...>)
2516inline auto BasicQueryBuilder<WorldT, Allocator>::Get(this auto&& self) -> BasicQuery<WorldT, Allocator, Comps...> {
2517 // Compile-time validation: const World requires const Components
2519 "Cannot request mutable component access from const World! "
2520 "Use const-qualified components (e.g., 'const Position&') or pass mutable World.");
2521
2522#ifdef HELIOS_ENABLE_ASSERTS
2523 if (self.policy_ != nullptr) [[likely]] {
2524 // Check that all requested component types are declared in at least one query
2525 const auto queries = self.policy_->GetQueries();
2526
2527 // Collect all requested component type IDs
2529
2530 // Check if each requested type is in any query (read or write)
2531 for (const auto& requested_id : requested_types) {
2532 bool found = false;
2533 for (const auto& query : queries) {
2534 auto matches_id = [requested_id](const auto& info) { return info.type_id == requested_id; };
2535 if (std::ranges::any_of(query.read_components, matches_id) ||
2536 std::ranges::any_of(query.write_components, matches_id)) {
2537 found = true;
2538 break;
2539 }
2540 }
2541
2543 "Attempted to query component that was not declared in app::AccessPolicy! "
2544 "Add .Query<>() with this component type to GetAccessPolicy().");
2545 }
2546 }
2547#endif
2548
2549 // Add required components for Get<> to with_components_ if not already there
2550 auto add_if_not_present = [&self](ComponentTypeId type_id) {
2551 if (std::ranges::find(self.with_components_, type_id) == self.with_components_.end()) {
2552 self.with_components_.push_back(type_id);
2553 }
2554 };
2555
2557 return {self.world_.get(), std::forward_like<decltype(self)>(self.with_components_),
2558 std::forward_like<decltype(self)>(self.without_components_), self.alloc_};
2559}
2560
2561} // namespace helios::ecs
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:140
BasicQueryBuilder(WorldT &world, Allocator alloc={}) noexcept
Constructs query builder for the specified world.
Definition query.hpp:2372
auto Get(this auto &&self) -> BasicQuery< WorldT, Allocator, Comps... >
Builds and executes the query, returning components with specified access.
Definition query.hpp:2516
BasicQueryBuilder(BasicQueryBuilder &&) noexcept=default
BasicQueryBuilder(const BasicQueryBuilder &)=delete
allocator_type get_allocator() const noexcept
Gets the allocator used by this builder.
Definition query.hpp:2448
auto With(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Adds required component types to the query.
Definition query.hpp:2498
auto Without(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Adds forbidden component types to the query.
Definition query.hpp:2507
BasicQueryBuilder(WorldT &world, const app::AccessPolicy &policy, Allocator alloc={})
Constructs query builder for the specified world with access validation.
Definition query.hpp:2381
Wrapper for queries that include entity in iteration.
Definition query.hpp:568
details::QueryWithEntityIterator< Components... > iterator
Definition query.hpp:570
auto GroupBy(const KeyExtractor &key_extractor) -> std::unordered_map< std::invoke_result_t< KeyExtractor, Entity, details::ComponentAccessType< Components >... >, std::vector< Entity > >
Definition query.hpp:1958
void ForEach(const Action &action)
Definition query.hpp:1716
auto CollectEntitiesWith(ResultAlloc alloc) const -> std::vector< Entity, ResultAlloc >
Collects all entities into a vector using a custom allocator.
Definition query.hpp:1692
auto CollectWith(ResultAlloc alloc) const -> std::vector< value_type, ResultAlloc >
Definition query.hpp:1667
auto TakeWhile(Pred predicate) const &-> utils::TakeWhileAdapter< iterator, Pred >
Definition query.hpp:1774
auto StepBy(size_t step) const &-> utils::StepByAdapter< iterator >
Definition query.hpp:1822
auto Skip(size_t count) const &-> utils::SkipAdapter< iterator >
Definition query.hpp:1761
iterator begin() const
Gets iterator to first matching entity and components.
Definition query.hpp:1974
BasicQueryWithEntity(BasicQueryWithEntity &&)=delete
auto Map(Func transform) const &-> utils::MapAdapter< iterator, Func >
Definition query.hpp:1739
auto Filter(Pred predicate) const &-> utils::FilterAdapter< iterator, Pred >
Definition query.hpp:1726
auto SkipWhile(Pred predicate) const &-> utils::SkipWhileAdapter< iterator, Pred >
Definition query.hpp:1787
auto CollectEntities() const -> std::vector< Entity >
Definition query.hpp:1679
auto Enumerate() const &-> utils::EnumerateAdapter< iterator >
Definition query.hpp:1798
auto FindFirst(const Pred &predicate) -> std::optional< value_type >
Definition query.hpp:1835
auto Reverse() const &-> utils::ReverseAdapter< iterator >
Definition query.hpp:871
typename iterator::pointer pointer
Definition query.hpp:573
bool All(const Pred &predicate)
Definition query.hpp:1925
auto Slide(size_t window_size) const &-> utils::SlideAdapter< iterator >
Definition query.hpp:885
auto Stride(size_t stride) const &-> utils::StrideAdapter< iterator >
Definition query.hpp:901
std::iter_difference_t< details::QueryWithEntityIterator< Components... > > difference_type
Definition query.hpp:572
auto Partition(const Pred &predicate) -> std::pair< std::vector< Entity >, std::vector< Entity > >
Definition query.hpp:1938
std::iter_reference_t< details::QueryWithEntityIterator< Components... > > reference
Definition query.hpp:574
BasicQueryWithEntity(const BasicQueryWithEntity &)=delete
auto MaxBy(const KeyFunc &key_func) const -> std::optional< value_type >
Definition query.hpp:1849
bool Any(const Pred &predicate)
Definition query.hpp:938
auto Inspect(Func inspector) const &-> utils::InspectAdapter< iterator, Func >
Definition query.hpp:1811
BasicQueryWithEntity(BasicQuery< WorldT, Allocator, Components... > &query) noexcept
Constructs entity-aware query wrapper.
Definition query.hpp:581
auto MinBy(const KeyFunc &key_func) const -> std::optional< value_type >
Definition query.hpp:1880
auto Collect() const -> std::vector< value_type >
Definition query.hpp:1653
size_t CountIf(const Pred &predicate)
Definition query.hpp:1911
std::iter_value_t< details::QueryWithEntityIterator< Components... > > value_type
Definition query.hpp:571
auto Zip(OtherIter other_begin, OtherIter other_end) const &-> utils::ZipAdapter< iterator, OtherIter >
Definition query.hpp:919
bool None(const Pred &predicate)
Definition query.hpp:974
~BasicQueryWithEntity() noexcept=default
iterator end() const
Gets iterator past the last matching entity.
Definition query.hpp:1981
auto Take(size_t count) const &-> utils::TakeAdapter< iterator >
Definition query.hpp:1750
void ForEachWithEntity(const Action &action) const
Definition query.hpp:2029
BasicQuery(const BasicQuery &)=delete
auto StepBy(size_t step) const &-> utils::StepByAdapter< iterator >
Definition query.hpp:2127
std::conditional_t< details::AllComponentsConst< Components... >, const details::Components, details::Components > ComponentsType
Components manager type based on whether all components are const-qualified.
Definition query.hpp:1092
void Into(OutIt out) const
Definition query.hpp:2009
BasicQuery(BasicQuery &&) noexcept=default
auto Filter(Pred predicate) const &-> utils::FilterAdapter< iterator, Pred >
Definition query.hpp:2042
auto Skip(size_t count) const &-> utils::SkipAdapter< iterator >
Definition query.hpp:2073
bool None(const Pred &predicate) const
Definition query.hpp:1477
auto Map(Func transform) const &-> utils::MapAdapter< iterator, Func >
Definition query.hpp:2054
auto WithEntity() &noexcept -> BasicQueryWithEntity< WorldT, Allocator, Components... >
Creates wrapper for entity-aware iteration.
Definition query.hpp:1132
std::iter_difference_t< details::QueryIterator< Components... > > difference_type
Definition query.hpp:1098
auto FindFirst(const Pred &predicate) const -> std::optional< value_type >
Definition query.hpp:2178
void ForEach(const Action &action) const
Definition query.hpp:2019
bool All(const Pred &predicate) const
Definition query.hpp:2192
details::QueryIterator< Components... > iterator
Definition query.hpp:1096
auto MaxBy(const KeyFunc &key_func) const -> std::optional< value_type >
Definition query.hpp:2239
auto SkipWhile(Pred predicate) const &-> utils::SkipWhileAdapter< iterator, Pred >
Definition query.hpp:2096
bool Empty() const noexcept
Checks if any entities match the query.
Definition query.hpp:2299
auto Inspect(Func inspector) const &-> utils::InspectAdapter< iterator, Func >
Definition query.hpp:2117
auto Enumerate() const &-> utils::EnumerateAdapter< iterator >
Definition query.hpp:2106
size_t Count() const noexcept
Gets the number of matching entities.
Definition query.hpp:2306
typename iterator::pointer pointer
Definition query.hpp:1099
details::QueryWithEntityIterator< Components... > WithEntityIterator
Definition query.hpp:1094
auto CollectWith(ResultAlloc alloc) const -> std::vector< value_type, ResultAlloc >
Definition query.hpp:2149
typename std::allocator_traits< Allocator >::template rebind_alloc< std::reference_wrapper< const details::Archetype > > ArchetypeAllocator
Rebind allocator for archetype references.
Definition query.hpp:1105
iterator begin() const
Gets iterator to first matching entity.
Definition query.hpp:2317
auto Zip(OtherIter other_begin, OtherIter other_end) const &-> utils::ZipAdapter< iterator, OtherIter >
Definition query.hpp:1348
std::iter_reference_t< details::QueryIterator< Components... > > reference
Definition query.hpp:1100
auto Partition(const Pred &predicate) const -> std::pair< std::vector< value_type >, std::vector< value_type > >
Definition query.hpp:2219
std::iter_value_t< details::QueryIterator< Components... > > value_type
Definition query.hpp:1097
iterator end() const noexcept
Gets iterator past the last matching entity.
Definition query.hpp:1603
allocator_type get_allocator() const noexcept
Gets the allocator used by this query.
Definition query.hpp:1611
auto Slide(size_t window_size) const &-> utils::SlideAdapter< iterator >
Definition query.hpp:1314
BasicQuery(WorldT &world, std::vector< ComponentTypeId, Allocator > with_components, std::vector< ComponentTypeId, Allocator > without_components={}, Allocator alloc={})
Constructs query with specified filtering criteria.
Definition query.hpp:1991
auto Take(size_t count) const &-> utils::TakeAdapter< iterator >
Definition query.hpp:2064
T Fold(T init, const Func &folder) const
Definition query.hpp:2163
auto TakeWhile(Pred predicate) const &-> utils::TakeWhileAdapter< iterator, Pred >
Definition query.hpp:2084
size_t CountIf(const Pred &predicate) const
Definition query.hpp:2205
auto Stride(size_t stride) const &-> utils::StrideAdapter< iterator >
Definition query.hpp:1330
auto Collect() const -> std::vector< value_type >
Definition query.hpp:2136
bool Any(const Pred &predicate) const
Definition query.hpp:1443
auto MinBy(const KeyFunc &key_func) const -> std::optional< value_type >
Definition query.hpp:2270
auto Reverse() const &-> utils::ReverseAdapter< iterator >
Definition query.hpp:1300
Unique identifier for entities with generation counter to handle recycling.
Definition entity.hpp:21
The World class manages entities with their components and systems.
Definition world.hpp:53
Manager for all component storages in the ECS world.
Entity manager responsible for entity creation, destruction, and validation.
Iterator for query results without entity information.
Definition query.hpp:129
bool operator!=(const QueryIterator &other) const noexcept
Compares iterators for inequality.
Definition query.hpp:207
std::forward_iterator_tag iterator_category
Definition query.hpp:136
QueryIterator(const QueryIterator &) noexcept=default
QueryIterator begin() const noexcept
Returns iterator to the beginning.
Definition query.hpp:213
QueryIterator & operator++()
Advances iterator to next matching entity.
Definition query.hpp:370
QueryIterator & operator--()
Moves iterator to previous matching entity.
Definition query.hpp:386
QueryIterator end() const noexcept
Returns iterator to the end.
Definition query.hpp:219
value_type operator*() const
Dereferences iterator to get component tuple.
Definition query.hpp:422
std::tuple< ComponentAccessType< Components >... > value_type
Definition query.hpp:137
std::conditional_t< AllComponentsConst< Components... >, const details::Components, details::Components > ComponentsType
Components manager type based on whether all components are const-qualified.
Definition query.hpp:133
QueryIterator(std::span< const std::reference_wrapper< const Archetype > > archetypes, ComponentsType &components, size_t archetype_index=0, size_t entity_index=0)
Constructs iterator for query results.
Definition query.hpp:362
QueryIterator(QueryIterator &&) noexcept=default
Iterator for query results with entity information.
Definition query.hpp:249
std::tuple< Entity, ComponentAccessType< Components >... > value_type
Definition query.hpp:257
QueryWithEntityIterator(std::span< const std::reference_wrapper< const Archetype > > archetypes, ComponentsType &components, size_t archetype_index=0, size_t entity_index=0)
Constructs iterator for query results with entity.
Definition query.hpp:453
QueryWithEntityIterator(QueryWithEntityIterator &&) noexcept=default
QueryWithEntityIterator end() const noexcept
Returns iterator to the end.
Definition query.hpp:337
QueryWithEntityIterator(const QueryWithEntityIterator &) noexcept=default
QueryWithEntityIterator begin() const noexcept
Returns iterator to the beginning.
Definition query.hpp:331
bool operator!=(const QueryWithEntityIterator &other) const noexcept
Compares iterators for inequality.
Definition query.hpp:325
std::forward_iterator_tag iterator_category
Definition query.hpp:256
value_type operator*() const
Dereferences iterator to get entity and component tuple.
Definition query.hpp:514
QueryWithEntityIterator & operator--()
Moves iterator to previous matching entity.
Definition query.hpp:478
QueryWithEntityIterator & operator++()
Advances iterator to next matching entity.
Definition query.hpp:462
std::conditional_t< AllComponentsConst< Components... >, const details::Components, details::Components > ComponentsType
Components manager type based on whether all components are const-qualified.
Definition query.hpp:253
Concept to check if a type can be used as a component.
Definition component.hpp:39
Concept that constrains a type to be the World type (with any cv-qualifiers).
Definition world.hpp:45
Concept for STL-compatible allocators.
Definition query.hpp:112
Concept for valid World/Component access combinations.
Definition query.hpp:85
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.
constexpr bool IsConstWorld
Helper to detect if World type is const.
Definition query.hpp:74
constexpr bool AllComponentsConst
Helper to check if all component types are const-qualified.
Definition query.hpp:66
std::conditional_t< std::is_reference_v< T >, T, std::conditional_t< std::is_const_v< T >, const ComponentTypeExtractor_t< T > &, ComponentTypeExtractor_t< T > & > > ComponentAccessType
Helper to determine the proper return type for component access.
Definition query.hpp:104
typename ComponentTypeExtractor< T >::type ComponentTypeExtractor_t
Definition query.hpp:50
size_t ComponentTypeId
Type ID for components.
constexpr ComponentTypeId ComponentTypeIdOf() noexcept
Type ID for components using CTTI.
BasicQuery< World, Allocator, Components... > Query
Type alias for query with mutable world access.
Definition query.hpp:2481
STL namespace.
Helper to detect const components.
Definition component.hpp:20
Type trait to extract the underlying component type from const/reference wrappers.
Definition query.hpp:45