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 void world_finish_write(World& world, Entity term, Entity entity);
49 GAIA_NODISCARD uint32_t world_component_index_bucket_size(
const World& world, Entity term);
50 GAIA_NODISCARD uint32_t world_component_index_comp_idx(
const World& world,
const Archetype& archetype, Entity term);
51 GAIA_NODISCARD uint32_t
52 world_component_index_match_count(
const World& world,
const Archetype& archetype, Entity term);
54 GAIA_NODISCARD GroupId group_by_func_depth_order(
const World& world,
const Archetype& archetype, Entity relation);
56 GAIA_NODISCARD
decltype(
auto) world_direct_entity_arg(World& world, Entity entity);
58 GAIA_NODISCARD
decltype(
auto) world_query_entity_arg(World& world, Entity entity);
60 GAIA_NODISCARD Entity world_query_arg_id(World& world);
62 GAIA_NODISCARD
decltype(
auto) world_query_entity_arg_by_id(World& world, Entity entity, Entity
id);
64 GAIA_NODISCARD
decltype(
auto) world_query_entity_arg_by_id_raw(World& world, Entity entity, Entity
id);
66 GAIA_NODISCARD uint32_t world_entity_archetype_version(
const World& world, Entity entity);
69 static constexpr uint32_t MAX_ITEMS_IN_QUERY = 12U;
71 static constexpr uint32_t MAX_TRAV_DEPTH = 128U;
73 GAIA_GCC_WARNING_PUSH()
76 GAIA_GCC_WARNING_DISABLE("-Wshadow")
79 enum class QueryOpKind : uint8_t { All, Or, Not, Any, Count };
81 enum class QueryAccess : uint8_t { None, Read, Write };
83 enum class QueryMatchKind : uint8_t { Semantic, In, Direct };
85 enum class QueryInputFlags : uint8_t { None, Variable };
87 enum class QueryTravKind : uint8_t { None = 0x00, Self = 0x01, Up = 0x02, Down = 0x04 };
89 GAIA_GCC_WARNING_POP()
91 GAIA_NODISCARD constexpr QueryTravKind operator|(QueryTravKind lhs, QueryTravKind rhs) {
92 return (QueryTravKind)((uint8_t)lhs | (uint8_t)rhs);
95 GAIA_NODISCARD
constexpr bool query_trav_has(QueryTravKind value, QueryTravKind bit) {
96 return (((uint8_t)value) & ((uint8_t)bit)) != 0;
99 using QueryLookupHash = core::direct_hash_key<uint64_t>;
100 using QueryEntityArray = cnt::sarray<Entity, MAX_ITEMS_IN_QUERY>;
101 using QuerySerMap = cnt::map<QueryId, QuerySerBuffer>;
115 static constexpr uint16_t ComponentIndexBad = (uint16_t)-1;
119 uint16_t compIdx = ComponentIndexBad;
120 uint16_t matchCount = 0;
122 GAIA_NODISCARD
bool matches(
const Archetype* pOther)
const {
123 return pArchetype == pOther;
141 static constexpr QueryId QueryIdBad = (QueryId)-1;
142 static constexpr GroupId GroupIdMax = ((GroupId)-1) - 1;
145 static constexpr uint32_t IdMask = QueryIdBad;
159 constexpr QueryHandle()
noexcept: val((uint64_t)-1) {};
172 GAIA_NODISCARD
constexpr bool operator==(
const QueryHandle& other)
const noexcept {
173 return val == other.val;
175 GAIA_NODISCARD
constexpr bool operator!=(
const QueryHandle& other)
const noexcept {
176 return val != other.val;
179 GAIA_NODISCARD
auto id()
const {
182 GAIA_NODISCARD
auto gen()
const {
185 GAIA_NODISCARD
auto value()
const {
203 return {core::calculate_hash64(handle.value())};
207 static constexpr bool IsDirectHashKey =
true;
222 size_t hash()
const {
223 return (
size_t)m_hash.hash;
227 if GAIA_LIKELY (m_hash != other.m_hash)
230 return m_handle == other.m_handle;
234 return !operator==(other);
242 static constexpr uint8_t TravDepthUnlimited = 0;
245 QueryOpKind
op = QueryOpKind::All;
260 QueryTravKind
travKind = QueryTravKind::Self | QueryTravKind::Up;
272 static constexpr uint8_t TravDepthUnlimited = QueryInput::TravDepthUnlimited;
279 QueryTravKind
travKind = QueryTravKind::Self | QueryTravKind::Up;
296 travKind = QueryTravKind::Self | QueryTravKind::Up;
301 QueryTermOptions& trav_up(Entity relation = ChildOf) {
308 QueryTermOptions& trav_parent(Entity relation = ChildOf) {
315 QueryTermOptions& trav_self_parent(Entity relation = ChildOf) {
317 travKind = QueryTravKind::Self | QueryTravKind::Up;
322 QueryTermOptions& trav_down(Entity relation = ChildOf) {
329 QueryTermOptions& trav_self_down(Entity relation = ChildOf) {
331 travKind = QueryTravKind::Self | QueryTravKind::Down;
336 QueryTermOptions& trav_child(Entity relation = ChildOf) {
343 QueryTermOptions& trav_self_child(Entity relation = ChildOf) {
345 travKind = QueryTravKind::Self | QueryTravKind::Down;
350 QueryTermOptions& trav_kind(QueryTravKind kind) {
355 QueryTermOptions& trav_depth(uint8_t maxDepth) {
360 QueryTermOptions& read() {
361 access = QueryAccess::Read;
365 QueryTermOptions& write() {
366 access = QueryAccess::Write;
370 QueryTermOptions& direct() {
375 QueryTermOptions& in() {
413 if (entity == EntityBad || core::has(
reads_view(), entity))
416 GAIA_ASSERT(
readCnt < MAX_ITEMS_IN_QUERY);
417 if (
readCnt < MAX_ITEMS_IN_QUERY)
424 if (entity == EntityBad || core::has(
writes_view(), entity))
427 GAIA_ASSERT(
writeCnt < MAX_ITEMS_IN_QUERY);
437 return QueryAccess::Write;
439 return QueryAccess::Read;
440 return QueryAccess::None;
465 bool operator==(
const QueryTerm& other)
const {
469 bool operator!=(
const QueryTerm& other)
const {
470 return !operator==(other);
474 constexpr bool query_term_less_for_lookup(
const QueryTerm& lhs,
const QueryTerm& rhs) {
475 if (lhs.op != rhs.op)
476 return lhs.op < rhs.op;
478 if (lhs.id != rhs.id)
479 return SortComponentCond()(lhs.id, rhs.id);
481 if (lhs.src != rhs.src)
482 return SortComponentCond()(lhs.src, rhs.src);
484 if (lhs.entTrav != rhs.entTrav)
485 return SortComponentCond()(lhs.entTrav, rhs.entTrav);
487 if (lhs.travKind != rhs.travKind)
488 return (uint8_t)lhs.travKind < (uint8_t)rhs.travKind;
490 if (lhs.travDepth != rhs.travDepth)
491 return lhs.travDepth < rhs.travDepth;
493 return (uint8_t)lhs.matchKind < (uint8_t)rhs.matchKind;
497 const auto idsCnt = (uint32_t)terms.size();
502 if (terms[i].op != QueryOpKind::Or)
511 terms[orIdx].op = QueryOpKind::All;
514 core::sort(terms.data(), terms.data() + idsCnt, [](
const QueryTerm& left,
const QueryTerm& right) {
515 return query_term_less_for_lookup(left, right);
520 const auto changedCnt = (uint32_t)changed.size();
522 core::sort(changed.data(), changed.data() + changedCnt, SortComponentCond{});
525 GAIA_NODISCARD
inline bool term_has_variables(
const QueryTerm& term) {
526 if (is_variable(term.src))
530 return is_variable(EntityId(term.id.id())) || is_variable(EntityId(term.id.gen()));
532 return is_variable(EntityId(term.id.id()));
539 GAIA_NODISCARD
inline bool query_term_uses_potential_inherited_id_matching(
const QueryTerm& term) {
540 const auto id = term.id;
541 return term.matchKind == QueryMatchKind::Semantic && term.src == EntityBad && term.entTrav == EntityBad &&
542 !term_has_variables(term) && !is_wildcard(
id) && !is_variable((EntityId)
id.
id()) &&
543 (!
id.pair() || !is_variable((EntityId)
id.gen()));
546 using QueryTermArray = cnt::sarray_ext<QueryTerm, MAX_ITEMS_IN_QUERY>;
548 using QueryRemappingArray = cnt::sarray_ext<uint8_t, MAX_ITEMS_IN_QUERY>;
557 return query_buffer(*world,
serId);
559 void ser_buffer_reset(
World* world) {
560 query_buffer_reset(*world,
serId);
574 enum QueryFlags : uint16_t {
585 HasSourceTerms = 0x10,
587 HasVariableTerms = 0x20,
591 HasPrefabTerms = 0x80,
596 enum class CachePolicy : uint8_t {
605 enum class CreateArchetypeMatchKind : uint8_t {
609 DirectStructuralTerms,
628 enum class DirectTargetEvalKind : uint8_t {
636 enum DependencyFlags : uint16_t {
637 DependencyNone = 0x00,
638 DependencyHasSourceTerms = 0x01,
639 DependencyHasVariableTerms = 0x02,
640 DependencyHasPositiveTerms = 0x04,
641 DependencyHasNegativeTerms = 0x08,
642 DependencyHasAnyTerms = 0x10,
643 DependencyHasWildcardTerms = 0x20,
644 DependencyHasSort = 0x40,
645 DependencyHasGroup = 0x80,
646 DependencyHasTraversalTerms = 0x100,
647 DependencyHasEntityFilterTerms = 0x200,
648 DependencyHasInheritedDataTerms = 0x400,
649 DependencyHasPotentialInheritedIdTerms = 0x800,
658 uint8_t createSelectorCnt = 0;
659 uint8_t exclusionCnt = 0;
660 uint8_t relationCnt = 0;
661 uint8_t sourceEntityCnt = 0;
662 uint8_t sourceTermCnt = 0;
663 DependencyFlags flags = DependencyNone;
666 createSelectorCnt = 0;
671 flags = DependencyNone;
675 return {createSelectors.data(), createSelectorCnt};
679 return {exclusions.data(), exclusionCnt};
683 return {relations.data(), relationCnt};
687 return {sourceEntities.data(), sourceEntityCnt};
690 void set_dep_flag(DependencyFlags dependency) {
691 flags = (DependencyFlags)(flags | dependency);
694 GAIA_NODISCARD
bool has_dep_flag(DependencyFlags dependency)
const {
695 return (flags & dependency) != 0;
698 void add_rel(
Entity relation) {
699 if (relation == EntityBad || core::has(relations_view(), relation))
702 GAIA_ASSERT(relationCnt < MAX_ITEMS_IN_QUERY);
703 relations[relationCnt++] = relation;
706 void add_src_entity(
Entity entity) {
707 if (entity == EntityBad || core::has(src_entities_view(), entity))
710 GAIA_ASSERT(sourceEntityCnt < MAX_ITEMS_IN_QUERY);
711 sourceEntities[sourceEntityCnt++] = entity;
714 GAIA_NODISCARD
bool can_reuse_src_cache()
const {
715 return sourceTermCnt > 0 && sourceTermCnt == sourceEntityCnt;
737 uint8_t changedCnt = 0;
799 return {
ids.data(), idsCnt};
803 return {
changed.data(), changedCnt};
847 if (relation == EntityBad || core::has(group_deps_view(), relation))
857 deps.set_dep_flag(DependencyHasGroup);
859 const bool hasBuiltInGroupDep =
groupBy != EntityBad && (
groupByFunc == group_by_func_default ||
861 if (hasBuiltInGroupDep)
863 for (
auto relation: group_deps_view())
864 deps.add_rel(relation);
868 return {
terms.data(), idsCnt};
871 return {
terms.data(), idsCnt};
880 const bool hasVariables =
deps.has_dep_flag(DependencyHasVariableTerms);
881 const bool hasSources =
deps.has_dep_flag(DependencyHasSourceTerms);
882 const bool hasTraversal =
deps.has_dep_flag(DependencyHasTraversalTerms);
883 const bool hasRelations =
deps.relationCnt != 0;
884 if (hasSources && hasTraversal && !hasVariables)
887 const uint8_t depCnt = (uint8_t)hasVariables + (uint8_t)hasSources + (uint8_t)hasRelations;
924 return deps.can_reuse_src_cache();
928 if (!
deps.has_dep_flag(DependencyHasSourceTerms))
930 if (!
deps.can_reuse_src_cache())
932 return !
deps.has_dep_flag(DependencyHasTraversalTerms) ||
cacheSrcTrav != 0;
954 GAIA_FOR((uint32_t)left.size()) {
955 if (left[i] != right[i])
963 GAIA_FOR((uint32_t)left.size()) {
964 if (left[i] != right[i])
972 GAIA_FOR((uint32_t)left.size()) {
973 if (left[i] != right[i])
987 QueryLookupHash::Type hash = 0;
990 hash = core::hash_combine(hash, (QueryLookupHash::Type)
pair.op);
991 hash = core::hash_combine(hash, (QueryLookupHash::Type)
pair.id.value());
992 hash = core::hash_combine(hash, (QueryLookupHash::Type)
pair.src.value());
993 hash = core::hash_combine(hash, (QueryLookupHash::Type)
pair.entTrav.value());
994 hash = core::hash_combine(hash, (QueryLookupHash::Type)(uint8_t)
pair.travKind);
995 hash = core::hash_combine(hash, (QueryLookupHash::Type)
pair.travDepth);
996 hash = core::hash_combine(hash, (QueryLookupHash::Type)(uint8_t)
pair.matchKind);
998 hash = core::hash_combine(hash, (QueryLookupHash::Type)idsCnt);
999 hash = core::hash_combine(hash, (QueryLookupHash::Type)
readWriteMask);
1000 hash = core::hash_combine(hash, (QueryLookupHash::Type)
cacheSrcTrav);
1002 const bool matchPrefab = (
flags & QueryFlags::MatchPrefab) != 0;
1003 hash = core::hash_combine(hash, (QueryLookupHash::Type)matchPrefab);
1010 QueryLookupHash::Type hash = 0;
1013 hash = core::hash_combine(hash, (QueryLookupHash::Type)entity.value());
1014 hash = core::hash_combine(hash, (QueryLookupHash::Type)changedCnt);
1021 QueryLookupHash::Type hash = 0;
1024 hash = core::hash_combine(hash, (QueryLookupHash::Type)entity.value());
1025 hash = core::hash_combine(hash, (QueryLookupHash::Type)
groupDepCnt);
1039 return (
flags & QueryFlags::OrderGroups) == (other.
flags & QueryFlags::OrderGroups);
1054 QueryLookupHash::Type hash = 0;
1055 hash = core::hash_combine(hash, (QueryLookupHash::Type)
sortBy.value());
1056 hash = core::hash_combine(hash, (QueryLookupHash::Type)
sortByFunc);
1062 if (idsCnt != other.idsCnt)
1064 if (changedCnt != other.changedCnt)
1081 QueryLookupHash::Type hash = 0;
1082 hash = core::hash_combine(hash, (QueryLookupHash::Type)
groupBy.value());
1083 hash = core::hash_combine(hash, (QueryLookupHash::Type)
groupByFunc);
1084 hash = core::hash_combine(hash, (QueryLookupHash::Type)((
flags & QueryFlags::OrderGroups) != 0));
1102 static_assert(MAX_ITEMS_IN_QUERY < 16);
1104 void init(World* pWorld) {
1106 cc = &comp_cache_mut(*pWorld);
1112 const auto isComplex_old = data.
flags & QueryFlags::Complex;
1113 const auto hasSourceTerms_old = data.
flags & QueryFlags::HasSourceTerms;
1114 const auto hasVariableTerms_old = data.
flags & QueryFlags::HasVariableTerms;
1122 const auto dependencyFlags_old = data.
deps.flags;
1123 const auto createSelectorCnt_old = data.
deps.createSelectorCnt;
1124 const auto exclusionCnt_old = data.
deps.exclusionCnt;
1125 const auto relationCnt_old = data.
deps.relationCnt;
1126 const auto sourceEntityCnt_old = data.
deps.sourceEntityCnt;
1127 const auto sourceTermCnt_old = data.
deps.sourceTermCnt;
1128 auto createSelectors_old = data.
deps.createSelectors;
1129 auto exclusions_old = data.
deps.exclusions;
1130 auto relations_old = data.
deps.relations;
1131 auto sourceEntities_old = data.
deps.sourceEntities;
1135 uint32_t as_mask_0 = 0;
1136 uint32_t as_mask_1 = 0;
1137 bool isComplex =
false;
1138 bool hasSourceTerms =
false;
1139 bool hasVariableTerms =
false;
1140 bool hasPrefabTerms =
false;
1141 bool hasCreateSelector =
false;
1142 bool canDirectCreateArchetypeMatch =
true;
1143 bool hasEntityFilterTerms =
false;
1144 bool canDirectTargetEval =
true;
1145 bool hasOnlyDirectOrTerms =
true;
1146 bool hasOrTerms =
false;
1147 bool hasDirectTargetEvalPositiveTerms =
false;
1148 const QueryTerm* pSingleDirectTargetAllTerm =
nullptr;
1149 bool singleDirectTargetEvalPossible =
true;
1150 QueryEntityArray idsNoSrc;
1151 QueryEntityArray createSelectorsAll;
1152 QueryEntityArray createSelectorsOr;
1153 uint32_t idsNoSrcCnt = 0;
1154 uint8_t createSelectorAllCnt = 0;
1155 uint8_t createSelectorOrCnt = 0;
1160 data.
deps.set_dep_flag(DependencyHasSort);
1161 if (data.
groupBy != EntityBad)
1164 auto terms = data.terms_view();
1165 const auto cnt = (uint32_t)terms.size();
1167 const auto& term = terms[i];
1168 const auto id = term.id;
1169 hasPrefabTerms |=
id == Prefab;
1170 const bool isDirectIsTerm = term.src == EntityBad && term.entTrav == EntityBad &&
1171 !term_has_variables(term) && term.matchKind != QueryMatchKind::Direct &&
1172 id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()) &&
1173 !is_variable((EntityId)
id.gen());
1174 const bool isPotentialInheritedTerm = query_term_uses_potential_inherited_id_matching(term);
1175 const bool isInheritedTerm = isPotentialInheritedTerm && world_term_uses_inherit_policy(*w,
id);
1176 const bool isAdjunctTerm =
1177 term.src == EntityBad && term.entTrav == EntityBad && !term_has_variables(term) &&
1178 ((
id.pair() && world_is_exclusive_dont_fragment_relation(*w, pair_rel(*w,
id))) ||
1179 (!
id.pair() && world_is_non_fragmenting_out_of_line_component(*w,
id)));
1180 hasEntityFilterTerms |= isAdjunctTerm || isDirectIsTerm || isInheritedTerm;
1184 const auto& term = terms[i];
1185 const auto id = term.id;
1186 if (term.src != EntityBad || term.entTrav != EntityBad || term_has_variables(term)) {
1187 singleDirectTargetEvalPossible =
false;
1188 canDirectTargetEval =
false;
1189 hasOnlyDirectOrTerms =
false;
1192 case QueryOpKind::All:
1193 hasDirectTargetEvalPositiveTerms =
true;
1194 if (pSingleDirectTargetAllTerm ==
nullptr)
1195 pSingleDirectTargetAllTerm = &term;
1197 singleDirectTargetEvalPossible =
false;
1198 hasOnlyDirectOrTerms =
false;
1200 case QueryOpKind::Or:
1201 hasDirectTargetEvalPositiveTerms =
true;
1204 case QueryOpKind::Not:
1206 case QueryOpKind::Any:
1207 case QueryOpKind::Count:
1208 singleDirectTargetEvalPossible =
false;
1209 canDirectTargetEval =
false;
1210 hasOnlyDirectOrTerms =
false;
1213 const bool isDirectIsTerm = term.src == EntityBad && term.entTrav == EntityBad &&
1214 !term_has_variables(term) && term.matchKind != QueryMatchKind::Direct &&
1215 id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()) &&
1216 !is_variable((EntityId)
id.gen());
1217 const bool isPotentialInheritedTerm = query_term_uses_potential_inherited_id_matching(term);
1218 const bool isInheritedTerm = isPotentialInheritedTerm && world_term_uses_inherit_policy(*w,
id);
1219 const bool isCachedInheritedDataTerm = isInheritedTerm && !world_is_out_of_line_component(*w,
id);
1220 const bool isAdjunctTerm =
1221 term.src == EntityBad && term.entTrav == EntityBad && !term_has_variables(term) &&
1222 ((
id.pair() && world_is_exclusive_dont_fragment_relation(*w, pair_rel(*w,
id))) ||
1223 (!
id.pair() && world_is_non_fragmenting_out_of_line_component(*w,
id)));
1224 canDirectCreateArchetypeMatch &= term.src == EntityBad;
1225 if (
id.pair() && (is_wildcard(
id.
id()) || is_wildcard(
id.gen())))
1226 data.
deps.set_dep_flag(DependencyHasWildcardTerms);
1227 const bool hasDynamicRelationUsage =
1228 term.entTrav != EntityBad || term.src != EntityBad || term_has_variables(term);
1229 if (
id.pair() && hasDynamicRelationUsage && !is_wildcard(
id.
id()) && !is_variable((EntityId)
id.
id()))
1230 data.
deps.add_rel(pair_rel(*w,
id));
1231 if (term.entTrav != EntityBad) {
1232 data.
deps.add_rel(term.entTrav);
1233 data.
deps.set_dep_flag(DependencyHasTraversalTerms);
1235 if (term.src != EntityBad) {
1236 hasSourceTerms =
true;
1237 data.
deps.set_dep_flag(DependencyHasSourceTerms);
1238 ++data.
deps.sourceTermCnt;
1239 if (!is_variable(term.src))
1240 data.
deps.add_src_entity(term.src);
1243 if (term_has_variables(term)) {
1244 hasVariableTerms =
true;
1245 data.
deps.set_dep_flag(DependencyHasVariableTerms);
1250 if (isPotentialInheritedTerm)
1251 data.
deps.set_dep_flag(DependencyHasPotentialInheritedIdTerms);
1253 if (isAdjunctTerm || isDirectIsTerm || isInheritedTerm) {
1254 data.
deps.set_dep_flag(DependencyHasEntityFilterTerms);
1255 if (isCachedInheritedDataTerm)
1256 data.
deps.set_dep_flag(DependencyHasInheritedDataTerms);
1257 if (
id.pair() && !is_wildcard(
id.
id()) && !is_variable((EntityId)
id.
id()))
1258 data.
deps.add_rel(pair_rel(*w,
id));
1262 if (hasEntityFilterTerms && term.op == QueryOpKind::Or) {
1269 if (term.src != EntityBad) {
1274 if (term.op != QueryOpKind::Any)
1275 idsNoSrc[idsNoSrcCnt++] = id;
1277 if (term.op == QueryOpKind::All || term.op == QueryOpKind::Or) {
1278 hasCreateSelector =
true;
1279 data.
deps.set_dep_flag(DependencyHasPositiveTerms);
1280 if (term.op == QueryOpKind::All)
1281 createSelectorsAll[createSelectorAllCnt++] = id;
1283 createSelectorsOr[createSelectorOrCnt++] = id;
1284 }
else if (term.op == QueryOpKind::Not) {
1285 data.
deps.set_dep_flag(DependencyHasNegativeTerms);
1286 data.
deps.exclusions[data.
deps.exclusionCnt++] = id;
1287 }
else if (term.op == QueryOpKind::Any) {
1288 data.
deps.set_dep_flag(DependencyHasAnyTerms);
1293 const bool allowSemanticIs = !(
1294 term.matchKind == QueryMatchKind::Direct &&
id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()));
1296 const auto j = (uint32_t)i;
1297 const auto has_as = allowSemanticIs ? (uint32_t)is_base(*w,
id) : 0U;
1298 as_mask_0 |= (has_as << j);
1300 const bool idIsWildcard = is_wildcard(
id.
id());
1301 const bool isGenWildcard = is_wildcard(
id.gen());
1302 isComplex |= (idIsWildcard || isGenWildcard);
1304 if (!idIsWildcard) {
1305 const auto j = (uint32_t)i;
1306 const auto e = pair_rel(*w,
id);
1307 const auto has_as = allowSemanticIs ? (uint32_t)is_base(*w, e) : 0U;
1308 as_mask_0 |= (has_as << j);
1311 if (!isGenWildcard) {
1312 const auto j = (uint32_t)i;
1313 const auto e = pair_tgt(*w,
id);
1314 const auto has_as = allowSemanticIs ? (uint32_t)is_base(*w, e) : 0U;
1315 as_mask_1 |= (has_as << j);
1320 if (singleDirectTargetEvalPossible && pSingleDirectTargetAllTerm !=
nullptr) {
1321 const auto& term = *pSingleDirectTargetAllTerm;
1322 const auto id = term.id;
1323 if (term.matchKind == QueryMatchKind::In &&
id.pair() &&
id.id() == Is.id() && !is_wildcard(
id.gen()) &&
1324 !is_variable((EntityId)
id.gen())) {
1327 term.matchKind == QueryMatchKind::Semantic &&
id.pair() &&
id.id() == Is.id() &&
1328 !is_wildcard(
id.gen()) && !is_variable((EntityId)
id.gen())) {
1331 term.matchKind == QueryMatchKind::Semantic && !is_wildcard(
id) && !is_variable((EntityId)
id.
id()) &&
1332 (!
id.pair() || !is_variable((EntityId)
id.gen())) && world_term_uses_inherit_policy(*w,
id)) {
1347 data.
deps.createSelectorCnt = 0;
1348 if (createSelectorAllCnt != 0) {
1349 auto selector_rank = [](Entity term) {
1352 if (!is_wildcard(term.id()) && !is_wildcard(term.gen()))
1354 if (is_wildcard(term.id()) && is_wildcard(term.gen()))
1363 uint8_t bestIdx = 0;
1364 auto bestBucketSize = world_component_index_bucket_size(*w, createSelectorsAll[0]);
1365 auto bestRank = selector_rank(createSelectorsAll[0]);
1366 GAIA_FOR2_(1, createSelectorAllCnt, i) {
1367 const auto bucketSize = world_component_index_bucket_size(*w, createSelectorsAll[i]);
1368 const auto rank = selector_rank(createSelectorsAll[i]);
1369 if (bucketSize < bestBucketSize || (bucketSize == bestBucketSize && rank < bestRank)) {
1370 bestBucketSize = bucketSize;
1372 bestIdx = (uint8_t)i;
1375 data.
deps.createSelectors[data.
deps.createSelectorCnt++] = createSelectorsAll[bestIdx];
1377 GAIA_FOR(createSelectorOrCnt) {
1378 data.
deps.createSelectors[data.
deps.createSelectorCnt++] = createSelectorsOr[i];
1382 data.
flags |= QueryCtx::QueryFlags::HasPrefabTerms;
1384 data.
flags &= ~QueryCtx::QueryFlags::HasPrefabTerms;
1387 data.
flags |= QueryCtx::QueryFlags::HasSourceTerms;
1389 data.
flags &= ~QueryCtx::QueryFlags::HasSourceTerms;
1391 if (hasVariableTerms)
1392 data.
flags |= QueryCtx::QueryFlags::HasVariableTerms;
1394 data.
flags &= ~QueryCtx::QueryFlags::HasVariableTerms;
1396 if (hasSourceTerms || hasVariableTerms)
1399 !hasEntityFilterTerms && data.
sortByFunc ==
nullptr && data.
groupBy == EntityBad && hasCreateSelector)
1405 ? CreateArchetypeMatchKind::DirectStructuralTerms
1406 : CreateArchetypeMatchKind::Vm;
1410 if (!data.
deps.has_dep_flag(DependencyHasSourceTerms) || !data.
deps.has_dep_flag(DependencyHasTraversalTerms))
1419 data.
flags |= QueryCtx::QueryFlags::Complex;
1421 data.
queryMask = build_entity_mask(EntitySpan{idsNoSrc.data(), idsNoSrcCnt});
1422 data.
flags &= ~QueryCtx::QueryFlags::Complex;
1431 isComplex_old != (data.
flags & QueryFlags::Complex) ||
1432 hasSourceTerms_old != (data.
flags & QueryFlags::HasSourceTerms) ||
1433 hasVariableTerms_old != (data.
flags & QueryFlags::HasVariableTerms) ||
1440 createSelectorCnt_old != data.
deps.createSelectorCnt || exclusionCnt_old != data.
deps.exclusionCnt ||
1441 relationCnt_old != data.
deps.relationCnt || sourceEntityCnt_old != data.
deps.sourceEntityCnt ||
1442 sourceTermCnt_old != data.
deps.sourceTermCnt || createSelectors_old != data.
deps.createSelectors ||
1443 exclusions_old != data.
deps.exclusions || relations_old != data.
deps.relations ||
1444 sourceEntities_old != data.
deps.sourceEntities)
1445 data.
flags |= QueryCtx::QueryFlags::Recompile;
1448 GAIA_NODISCARD
static bool
1449 equals_no_handle_assumption(
const QueryCtx& leftCtx,
const QueryCtx& rightCtx)
noexcept {
1451 if (leftCtx.hashLookup != rightCtx.hashLookup)
1454 const auto& left = leftCtx.data;
1455 const auto& right = rightCtx.data;
1456 return left.identity_payload_equal(right);
1459 GAIA_NODISCARD
bool operator==(
const QueryCtx& other)
const noexcept {
1461 GAIA_ASSERT(
q.
handle.id() == QueryIdBad);
1466 return equals_no_handle_assumption(*
this, other);
1469 GAIA_NODISCARD
bool operator!=(
const QueryCtx& other)
const noexcept {
1470 return !operator==(other);
1477 return query_term_less_for_lookup(lhs, rhs);
1483 const uint32_t idsCnt = ctx.data.idsCnt;
1484 const uint32_t changedCnt = ctx.data.changedCnt;
1486 auto& ctxData = ctx.data;
1493 if (ctxData.terms[i].op != QueryOpKind::Or)
1502 ctxData.terms[orIdx].op = QueryOpKind::All;
1509 ctxData.terms.data(), ctxData.terms.data() + ctxData.idsCnt, query_sort_cond{},
1510 [&](uint32_t left, uint32_t right) {
1511 core::swap(ctxData.ids[left], ctxData.ids[right]);
1512 core::swap(ctxData.terms[left], ctxData.terms[right]);
1515 core::swap_bits(ctxData.readWriteMask, left, right);
1516 core::swap_bits(ctxData.as_mask_0, left, right);
1517 core::swap_bits(ctxData.as_mask_1, left, right);
1522 while (i < idsCnt && ctxData.terms[i].op == QueryOpKind::All)
1524 ctxData.firstOr = (uint8_t)i;
1525 while (i < idsCnt && ctxData.terms[i].op == QueryOpKind::Or)
1527 ctxData.firstNot = (uint8_t)i;
1528 while (i < idsCnt && ctxData.terms[i].op == QueryOpKind::Not)
1530 ctxData.firstAny = (uint8_t)i;
1532 ctxData.firstOr = ctxData.firstNot = ctxData.firstAny = 0;
1536 if (changedCnt > 1) {
1537 core::sort(ctxData.changed.data(), ctxData.changed.data() + changedCnt, SortComponentCond{});
1540 GAIA_FOR(changedCnt) {
1541 const auto comp = ctxData.changed[i];
1542 uint32_t compIdx = 0;
1543 while (compIdx < idsCnt && ctxData.ids[compIdx] != comp)
1546 GAIA_ASSERT(compIdx < idsCnt);
1547 ctxData.changedFields[i] = compIdx < idsCnt ? (uint8_t)compIdx : (uint8_t)0xFF;
1553 inline void normalize_cache_src_trav(QueryCtx& ctx) {
1554 auto& ctxData = ctx.data;
1555 if (ctxData.cacheSrcTrav == 0)
1558 bool hasTraversedSourceTerm =
false;
1559 for (
const auto& term: ctxData.terms_view()) {
1560 if (term.src == EntityBad || term.entTrav == EntityBad)
1563 hasTraversedSourceTerm =
true;
1567 if (!hasTraversedSourceTerm)
1568 ctxData.cacheSrcTrav = 0;
1571 inline void calc_lookup_hash(QueryCtx& ctx) {
1572 GAIA_ASSERT(ctx.cc !=
nullptr);
1574 GAIA_ASSERT(ctx.hashLookup.hash == 0);
1576 ctx.hashLookup = ctx.data.calc_lookup_hash();
1586 template <u
int32_t MAX_COMPONENTS>
1587 GAIA_NODISCARD
inline uint32_t comp_idx(
const QueryTerm* pTerms, Entity entity, Entity src) {
1590 GAIA_FOR(MAX_COMPONENTS) {
1591 if (pTerms[i].
id == entity && pTerms[i].src == src)
Array with variable size of elements of type.
Definition darray_impl.h:25
Definition span_impl.h:99
Definition archetype.h:83
Cache for compile-time defined components.
Definition component_cache.h:24
Wrapper for two types forming a relationship pair. Depending on what types are used to form a pair it...
Definition id.h:224
Same API as ser_buffer_binary, but backed by fully dynamic storage.
Definition ser_buffer_binary.h:157
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
constexpr uint32_t BadIndex
Sentinel index value returned by helpers when a lookup fails.
Definition utility.h:20
Definition query_common.h:117
Hashmap lookup structure used for Entity.
Definition id.h:468
Explicit component/entity access declarations used for scheduling decisions.
Definition query_common.h:388
GAIA_NODISCARD QueryAccess access(Entity entity) const
Returns explicitly declared access for an id.
Definition query_common.h:435
uint8_t readCnt
Number of valid entries in reads.
Definition query_common.h:394
GAIA_NODISCARD std::span< const Entity > writes_view() const
Returns the explicitly declared write ids.
Definition query_common.h:406
void add_read(Entity entity)
Declares that an id is read.
Definition query_common.h:412
cnt::sarray< Entity, MAX_ITEMS_IN_QUERY > reads
Component/entity ids read by the callback outside the query terms.
Definition query_common.h:390
GAIA_NODISCARD std::span< const Entity > reads_view() const
Returns the explicitly declared read ids.
Definition query_common.h:400
uint8_t writeCnt
Number of valid entries in writes.
Definition query_common.h:396
cnt::sarray< Entity, MAX_ITEMS_IN_QUERY > writes
Component/entity ids written by the callback outside the query terms.
Definition query_common.h:392
void add_write(Entity entity)
Declares that an id is written.
Definition query_common.h:423
Incremental query-matching cursor for one entity-to-archetype lookup bucket.
Definition query_common.h:104
uint32_t index
Number of bucket records that were already matched at revision.
Definition query_common.h:106
uint32_t revision
Lookup-bucket revision associated with index.
Definition query_common.h:108
Definition query_common.h:653
Definition query_common.h:719
QueryEntityArray changed
Canonicalized changed-filter ids reused by hash/equality for shared query dedup.
Definition query_common.h:723
cnt::sarray< QueryTerm, MAX_ITEMS_IN_QUERY > lookupTerms
Canonicalized lookup terms reused by hash/equality for shared query dedup.
Definition query_common.h:721
QueryEntityArray groupDeps
Canonicalized group dependency ids reused by hash/equality for shared query dedup.
Definition query_common.h:725
Definition query_common.h:652
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:770
QueryEntityArray groupDeps
Explicit grouping invalidation dependencies for custom group_by callbacks.
Definition query_common.h:743
Entity sortBy
Entity to sort the archetypes by. EntityBad for no sorting.
Definition query_common.h:745
TGroupByFunc groupByFunc
Function to use to perform the grouping.
Definition query_common.h:751
GAIA_NODISCARD DynamicCacheKind calc_dynamic_cache_kind() const
Returns the dynamic-cache dependency shape derived from cache policy and dependencies.
Definition query_common.h:876
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:756
Entity groupBy
Entity to group the archetypes by. EntityBad for no grouping.
Definition query_common.h:749
bool hasOnlyDirectOrTerms
True when the query contains only direct OR/NOT terms and at least one OR term.
Definition query_common.h:784
void add_group_dep(Entity relation)
Adds a declared grouping invalidation dependency.
Definition query_common.h:846
cnt::sarray< uint8_t, MAX_ITEMS_IN_QUERY > changedFields
Query term index for each changed-filter component after query canonicalization.
Definition query_common.h:741
QueryEntityArray ids
Array of queried ids.
Definition query_common.h:729
GAIA_NODISCARD QueryLookupHash::Type hash_lookup_key_payload() const
Returns the hash contribution from canonical lookup-key payload arrays.
Definition query_common.h:982
GAIA_NODISCARD bool uses_src_trav_snapshot() const
Returns whether reusable dynamic-cache checks use a traversed source closure snapshot.
Definition query_common.h:907
GAIA_NODISCARD bool has_sort_payload() const
Returns true when sort identity payload is active.
Definition query_common.h:1048
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:759
bool canDirectEntitySeedEvalShape
True when the query shape is eligible for direct entity seed evaluation.
Definition query_common.h:782
uint8_t firstOr
First OR record in pairs/ids/ops.
Definition query_common.h:765
uint16_t cacheSrcTrav
Maximum allowed size of an explicitly cached traversed-source lookup closure.
Definition query_common.h:774
GAIA_NODISCARD QueryLookupHash::Type hash_sort_payload() const
Returns the hash contribution from sort identity payload.
Definition query_common.h:1053
QueryMask queryMask
Component mask used for faster matching of simple queries.
Definition query_common.h:753
uint8_t firstAny
First ANY record in pairs/ids/ops.
Definition query_common.h:763
GAIA_NODISCARD std::span< QueryTerm > lookup_terms_view_mut()
Returns mutable canonicalized lookup terms used by shared query deduplication.
Definition query_common.h:821
GAIA_NODISCARD bool identity_payload_equal(const Data &other) const
Returns true when the shared query identity payload matches another query context payload.
Definition query_common.h:1061
GAIA_NODISCARD std::span< const Entity > changed_lookup_view() const
Returns canonicalized changed-filter lookup ids used by shared query deduplication.
Definition query_common.h:826
void refresh_lookup_keys()
Refreshes canonical lookup arrays used by shared query deduplication.
Definition query_common.h:940
GAIA_NODISCARD std::span< const QueryTerm > lookup_terms_view() const
Returns canonicalized lookup terms used by shared query deduplication.
Definition query_common.h:816
QueryArchetypeCacheIndexMap lastMatchedArchetypeIdx_All
Index of the last checked archetype in the component-to-archetype map.
Definition query_common.h:733
CreateArchetypeMatchKind createArchetypeMatchKind
Create-time archetype matcher derived from query shape.
Definition query_common.h:792
Entity directTargetEvalId
Term id used by the specialized direct-target evaluation shape.
Definition query_common.h:778
void add_group_deps()
Adds all grouping invalidation relations to the dependency set.
Definition query_common.h:856
GAIA_NODISCARD std::span< const uint8_t > changed_fields_view() const
Returns query-term indices matching changed-filter components.
Definition query_common.h:807
GAIA_NODISCARD QueryLookupHash calc_lookup_hash() const
Returns the finalized lookup hash for shared query identity.
Definition query_common.h:1097
GAIA_NODISCARD bool sort_payload_equal(const Data &other) const
Returns true when the sort identity payload matches another query context payload.
Definition query_common.h:1043
GAIA_NODISCARD bool uses_direct_src_version_tracking() const
Returns whether reusable dynamic-cache checks use direct source entity archetype versions.
Definition query_common.h:901
GAIA_NODISCARD std::span< const Entity > group_deps_lookup_view() const
Returns canonicalized group dependency lookup ids used by shared query deduplication.
Definition query_common.h:836
DynamicCacheKind dynamicCacheKind
Dynamic-cache dependency shape derived from compiled query metadata.
Definition query_common.h:794
Dependencies deps
Explicit dependency metadata derived from query shape.
Definition query_common.h:788
GAIA_NODISCARD std::span< Entity > group_deps_lookup_view_mut()
Returns mutable canonicalized group dependency lookup ids used by shared query deduplication.
Definition query_common.h:841
TSortByFunc sortByFunc
Function to use to perform sorting.
Definition query_common.h:747
uint16_t flags
Query flags.
Definition query_common.h:772
bool canDirectTargetEval
True when the query can evaluate concrete target entities directly.
Definition query_common.h:780
GAIA_NODISCARD std::span< Entity > changed_lookup_view_mut()
Returns mutable canonicalized changed-filter lookup ids used by shared query deduplication.
Definition query_common.h:831
uint8_t firstNot
First NOT record in pairs/ids/ops.
Definition query_common.h:761
CachePolicy cachePolicy
Cache maintenance policy derived from query shape.
Definition query_common.h:790
GAIA_NODISCARD bool calc_can_reuse_dynamic_cache() const
Returns whether the current query shape can reuse dynamic-cache results.
Definition query_common.h:913
uint8_t groupDepCnt
Number of defined group dependencies.
Definition query_common.h:767
GAIA_NODISCARD bool grouping_payload_equal(const Data &other) const
Returns true when grouping identity payload matches another query context payload.
Definition query_common.h:1034
QueryEntityArray changed
Array of filtered components.
Definition query_common.h:739
GAIA_NODISCARD bool lookup_keys_equal(const Data &other) const
Returns true when canonical lookup arrays match another query context payload.
Definition query_common.h:950
GAIA_NODISCARD QueryLookupHash::Type hash_identity_payload() const
Returns the hash contribution from the full shared query identity payload.
Definition query_common.h:1089
cnt::sarray< QueryTerm, MAX_ITEMS_IN_QUERY > terms
Array of terms.
Definition query_common.h:731
GAIA_NODISCARD QueryLookupHash::Type hash_grouping_payload() const
Returns the hash contribution from grouping identity payload.
Definition query_common.h:1080
LookupIdentity lookupIdentity
Cold canonical shared-query identity payload.
Definition query_common.h:796
DirectTargetEvalKind directTargetEvalKind
Specialized direct-target evaluation shape for single-term queries.
Definition query_common.h:776
bool canReuseDynamicCache
True when a dynamic cache can be reused by checking tracked runtime inputs.
Definition query_common.h:786
Definition query_common.h:564
ComponentCache * cc
Component cache.
Definition query_common.h:568
QueryIdentity q
Query identity.
Definition query_common.h:572
QueryLookupHash hashLookup
Lookup hash for this query.
Definition query_common.h:570
DynamicCacheKind
Dynamic-cache dependency shape derived from compiled query metadata.
Definition query_common.h:613
@ Variable
Dynamic cache tracks runtime variable bindings only.
@ TraversedSource
Dynamic cache tracks a traversed source closure.
@ DirectSource
Dynamic cache tracks concrete source entity archetype versions.
@ Mixed
Dynamic cache tracks more than one dependency family.
@ None
Query does not use dynamic-cache validation.
@ RelationOnly
Dynamic cache is invalidated by relation version dependencies only.
Hashmap lookup structure used for Entity.
Definition query_common.h:193
Definition query_common.h:144
Definition query_common.h:550
QueryHandle handle
Query id.
Definition query_common.h:552
QueryId serId
Serialization id.
Definition query_common.h:554
Additional options for query terms. This can be used to configure source lookup, traversal and access...
Definition query_common.h:271
uint8_t travDepth
Maximum number of traversal steps. 0 means unlimited traversal depth (bounded internally,...
Definition query_common.h:282
Entity entSrc
Source entity to query from.
Definition query_common.h:275
Entity entTrav
Optional traversal relation used for source lookup.
Definition query_common.h:277
QueryAccess access
Access mode for the term. When None, typed query terms infer read/write access from template mutabili...
Definition query_common.h:285
QueryMatchKind matchKind
Match semantics for terms with special meaning, such as Pair(Is, X).
Definition query_common.h:287
QueryTravKind travKind
Source traversal filter.
Definition query_common.h:279
Internal representation of QueryInput.
Definition query_common.h:445
Entity id
Queried id.
Definition query_common.h:447
Archetype * srcArchetype
Archetype of the src entity.
Definition query_common.h:459
uint8_t travDepth
Maximum number of traversal steps.
Definition query_common.h:455
QueryMatchKind matchKind
Match semantics for this term.
Definition query_common.h:457
uint8_t fieldIndex
Stable execution field index matching the user-defined query field order.
Definition query_common.h:463
Entity entTrav
Optional traversal relation for source lookups.
Definition query_common.h:451
QueryOpKind op
Operation to perform with the term.
Definition query_common.h:461
Entity src
Source of where the queried id is looked up at.
Definition query_common.h:449
QueryTravKind travKind
Source traversal filter.
Definition query_common.h:453
Definition query_common.h:129
Functor for sorting terms in a query before compilation.
Definition query_common.h:1475