2#include "gaia/config/config.h"
6#include "gaia/cnt/darray.h"
7#include "gaia/cnt/map.h"
8#include "gaia/cnt/sarray.h"
9#include "gaia/cnt/sarray_ext.h"
10#include "gaia/core/bit_utils.h"
11#include "gaia/core/hashing_policy.h"
12#include "gaia/core/span.h"
13#include "gaia/core/utility.h"
14#include "gaia/ecs/api.h"
15#include "gaia/ecs/component.h"
16#include "gaia/ecs/id.h"
17#include "gaia/ecs/query_fwd.h"
18#include "gaia/ecs/query_mask.h"
25 GAIA_NODISCARD uint32_t world_rel_version(
const World& world, Entity relation);
26 GAIA_NODISCARD
bool world_has_entity_term(
const World& world, Entity entity, Entity term);
27 GAIA_NODISCARD
bool world_has_entity_term_in(
const World& world, Entity entity, Entity term);
28 GAIA_NODISCARD
bool world_has_entity_term_direct(
const World& world, Entity entity, Entity term);
29 GAIA_NODISCARD
bool world_term_uses_inherit_policy(
const World& world, Entity term);
30 GAIA_NODISCARD
bool world_is_exclusive_dont_fragment_relation(
const World& world, Entity relation);
31 GAIA_NODISCARD
bool world_is_out_of_line_component(
const World& world, Entity component);
32 GAIA_NODISCARD
bool world_is_non_fragmenting_out_of_line_component(
const World& world, Entity component);
33 GAIA_NODISCARD uint32_t world_count_direct_term_entities(
const World& world, Entity term);
34 GAIA_NODISCARD uint32_t world_count_in_term_entities(
const World& world, Entity term);
35 GAIA_NODISCARD uint32_t world_count_direct_term_entities_direct(
const World& world, Entity term);
36 void world_collect_direct_term_entities(
const World& world, Entity term, cnt::darray<Entity>& out);
37 void world_collect_in_term_entities(
const World& world, Entity term, cnt::darray<Entity>& out);
38 void world_collect_direct_term_entities_direct(
const World& world, Entity term, cnt::darray<Entity>& out);
40 world_for_each_direct_term_entity(
const World& world, Entity term,
void* ctx,
bool (*func)(
void*, Entity));
42 world_for_each_in_term_entity(
const World& world, Entity term,
void* ctx,
bool (*func)(
void*, Entity));
44 world_for_each_direct_term_entity_direct(
const World& world, Entity term,
void* ctx,
bool (*func)(
void*, Entity));
45 GAIA_NODISCARD
bool world_entity_enabled(
const World& world, Entity entity);
46 GAIA_NODISCARD
bool world_entity_prefab(
const World& world, Entity entity);
47 GAIA_NODISCARD
const Archetype* world_entity_archetype(
const World& world, Entity entity);
48 GAIA_NODISCARD uint32_t world_component_index_bucket_size(
const World& world, Entity term);
49 GAIA_NODISCARD uint32_t world_component_index_comp_idx(
const World& world,
const Archetype& archetype, Entity term);
50 GAIA_NODISCARD uint32_t
51 world_component_index_match_count(
const World& world,
const Archetype& archetype, Entity term);
53 GAIA_NODISCARD GroupId group_by_func_depth_order(
const World& world,
const Archetype& archetype, Entity relation);
55 GAIA_NODISCARD
decltype(
auto) world_direct_entity_arg(World& world, Entity entity);
57 GAIA_NODISCARD
decltype(
auto) world_query_entity_arg(World& world, Entity entity);
59 GAIA_NODISCARD uint32_t world_entity_archetype_version(
const World& world, Entity entity);
62 static constexpr uint32_t MAX_ITEMS_IN_QUERY = 12U;
64 static constexpr uint32_t MAX_TRAV_DEPTH = 128U;
66 GAIA_GCC_WARNING_PUSH()
69 GAIA_GCC_WARNING_DISABLE("-Wshadow")
72 enum class QueryOpKind : uint8_t { All, Or, Not, Any, Count };
74 enum class QueryAccess : uint8_t { None, Read, Write };
76 enum class QueryMatchKind : uint8_t { Semantic, In, Direct };
78 enum class QueryInputFlags : uint8_t { None, Variable };
80 enum class QueryTravKind : uint8_t { None = 0x00, Self = 0x01, Up = 0x02, Down = 0x04 };
82 GAIA_GCC_WARNING_POP()
84 GAIA_NODISCARD constexpr QueryTravKind operator|(QueryTravKind lhs, QueryTravKind rhs) {
85 return (QueryTravKind)((uint8_t)lhs | (uint8_t)rhs);
88 GAIA_NODISCARD
constexpr bool query_trav_has(QueryTravKind value, QueryTravKind bit) {
89 return (((uint8_t)value) & ((uint8_t)bit)) != 0;
92 using QueryLookupHash = core::direct_hash_key<uint64_t>;
93 using QueryEntityArray = cnt::sarray<Entity, MAX_ITEMS_IN_QUERY>;
94 using QueryArchetypeCacheIndexMap = cnt::map<EntityLookupKey, uint32_t>;
95 using QuerySerMap = cnt::map<QueryId, QuerySerBuffer>;
96 static constexpr uint16_t ComponentIndexBad = (uint16_t)-1;
100 uint16_t compIdx = ComponentIndexBad;
101 uint16_t matchCount = 0;
103 GAIA_NODISCARD
bool matches(
const Archetype* pOther)
const {
104 return pArchetype == pOther;
122 static constexpr QueryId QueryIdBad = (QueryId)-1;
123 static constexpr GroupId GroupIdMax = ((GroupId)-1) - 1;
126 static constexpr uint32_t IdMask = QueryIdBad;
140 constexpr QueryHandle()
noexcept: val((uint64_t)-1) {};
153 GAIA_NODISCARD
constexpr bool operator==(
const QueryHandle& other)
const noexcept {
154 return val == other.val;
156 GAIA_NODISCARD
constexpr bool operator!=(
const QueryHandle& other)
const noexcept {
157 return val != other.val;
160 GAIA_NODISCARD
auto id()
const {
163 GAIA_NODISCARD
auto gen()
const {
166 GAIA_NODISCARD
auto value()
const {
184 return {core::calculate_hash64(handle.value())};
188 static constexpr bool IsDirectHashKey =
true;
203 size_t hash()
const {
204 return (
size_t)m_hash.hash;
208 if GAIA_LIKELY (m_hash != other.m_hash)
211 return m_handle == other.m_handle;
215 return !operator==(other);
223 static constexpr uint8_t TravDepthUnlimited = 0;
226 QueryOpKind
op = QueryOpKind::All;
241 QueryTravKind
travKind = QueryTravKind::Self | QueryTravKind::Up;
253 static constexpr uint8_t TravDepthUnlimited = QueryInput::TravDepthUnlimited;
260 QueryTravKind
travKind = QueryTravKind::Self | QueryTravKind::Up;
277 travKind = QueryTravKind::Self | QueryTravKind::Up;
282 QueryTermOptions& trav_up(Entity relation = ChildOf) {
289 QueryTermOptions& trav_parent(Entity relation = ChildOf) {
296 QueryTermOptions& trav_self_parent(Entity relation = ChildOf) {
298 travKind = QueryTravKind::Self | QueryTravKind::Up;
303 QueryTermOptions& trav_down(Entity relation = ChildOf) {
310 QueryTermOptions& trav_self_down(Entity relation = ChildOf) {
312 travKind = QueryTravKind::Self | QueryTravKind::Down;
317 QueryTermOptions& trav_child(Entity relation = ChildOf) {
324 QueryTermOptions& trav_self_child(Entity relation = ChildOf) {
326 travKind = QueryTravKind::Self | QueryTravKind::Down;
331 QueryTermOptions& trav_kind(QueryTravKind kind) {
336 QueryTermOptions& trav_depth(uint8_t maxDepth) {
341 QueryTermOptions& read() {
342 access = QueryAccess::Read;
346 QueryTermOptions& write() {
347 access = QueryAccess::Write;
351 QueryTermOptions& direct() {
356 QueryTermOptions& in() {
383 bool operator==(
const QueryTerm& other)
const {
387 bool operator!=(
const QueryTerm& other)
const {
388 return !operator==(other);
392 constexpr bool query_term_less_for_lookup(
const QueryTerm& lhs,
const QueryTerm& rhs) {
393 if (lhs.op != rhs.op)
394 return lhs.op < rhs.op;
396 if (lhs.id != rhs.id)
397 return SortComponentCond()(lhs.id, rhs.id);
399 if (lhs.src != rhs.src)
400 return SortComponentCond()(lhs.src, rhs.src);
402 if (lhs.entTrav != rhs.entTrav)
403 return SortComponentCond()(lhs.entTrav, rhs.entTrav);
405 if (lhs.travKind != rhs.travKind)
406 return (uint8_t)lhs.travKind < (uint8_t)rhs.travKind;
408 if (lhs.travDepth != rhs.travDepth)
409 return lhs.travDepth < rhs.travDepth;
411 return (uint8_t)lhs.matchKind < (uint8_t)rhs.matchKind;
415 const auto idsCnt = (uint32_t)terms.size();
418 uint32_t orIdx = BadIndex;
420 if (terms[i].op != QueryOpKind::Or)
429 terms[orIdx].op = QueryOpKind::All;
432 core::sort(terms.data(), terms.data() + idsCnt, [](
const QueryTerm& left,
const QueryTerm& right) {
433 return query_term_less_for_lookup(left, right);
438 const auto changedCnt = (uint32_t)changed.size();
440 core::sort(changed.data(), changed.data() + changedCnt, SortComponentCond{});
443 GAIA_NODISCARD
inline bool term_has_variables(
const QueryTerm& term) {
444 if (is_variable(term.src))
448 return is_variable(EntityId(term.id.id())) || is_variable(EntityId(term.id.gen()));
450 return is_variable(EntityId(term.id.id()));
453 using QueryTermArray = cnt::sarray_ext<QueryTerm, MAX_ITEMS_IN_QUERY>;
455 using QueryRemappingArray = cnt::sarray_ext<uint8_t, MAX_ITEMS_IN_QUERY>;
464 return query_buffer(*world,
serId);
466 void ser_buffer_reset(
World* world) {
467 query_buffer_reset(*world,
serId);
481 enum QueryFlags : uint8_t {
492 HasSourceTerms = 0x10,
494 HasVariableTerms = 0x20,
498 HasPrefabTerms = 0x80,
501 enum class CachePolicy : uint8_t {
510 enum class CreateArchetypeMatchKind : uint8_t {
514 DirectStructuralTerms,
517 enum class DirectTargetEvalKind : uint8_t {
525 enum DependencyFlags : uint16_t {
526 DependencyNone = 0x00,
527 DependencyHasSourceTerms = 0x01,
528 DependencyHasVariableTerms = 0x02,
529 DependencyHasPositiveTerms = 0x04,
530 DependencyHasNegativeTerms = 0x08,
531 DependencyHasAnyTerms = 0x10,
532 DependencyHasWildcardTerms = 0x20,
533 DependencyHasSort = 0x40,
534 DependencyHasGroup = 0x80,
535 DependencyHasTraversalTerms = 0x100,
536 DependencyHasEntityFilterTerms = 0x200,
537 DependencyHasInheritedDataTerms = 0x400,
546 uint8_t createSelectorCnt = 0;
547 uint8_t exclusionCnt = 0;
548 uint8_t relationCnt = 0;
549 uint8_t sourceEntityCnt = 0;
550 uint8_t sourceTermCnt = 0;
551 DependencyFlags flags = DependencyNone;
554 createSelectorCnt = 0;
559 flags = DependencyNone;
563 return {createSelectors.data(), createSelectorCnt};
567 return {exclusions.data(), exclusionCnt};
571 return {relations.data(), relationCnt};
575 return {sourceEntities.data(), sourceEntityCnt};
578 void set_dep_flag(DependencyFlags dependency) {
579 flags = (DependencyFlags)(flags | dependency);
582 GAIA_NODISCARD
bool has_dep_flag(DependencyFlags dependency)
const {
583 return (flags & dependency) != 0;
586 void add_rel(
Entity relation) {
587 if (relation == EntityBad || core::has(relations_view(), relation))
590 GAIA_ASSERT(relationCnt < MAX_ITEMS_IN_QUERY);
591 relations[relationCnt++] = relation;
594 void add_src_entity(
Entity entity) {
595 if (entity == EntityBad || core::has(src_entities_view(), entity))
598 GAIA_ASSERT(sourceEntityCnt < MAX_ITEMS_IN_QUERY);
599 sourceEntities[sourceEntityCnt++] = entity;
602 GAIA_NODISCARD
bool can_reuse_src_cache()
const {
603 return sourceTermCnt > 0 && sourceTermCnt == sourceEntityCnt;
618 uint8_t changedCnt = 0;
670 return {
ids.data(), idsCnt};
674 return {
changed.data(), changedCnt};
683 if (relation == EntityBad || core::has(group_deps_view(), relation))
693 deps.set_dep_flag(DependencyHasGroup);
695 const bool hasBuiltInGroupDep =
groupBy != EntityBad && (
groupByFunc == group_by_func_default ||
697 if (hasBuiltInGroupDep)
699 for (
auto relation: group_deps_view())
700 deps.add_rel(relation);
704 return {
terms.data(), idsCnt};
707 return {
terms.data(), idsCnt};
711 static_assert(MAX_ITEMS_IN_QUERY < 16);
713 void init(World* pWorld) {
715 cc = &comp_cache_mut(*pWorld);
721 const auto isComplex_old = data.
flags & QueryFlags::Complex;
722 const auto hasSourceTerms_old = data.
flags & QueryFlags::HasSourceTerms;
723 const auto hasVariableTerms_old = data.
flags & QueryFlags::HasVariableTerms;
726 const auto dependencyFlags_old = data.
deps.flags;
727 const auto createSelectorCnt_old = data.
deps.createSelectorCnt;
728 const auto exclusionCnt_old = data.
deps.exclusionCnt;
729 const auto relationCnt_old = data.
deps.relationCnt;
730 const auto sourceEntityCnt_old = data.
deps.sourceEntityCnt;
731 const auto sourceTermCnt_old = data.
deps.sourceTermCnt;
732 auto createSelectors_old = data.
deps.createSelectors;
733 auto exclusions_old = data.
deps.exclusions;
734 auto relations_old = data.
deps.relations;
735 auto sourceEntities_old = data.
deps.sourceEntities;
739 uint32_t as_mask_0 = 0;
740 uint32_t as_mask_1 = 0;
741 bool isComplex =
false;
742 bool hasSourceTerms =
false;
743 bool hasVariableTerms =
false;
744 bool hasPrefabTerms =
false;
745 bool hasCreateSelector =
false;
746 bool canDirectCreateArchetypeMatch =
true;
747 bool hasEntityFilterTerms =
false;
748 const QueryTerm* pSingleDirectTargetAllTerm =
nullptr;
749 bool singleDirectTargetEvalPossible =
true;
750 QueryEntityArray idsNoSrc;
751 QueryEntityArray createSelectorsAll;
752 QueryEntityArray createSelectorsOr;
753 uint32_t idsNoSrcCnt = 0;
754 uint8_t createSelectorAllCnt = 0;
755 uint8_t createSelectorOrCnt = 0;
760 data.
deps.set_dep_flag(DependencyHasSort);
764 auto terms = data.terms_view();
765 const auto cnt = (uint32_t)terms.size();
767 const auto& term = terms[i];
768 const auto id = term.id;
769 hasPrefabTerms |=
id == Prefab;
770 const bool isDirectIsTerm = term.src == EntityBad && term.entTrav == EntityBad &&
771 !term_has_variables(term) && term.matchKind != QueryMatchKind::Direct &&
772 id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()) &&
773 !is_variable((EntityId)
id.gen());
774 const bool isInheritedTerm =
775 term.src == EntityBad && term.entTrav == EntityBad && !term_has_variables(term) &&
776 term.matchKind == QueryMatchKind::Semantic && !is_wildcard(
id) && !is_variable((EntityId)
id.
id()) &&
777 (!
id.pair() || !is_variable((EntityId)
id.gen())) && world_term_uses_inherit_policy(*w,
id);
778 const bool isAdjunctTerm =
779 term.src == EntityBad && term.entTrav == EntityBad && !term_has_variables(term) &&
780 ((
id.pair() && world_is_exclusive_dont_fragment_relation(*w, entity_from_id(*w,
id.
id()))) ||
781 (!
id.pair() && world_is_non_fragmenting_out_of_line_component(*w,
id)));
782 hasEntityFilterTerms |= isAdjunctTerm || isDirectIsTerm || isInheritedTerm;
786 const auto& term = terms[i];
787 const auto id = term.id;
788 if (term.src != EntityBad || term.entTrav != EntityBad || term_has_variables(term))
789 singleDirectTargetEvalPossible =
false;
791 case QueryOpKind::All:
792 if (pSingleDirectTargetAllTerm ==
nullptr)
793 pSingleDirectTargetAllTerm = &term;
795 singleDirectTargetEvalPossible =
false;
797 case QueryOpKind::Or:
798 case QueryOpKind::Not:
799 case QueryOpKind::Any:
800 case QueryOpKind::Count:
801 singleDirectTargetEvalPossible =
false;
804 const bool isDirectIsTerm = term.src == EntityBad && term.entTrav == EntityBad &&
805 !term_has_variables(term) && term.matchKind != QueryMatchKind::Direct &&
806 id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()) &&
807 !is_variable((EntityId)
id.gen());
808 const bool isInheritedTerm =
809 term.src == EntityBad && term.entTrav == EntityBad && !term_has_variables(term) &&
810 term.matchKind == QueryMatchKind::Semantic && !is_wildcard(
id) && !is_variable((EntityId)
id.
id()) &&
811 (!
id.pair() || !is_variable((EntityId)
id.gen())) && world_term_uses_inherit_policy(*w,
id);
812 const bool isCachedInheritedDataTerm = isInheritedTerm && !world_is_out_of_line_component(*w,
id);
813 const bool isAdjunctTerm =
814 term.src == EntityBad && term.entTrav == EntityBad && !term_has_variables(term) &&
815 ((
id.pair() && world_is_exclusive_dont_fragment_relation(*w, entity_from_id(*w,
id.
id()))) ||
816 (!
id.pair() && world_is_non_fragmenting_out_of_line_component(*w,
id)));
817 canDirectCreateArchetypeMatch &= term.src == EntityBad;
818 if (
id.pair() && (is_wildcard(
id.
id()) || is_wildcard(
id.gen())))
819 data.
deps.set_dep_flag(DependencyHasWildcardTerms);
820 const bool hasDynamicRelationUsage =
821 term.entTrav != EntityBad || term.src != EntityBad || term_has_variables(term);
822 if (
id.pair() && hasDynamicRelationUsage && !is_wildcard(
id.
id()) && !is_variable((EntityId)
id.
id()))
823 data.
deps.add_rel(entity_from_id(*w,
id.
id()));
824 if (term.entTrav != EntityBad) {
825 data.
deps.add_rel(term.entTrav);
826 data.
deps.set_dep_flag(DependencyHasTraversalTerms);
828 if (term.src != EntityBad) {
829 hasSourceTerms =
true;
830 data.
deps.set_dep_flag(DependencyHasSourceTerms);
831 ++data.
deps.sourceTermCnt;
832 if (!is_variable(term.src))
833 data.
deps.add_src_entity(term.src);
836 if (term_has_variables(term)) {
837 hasVariableTerms =
true;
838 data.
deps.set_dep_flag(DependencyHasVariableTerms);
843 if (isAdjunctTerm || isDirectIsTerm || isInheritedTerm) {
844 data.
deps.set_dep_flag(DependencyHasEntityFilterTerms);
845 if (isCachedInheritedDataTerm)
846 data.
deps.set_dep_flag(DependencyHasInheritedDataTerms);
847 if (
id.pair() && !is_wildcard(
id.
id()) && !is_variable((EntityId)
id.
id()))
848 data.
deps.add_rel(entity_from_id(*w,
id.
id()));
852 if (hasEntityFilterTerms && term.op == QueryOpKind::Or) {
859 if (term.src != EntityBad) {
864 if (term.op != QueryOpKind::Any)
865 idsNoSrc[idsNoSrcCnt++] = id;
867 if (term.op == QueryOpKind::All || term.op == QueryOpKind::Or) {
868 hasCreateSelector =
true;
869 data.
deps.set_dep_flag(DependencyHasPositiveTerms);
870 if (term.op == QueryOpKind::All)
871 createSelectorsAll[createSelectorAllCnt++] = id;
873 createSelectorsOr[createSelectorOrCnt++] = id;
874 }
else if (term.op == QueryOpKind::Not) {
875 data.
deps.set_dep_flag(DependencyHasNegativeTerms);
876 data.
deps.exclusions[data.
deps.exclusionCnt++] = id;
877 }
else if (term.op == QueryOpKind::Any) {
878 data.
deps.set_dep_flag(DependencyHasAnyTerms);
883 const bool allowSemanticIs = !(
884 term.matchKind == QueryMatchKind::Direct &&
id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()));
886 const auto j = (uint32_t)i;
887 const auto has_as = allowSemanticIs ? (uint32_t)is_base(*w,
id) : 0U;
888 as_mask_0 |= (has_as << j);
890 const bool idIsWildcard = is_wildcard(
id.
id());
891 const bool isGenWildcard = is_wildcard(
id.gen());
892 isComplex |= (idIsWildcard || isGenWildcard);
895 const auto j = (uint32_t)i;
896 const auto e = entity_from_id(*w,
id.
id());
897 const auto has_as = allowSemanticIs ? (uint32_t)is_base(*w, e) : 0U;
898 as_mask_0 |= (has_as << j);
901 if (!isGenWildcard) {
902 const auto j = (uint32_t)i;
903 const auto e = entity_from_id(*w,
id.gen());
904 const auto has_as = allowSemanticIs ? (uint32_t)is_base(*w, e) : 0U;
905 as_mask_1 |= (has_as << j);
910 if (singleDirectTargetEvalPossible && pSingleDirectTargetAllTerm !=
nullptr) {
911 const auto& term = *pSingleDirectTargetAllTerm;
912 const auto id = term.id;
913 if (term.matchKind == QueryMatchKind::In &&
id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()) &&
914 !is_variable((EntityId)
id.gen())) {
917 term.matchKind == QueryMatchKind::Semantic &&
id.pair() &&
id.id() == Is.id() &&
918 !is_wildcard(
id.gen()) && !is_variable((EntityId)
id.gen())) {
921 term.matchKind == QueryMatchKind::Semantic && !is_wildcard(
id) && !is_variable((EntityId)
id.
id()) &&
922 (!
id.pair() || !is_variable((EntityId)
id.gen())) && world_term_uses_inherit_policy(*w,
id)) {
933 data.
deps.createSelectorCnt = 0;
934 if (createSelectorAllCnt != 0) {
935 auto selector_rank = [](Entity term) {
938 if (!is_wildcard(term.id()) && !is_wildcard(term.gen()))
940 if (is_wildcard(term.id()) && is_wildcard(term.gen()))
950 auto bestBucketSize = world_component_index_bucket_size(*w, createSelectorsAll[0]);
951 auto bestRank = selector_rank(createSelectorsAll[0]);
952 GAIA_FOR2_(1, createSelectorAllCnt, i) {
953 const auto bucketSize = world_component_index_bucket_size(*w, createSelectorsAll[i]);
954 const auto rank = selector_rank(createSelectorsAll[i]);
955 if (bucketSize < bestBucketSize || (bucketSize == bestBucketSize && rank < bestRank)) {
956 bestBucketSize = bucketSize;
958 bestIdx = (uint8_t)i;
961 data.
deps.createSelectors[data.
deps.createSelectorCnt++] = createSelectorsAll[bestIdx];
963 GAIA_FOR(createSelectorOrCnt) {
964 data.
deps.createSelectors[data.
deps.createSelectorCnt++] = createSelectorsOr[i];
968 data.
flags |= QueryCtx::QueryFlags::HasPrefabTerms;
970 data.
flags &= ~QueryCtx::QueryFlags::HasPrefabTerms;
973 data.
flags |= QueryCtx::QueryFlags::HasSourceTerms;
975 data.
flags &= ~QueryCtx::QueryFlags::HasSourceTerms;
977 if (hasVariableTerms)
978 data.
flags |= QueryCtx::QueryFlags::HasVariableTerms;
980 data.
flags &= ~QueryCtx::QueryFlags::HasVariableTerms;
982 if (hasSourceTerms || hasVariableTerms)
985 !hasEntityFilterTerms && data.
sortByFunc ==
nullptr && data.
groupBy == EntityBad && hasCreateSelector)
991 ? CreateArchetypeMatchKind::DirectStructuralTerms
992 : CreateArchetypeMatchKind::Vm;
995 if (!data.
deps.has_dep_flag(DependencyHasSourceTerms) || !data.
deps.has_dep_flag(DependencyHasTraversalTerms))
1002 data.
flags |= QueryCtx::QueryFlags::Complex;
1004 data.
queryMask = build_entity_mask(EntitySpan{idsNoSrc.data(), idsNoSrcCnt});
1005 data.
flags &= ~QueryCtx::QueryFlags::Complex;
1010 GAIA_FOR(data.idsCnt) data.lookupTerms[i] = data.terms[i];
1011 canonicalize_lookup_terms(std::span<QueryTerm>{data.
lookupTerms.data(), data.idsCnt});
1012 GAIA_FOR(data.changedCnt) data.changedLookup[i] = data.changed[i];
1013 canonicalize_lookup_changed(std::span<Entity>{data.
changedLookup.data(), data.changedCnt});
1014 GAIA_FOR(data.
groupDepCnt) data.groupDepsLookup[i] = data.groupDeps[i];
1019 isComplex_old != (data.
flags & QueryFlags::Complex) ||
1020 hasSourceTerms_old != (data.
flags & QueryFlags::HasSourceTerms) ||
1021 hasVariableTerms_old != (data.
flags & QueryFlags::HasVariableTerms) ||
1023 dependencyFlags_old != data.
deps.flags || createSelectorCnt_old != data.
deps.createSelectorCnt ||
1024 exclusionCnt_old != data.
deps.exclusionCnt || relationCnt_old != data.
deps.relationCnt ||
1025 sourceEntityCnt_old != data.
deps.sourceEntityCnt || sourceTermCnt_old != data.
deps.sourceTermCnt ||
1026 createSelectors_old != data.
deps.createSelectors || exclusions_old != data.
deps.exclusions ||
1027 relations_old != data.
deps.relations || sourceEntities_old != data.
deps.sourceEntities)
1028 data.
flags |= QueryCtx::QueryFlags::Recompile;
1031 GAIA_NODISCARD
static bool
1032 equals_no_handle_assumption(
const QueryCtx& leftCtx,
const QueryCtx& rightCtx)
noexcept {
1034 if (leftCtx.hashLookup != rightCtx.hashLookup)
1037 const auto& left = leftCtx.data;
1038 const auto& right = rightCtx.data;
1041 if (left.idsCnt != right.idsCnt)
1043 if (left.changedCnt != right.changedCnt)
1045 if (left.groupDepCnt != right.groupDepCnt)
1047 if (left.readWriteMask != right.readWriteMask)
1049 if (left.cacheSrcTrav != right.cacheSrcTrav)
1053 const auto cnt = left.idsCnt;
1055 if (left.lookupTerms[i] != right.lookupTerms[i])
1061 const auto cnt = left.changedCnt;
1063 if (left.changedLookup[i] != right.changedLookup[i])
1069 const auto cnt = left.groupDepCnt;
1071 if (left.groupDepsLookup[i] != right.groupDepsLookup[i])
1077 if (left.sortBy != right.sortBy)
1079 if (left.sortByFunc != right.sortByFunc)
1083 if (left.groupBy != right.groupBy)
1085 if (left.groupByFunc != right.groupByFunc)
1091 GAIA_NODISCARD
bool operator==(
const QueryCtx& other)
const noexcept {
1093 GAIA_ASSERT(
q.
handle.id() == QueryIdBad);
1098 return equals_no_handle_assumption(*
this, other);
1101 GAIA_NODISCARD
bool operator!=(
const QueryCtx& other)
const noexcept {
1102 return !operator==(other);
1109 return query_term_less_for_lookup(lhs, rhs);
1115 const uint32_t idsCnt = ctx.data.idsCnt;
1116 const uint32_t changedCnt = ctx.data.changedCnt;
1118 auto& ctxData = ctx.data;
1123 uint32_t orIdx = BadIndex;
1125 if (ctxData.terms[i].op != QueryOpKind::Or)
1134 ctxData.terms[orIdx].op = QueryOpKind::All;
1141 ctxData.terms.data(), ctxData.terms.data() + ctxData.idsCnt, query_sort_cond{},
1142 [&](uint32_t left, uint32_t right) {
1143 core::swap(ctxData.ids[left], ctxData.ids[right]);
1144 core::swap(ctxData.terms[left], ctxData.terms[right]);
1147 core::swap_bits(ctxData.readWriteMask, left, right);
1148 core::swap_bits(ctxData.as_mask_0, left, right);
1149 core::swap_bits(ctxData.as_mask_1, left, right);
1154 while (i < idsCnt && ctxData.terms[i].op == QueryOpKind::All)
1156 ctxData.firstOr = (uint8_t)i;
1157 while (i < idsCnt && ctxData.terms[i].op == QueryOpKind::Or)
1159 ctxData.firstNot = (uint8_t)i;
1160 while (i < idsCnt && ctxData.terms[i].op == QueryOpKind::Not)
1162 ctxData.firstAny = (uint8_t)i;
1164 ctxData.firstOr = ctxData.firstNot = ctxData.firstAny = 0;
1168 if (changedCnt > 1) {
1169 core::sort(ctxData.changed.data(), ctxData.changed.data() + changedCnt, SortComponentCond{});
1175 inline void normalize_cache_src_trav(QueryCtx& ctx) {
1176 auto& ctxData = ctx.data;
1177 if (ctxData.cacheSrcTrav == 0)
1180 bool hasTraversedSourceTerm =
false;
1181 for (
const auto& term: ctxData.terms_view()) {
1182 if (term.src == EntityBad || term.entTrav == EntityBad)
1185 hasTraversedSourceTerm =
true;
1189 if (!hasTraversedSourceTerm)
1190 ctxData.cacheSrcTrav = 0;
1193 inline void calc_lookup_hash(QueryCtx& ctx) {
1194 GAIA_ASSERT(ctx.cc !=
nullptr);
1196 GAIA_ASSERT(ctx.hashLookup.hash == 0);
1198 QueryLookupHash::Type hashLookup = 0;
1200 const auto& ctxData = ctx.data;
1204 QueryLookupHash::Type hash = 0;
1206 for (uint32_t i = 0; i < ctxData.idsCnt; ++i) {
1207 const auto& pair = ctxData.lookupTerms[i];
1208 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.op);
1209 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.id.value());
1210 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.src.value());
1211 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.entTrav.value());
1212 hash = core::hash_combine(hash, (QueryLookupHash::Type)(uint8_t)pair.travKind);
1213 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.travDepth);
1214 hash = core::hash_combine(hash, (QueryLookupHash::Type)(uint8_t)pair.matchKind);
1216 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.idsCnt);
1217 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.readWriteMask);
1218 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.cacheSrcTrav);
1220 const bool matchPrefab = (ctxData.flags & QueryCtx::QueryFlags::MatchPrefab) != 0;
1221 hash = core::hash_combine(hash, (QueryLookupHash::Type)matchPrefab);
1228 QueryLookupHash::Type hash = 0;
1230 for (uint32_t i = 0; i < ctxData.changedCnt; ++i)
1231 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.changedLookup[i].value());
1232 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.changedCnt);
1234 hashLookup = core::hash_combine(hashLookup, hash);
1239 QueryLookupHash::Type hash = 0;
1241 for (uint32_t i = 0; i < ctxData.groupDepCnt; ++i)
1242 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.groupDepsLookup[i].value());
1243 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.groupDepCnt);
1245 hashLookup = core::hash_combine(hashLookup, hash);
1250 QueryLookupHash::Type hash = 0;
1252 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.groupBy.value());
1253 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.groupByFunc);
1255 hashLookup = core::hash_combine(hashLookup, hash);
1258 ctx.hashLookup = {core::calculate_hash64(hashLookup)};
1267 template <u
int32_t MAX_COMPONENTS>
1268 GAIA_NODISCARD
inline uint32_t comp_idx(
const QueryTerm* pTerms, Entity entity, Entity src) {
1271 GAIA_FOR(MAX_COMPONENTS) {
1272 if (pTerms[i].
id == entity && pTerms[i].src == src)
Array with variable size of elements of type.
Definition darray_impl.h:25
Array of elements of type.
Definition sarray_ext_impl.h:27
Array of elements of type.
Definition sarray_impl.h:26
Definition span_impl.h:99
Definition archetype.h:83
Cache for compile-time defined components.
Definition component_cache.h:25
Same API as ser_buffer_binary, but backed by fully dynamic storage.
Definition ser_buffer_binary.h:157
Definition robin_hood.h:720
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition query_common.h:98
Hashmap lookup structure used for Entity.
Definition id.h:439
Definition query_common.h:541
Definition query_common.h:540
cnt::sarray< QueryTerm, MAX_ITEMS_IN_QUERY > lookupTerms
Canonicalized lookup terms reused by hash/equality for shared query dedup.
Definition query_common.h:612
uint16_t readWriteMask
Read-write mask. Bit 0 stands for component 0 in component arrays. A set bit means write access is re...
Definition query_common.h:653
QueryEntityArray groupDeps
Explicit grouping invalidation dependencies for custom group_by callbacks.
Definition query_common.h:624
Entity sortBy
Entity to sort the archetypes by. EntityBad for no sorting.
Definition query_common.h:628
TGroupByFunc groupByFunc
Function to use to perform the grouping.
Definition query_common.h:634
uint32_t as_mask_0
Mask for items with Is relationship pair. If the id is a pair, the first part (id) is written here.
Definition query_common.h:639
Entity groupBy
Entity to group the archetypes by. EntityBad for no grouping.
Definition query_common.h:632
void add_group_dep(Entity relation)
Adds a declared grouping invalidation dependency.
Definition query_common.h:682
QueryEntityArray ids
Array of queried ids.
Definition query_common.h:608
uint32_t as_mask_1
Mask for items with Is relationship pair. If the id is a pair, the second part (gen) is written here.
Definition query_common.h:642
uint8_t firstOr
First OR record in pairs/ids/ops.
Definition query_common.h:648
uint16_t cacheSrcTrav
Maximum allowed size of an explicitly cached traversed-source lookup closure.
Definition query_common.h:657
QueryEntityArray changedLookup
Canonicalized changed-filter ids reused by hash/equality for shared query dedup.
Definition query_common.h:622
QueryMask queryMask
Component mask used for faster matching of simple queries.
Definition query_common.h:636
uint8_t firstAny
First ANY record in pairs/ids/ops.
Definition query_common.h:646
QueryArchetypeCacheIndexMap lastMatchedArchetypeIdx_All
Index of the last checked archetype in the component-to-archetype map.
Definition query_common.h:614
CreateArchetypeMatchKind createArchetypeMatchKind
Create-time archetype matcher derived from query shape.
Definition query_common.h:667
Entity directTargetEvalId
Term id used by the specialized direct-target evaluation shape.
Definition query_common.h:661
void add_group_deps()
Adds all grouping invalidation relations to the dependency set.
Definition query_common.h:692
QueryEntityArray groupDepsLookup
Canonicalized group dependency ids reused by hash/equality for shared query dedup.
Definition query_common.h:626
Dependencies deps
Explicit dependency metadata derived from query shape.
Definition query_common.h:663
TSortByFunc sortByFunc
Function to use to perform sorting.
Definition query_common.h:630
uint8_t flags
Query flags.
Definition query_common.h:655
uint8_t firstNot
First NOT record in pairs/ids/ops.
Definition query_common.h:644
CachePolicy cachePolicy
Cache maintenance policy derived from query shape.
Definition query_common.h:665
uint8_t groupDepCnt
Number of defined group dependencies.
Definition query_common.h:650
QueryEntityArray changed
Array of filtered components.
Definition query_common.h:620
cnt::sarray< QueryTerm, MAX_ITEMS_IN_QUERY > terms
Array of terms.
Definition query_common.h:610
DirectTargetEvalKind directTargetEvalKind
Specialized direct-target evaluation shape for single-term queries.
Definition query_common.h:659
Definition query_common.h:471
ComponentCache * cc
Component cache.
Definition query_common.h:475
QueryIdentity q
Query identity.
Definition query_common.h:479
QueryLookupHash hashLookup
Lookup hash for this query.
Definition query_common.h:477
Hashmap lookup structure used for Entity.
Definition query_common.h:174
Definition query_common.h:125
Definition query_common.h:457
QueryHandle handle
Query id.
Definition query_common.h:459
QueryId serId
Serialization id.
Definition query_common.h:461
Additional options for query terms. This can be used to configure source lookup, traversal and access...
Definition query_common.h:252
uint8_t travDepth
Maximum number of traversal steps. 0 means unlimited traversal depth (bounded internally,...
Definition query_common.h:263
Entity entSrc
Source entity to query from.
Definition query_common.h:256
Entity entTrav
Optional traversal relation used for source lookup.
Definition query_common.h:258
QueryAccess access
Access mode for the term. When None, typed query terms infer read/write access from template mutabili...
Definition query_common.h:266
QueryMatchKind matchKind
Match semantics for terms with special meaning, such as Pair(Is, X).
Definition query_common.h:268
QueryTravKind travKind
Source traversal filter.
Definition query_common.h:260
Internal representation of QueryInput.
Definition query_common.h:363
Entity id
Queried id.
Definition query_common.h:365
Archetype * srcArchetype
Archetype of the src entity.
Definition query_common.h:377
uint8_t travDepth
Maximum number of traversal steps.
Definition query_common.h:373
QueryMatchKind matchKind
Match semantics for this term.
Definition query_common.h:375
uint8_t fieldIndex
Stable execution field index matching the user-defined query field order.
Definition query_common.h:381
Entity entTrav
Optional traversal relation for source lookups.
Definition query_common.h:369
QueryOpKind op
Operation to perform with the term.
Definition query_common.h:379
Entity src
Source of where the queried id is looked up at.
Definition query_common.h:367
QueryTravKind travKind
Source traversal filter.
Definition query_common.h:371
Definition query_common.h:110
Functor for sorting terms in a query before compilation.
Definition query_common.h:1107