2#include "gaia/config/config.h"
4#include "gaia/cnt/darray.h"
5#include "gaia/cnt/ilist.h"
6#include "gaia/config/profiler.h"
7#include "gaia/core/hashing_policy.h"
8#include "gaia/core/utility.h"
9#include "gaia/ecs/api.h"
10#include "gaia/ecs/archetype.h"
11#include "gaia/ecs/archetype_common.h"
12#include "gaia/ecs/component.h"
13#include "gaia/ecs/component_cache.h"
14#include "gaia/ecs/id.h"
15#include "gaia/ecs/query_common.h"
16#include "gaia/ecs/query_match_stamps.h"
17#include "gaia/ecs/vm.h"
18#include "gaia/mem/mem_utils.h"
19#include "gaia/mem/smallblock_allocator.h"
26 uint32_t world_version(
const World& world);
27 Entity world_query_first_inherited_owner(
const World& world,
const Archetype& archetype, Entity term);
28 const void* world_query_inherited_arg_data_const_ptr(
const World& world, Entity owner, Entity
id);
30 using EntityToArchetypeMap = cnt::map<EntityLookupKey, ComponentIndexEntryArray>;
91 GAIA_NODISCARD QueryMatchScratch& query_match_scratch_acquire(World& world);
92 void query_match_scratch_release(World& world,
bool keepStamps);
119 uint32_t archetypeIdx;
131 struct SrcTravSnapshotItem {
132 Entity entity = EntityBad;
134 uint32_t sourceVersion = 0;
136 GAIA_NODISCARD
bool operator==(
const SrcTravSnapshotItem& other)
const {
137 return entity == other.entity && sourceVersion == other.sourceVersion;
140 GAIA_NODISCARD
bool operator!=(
const SrcTravSnapshotItem& other)
const {
141 return !operator==(other);
162 enum DirtyFlags : uint8_t { Clean = 0x00, Seed = 0x01, Result = 0x02, All = Seed | Result };
165 cnt::set<const Archetype*> seedArchetypeSet;
166 CArchetypeDArray seedArchetypeCache;
170 cnt::set<const Archetype*> archetypeSet;
172 CArchetypeDArray archetypeCache;
273 GroupedPayload grouped;
275 NonTrivialPayload nonTrivial;
285 const auto cnt = (uint32_t)relations.size();
296 const auto cnt = (uint32_t)relations.size();
309 const auto cnt = (uint32_t)sourceEntities.size();
320 const auto cnt = (uint32_t)sourceEntities.size();
346 const auto cnt = (uint32_t)
snapshot.size();
349 if (item.sourceVersion != world_entity_archetype_version(
world, item.entity))
358 if (items.size() !=
snapshot.size())
361 const auto cnt = (uint32_t)
snapshot.size();
400 if (runtimeBindingMask == 0)
403 GAIA_FOR(MaxVarCnt) {
404 const auto bit = (uint8_t(1) << i);
405 if ((runtimeBindingMask & bit) == 0)
408 if (
bindings[i] != runtimeBindings[i])
439 DynamicCacheState dynamic;
442 ArchetypeId lastArchetypeId{};
445 uint32_t resultCacheRevision = 1;
447 uint8_t dirtyFlags = DirtyFlags::All;
450 void clear_seed_cache() {
451 seedArchetypeSet = {};
452 seedArchetypeCache = {};
456 void clear_result_cache() {
465 void clear_transient_result_cache() {
466 archetypeCache.clear();
467 exec.clear_transient();
468 grouped.clear_transient();
469 nonTrivial.clear_transient();
475 clear_result_cache();
481 dynamic.clear_input_snapshots();
483 dirtyFlags = DirtyFlags::All;
487 void invalidate_seed() {
488 dirtyFlags = (uint8_t)(dirtyFlags | DirtyFlags::Seed | DirtyFlags::Result);
492 void invalidate_result() {
493 dirtyFlags = (uint8_t)(dirtyFlags | DirtyFlags::Result);
497 void invalidate_all() {
498 dirtyFlags = DirtyFlags::All;
502 GAIA_NODISCARD
bool seed_dirty()
const {
503 return (dirtyFlags & DirtyFlags::Seed) != 0;
507 GAIA_NODISCARD
bool result_dirty()
const {
508 return (dirtyFlags & DirtyFlags::Result) != 0;
512 GAIA_NODISCARD
bool needs_refresh()
const {
513 return seed_dirty() || result_dirty();
518 dirtyFlags = DirtyFlags::Clean;
523#if GAIA_ECS_TEST_HOOKS
525 uint32_t m_testMatchPassCount = 0;
531 enum QueryCmdType : uint8_t { ALL, OR, NOT };
535 void reset_matching_cache(
bool trackMembershipChange) {
536 if (trackMembershipChange && !m_state.archetypeCache.empty())
537 mark_result_cache_membership_changed();
541 auto& ctxData = m_plan.ctx.data;
542 ctxData.lastMatchedArchetypeIdx_All = {};
543 ctxData.lastMatchedArchetypeIdx_Or = {};
544 ctxData.lastMatchedArchetypeIdx_Not = {};
548 void clear_result_cache() {
549 m_state.clear_result_cache();
554 void invalidate_result_barriers() {
555 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
556 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
561 void mark_result_cache_membership_changed() {
562 invalidate_result_barriers();
563 ++m_state.resultCacheRevision;
564 if (m_state.resultCacheRevision != 0)
568 m_state.resultCacheRevision = 1;
572 GAIA_NODISCARD
bool has_dyn_terms()
const {
573 return m_plan.ctx.data.cachePolicy == QueryCtx::CachePolicy::Dynamic;
577 GAIA_NODISCARD
bool can_reuse_dyn_cache()
const {
578 return m_plan.ctx.data.canReuseDynamicCache;
582 GAIA_NODISCARD
bool uses_direct_src_version_tracking()
const {
583 return m_plan.ctx.data.uses_direct_src_version_tracking();
587 GAIA_NODISCARD
bool uses_src_trav_snapshot()
const {
588 return m_plan.ctx.data.uses_src_trav_snapshot();
592 GAIA_NODISCARD
bool dyn_rel_versions_changed()
const {
593 return m_state.dynamic.relation.changed(*
world(), m_plan.ctx.data.deps.relations_view());
597 GAIA_NODISCARD
bool dyn_var_bindings_changed(
598 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask)
const {
599 return m_state.dynamic.variable.changed(runtimeVarBindings, runtimeVarBindingMask);
603 GAIA_NODISCARD
bool direct_src_versions_changed()
const {
604 return m_state.dynamic.directSource.changed(*
world(), m_plan.ctx.data.deps.src_entities_view());
610 template <
typename Func>
611 void each_reusable_src_entity(Func&& func)
const {
612 const auto terms = m_plan.ctx.data.terms_view();
613 const auto cnt = (uint32_t)terms.size();
615 const auto& term = terms[i];
616 if (term.src == EntityBad || is_variable(term.src))
619 (void)vm::detail::each_lookup_src(*
world(), term, term.src, [&](Entity source) {
627 GAIA_NODISCARD
bool build_src_trav_snapshot(cnt::darray<SrcTravSnapshotItem>& items)
const {
628 const auto maxItems = (uint32_t)m_plan.ctx.data.cacheSrcTrav;
633 bool overflowed =
false;
634 each_reusable_src_entity([&](Entity source) {
635 if (items.size() >= maxItems) {
639 items.push_back({source, world_entity_archetype_version(*world(), source)});
648 GAIA_NODISCARD
bool traversed_src_versions_changed()
const {
649 return m_state.dynamic.traversedSource.versions_changed(*
world());
653 GAIA_NODISCARD
bool traversed_src_inputs_changed(
bool relationVersionsChanged) {
654 if (m_state.dynamic.traversedSource.is_overflowed())
657 if (!relationVersionsChanged)
658 return traversed_src_versions_changed();
660 cnt::darray<SrcTravSnapshotItem> scratch;
661 if (!build_src_trav_snapshot(scratch))
664 return m_state.dynamic.traversedSource.changed(scratch);
668 GAIA_NODISCARD
bool mixed_dyn_inputs_changed(
669 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
670 const auto& deps = m_plan.ctx.data.deps;
671 if (deps.has_dep_flag(QueryCtx::DependencyHasVariableTerms) &&
672 dyn_var_bindings_changed(runtimeVarBindings, runtimeVarBindingMask))
675 const bool relationVersionsChanged = dyn_rel_versions_changed();
676 const bool hasSourceTerms = deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms);
677 const bool hasTraversalTerms = deps.has_dep_flag(QueryCtx::DependencyHasTraversalTerms);
678 if (relationVersionsChanged && !(hasSourceTerms && hasTraversalTerms))
682 return relationVersionsChanged;
684 if (m_state.dynamic.traversedSource.is_overflowed())
687 if (!hasTraversalTerms)
688 return direct_src_versions_changed();
690 return traversed_src_inputs_changed(relationVersionsChanged);
695 dyn_inputs_changed(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
696 if (!can_reuse_dyn_cache())
699 switch (m_plan.ctx.data.dynamicCacheKind) {
703 return dyn_rel_versions_changed();
705 return direct_src_versions_changed();
707 return traversed_src_inputs_changed(dyn_rel_versions_changed());
709 return dyn_var_bindings_changed(runtimeVarBindings, runtimeVarBindingMask);
711 return mixed_dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask);
719 void snapshot_dyn_rel_inputs() {
720 m_state.dynamic.relation.snapshot(*
world(), m_plan.ctx.data.deps.relations_view());
724 void snapshot_dyn_direct_src_inputs() {
725 m_state.dynamic.directSource.snapshot(*
world(), m_plan.ctx.data.deps.src_entities_view());
729 void snapshot_dyn_traversed_src_inputs() {
730 cnt::darray<SrcTravSnapshotItem> scratch;
731 if (build_src_trav_snapshot(scratch))
732 m_state.dynamic.traversedSource.capture(scratch);
734 m_state.dynamic.traversedSource.mark_overflowed();
739 snapshot_dyn_var_inputs(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
740 m_state.dynamic.variable.snapshot(runtimeVarBindings, runtimeVarBindingMask);
745 snapshot_dyn_inputs(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
746 if (!can_reuse_dyn_cache())
749 m_state.dynamic.clear_input_snapshots();
751 switch (m_plan.ctx.data.dynamicCacheKind) {
755 snapshot_dyn_rel_inputs();
758 snapshot_dyn_direct_src_inputs();
761 snapshot_dyn_rel_inputs();
762 snapshot_dyn_traversed_src_inputs();
765 snapshot_dyn_var_inputs(runtimeVarBindings, runtimeVarBindingMask);
768 const auto& deps = m_plan.ctx.data.deps;
769 snapshot_dyn_rel_inputs();
770 if (deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms)) {
771 if (deps.has_dep_flag(QueryCtx::DependencyHasTraversalTerms))
772 snapshot_dyn_traversed_src_inputs();
774 snapshot_dyn_direct_src_inputs();
776 if (deps.has_dep_flag(QueryCtx::DependencyHasVariableTerms))
777 snapshot_dyn_var_inputs(runtimeVarBindings, runtimeVarBindingMask);
788 template <
typename TType>
789 GAIA_NODISCARD
bool has_inter([[maybe_unused]] QueryOpKind op,
bool isReadWrite)
const {
790 using T = core::raw_t<TType>;
792 if constexpr (std::is_same_v<T, Entity>) {
794 GAIA_ASSERT(!isReadWrite);
800 if constexpr (is_pair<T>::value) {
801 const auto rel = m_plan.ctx.cc->get<
typename T::rel>().entity;
802 const auto tgt = m_plan.ctx.cc->get<
typename T::tgt>().entity;
803 id = (Entity)Pair(rel, tgt);
805 id = m_plan.ctx.cc->get<T>().entity;
808 const auto& ctxData = m_plan.ctx.data;
809 const auto compIdx = comp_idx<MAX_ITEMS_IN_QUERY>(ctxData.terms.data(),
id, EntityBad);
811 if (op != ctxData.terms[compIdx].op)
815 const uint32_t maskRW = (uint32_t)ctxData.readWriteMask & (1U << compIdx);
816 const uint32_t maskXX = (uint32_t)isReadWrite << compIdx;
817 return maskRW == maskXX;
824 template <
typename T>
825 GAIA_NODISCARD
bool has_inter(QueryOpKind op)
const {
827 constexpr bool isReadWrite = core::is_mut_v<T>;
828 return has_inter<T>(op, isReadWrite);
835 GAIA_ASSERT(m_refs != 0);
840 GAIA_ASSERT(m_refs > 0);
852 m_plan.ctx.w =
world;
857 reset_matching_cache(
true);
865 m_state.invalidate_result();
866 invalidate_result_barriers();
869 m_state.invalidate_seed();
872 m_state.invalidate_all();
889 if (m_plan.ctx.data.sortByFunc !=
nullptr)
890 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortEntities;
908 info.m_plan.ctx = GAIA_MOV(
ctx);
909 info.m_plan.ctx.q.handle = {id, 0};
912 info.
compile(entityToArchetypeMap, allArchetypes);
923 auto& queryCtx = *pCreationCtx->pQueryCtx;
933 info.m_plan.ctx = GAIA_MOV(queryCtx);
934 info.m_plan.ctx.q.handle = {
idx,
gen};
937 info.
compile(entityToArchetypeMap, pCreationCtx->allArchetypes);
949 GAIA_PROF_SCOPE(queryinfo::compile);
952 m_plan.vm.compile(entityToArchetypeMap, allArchetypes, m_plan.ctx);
957 GAIA_PROF_SCOPE(queryinfo::recompile);
960 m_plan.vm.create_opcodes(m_plan.ctx);
965 return m_plan.ctx.data.cachePolicy;
970 return m_plan.ctx.data.groupBy != EntityBad;
975 return m_plan.ctx.data.sortByFunc !=
nullptr;
980 return m_state.resultCacheRevision;
986 return m_plan.vm.is_compiled() &&
cache_policy() == QueryCtx::CachePolicy::Immediate &&
987 !m_state.needs_refresh();
992 return m_plan.ctx.data.createArchetypeMatchKind == QueryCtx::CreateArchetypeMatchKind::DirectStructuralTerms;
997 const auto& ctxData = m_plan.ctx.data;
998 return (ctxData.as_mask_0 + ctxData.as_mask_1) != 0;
1001 GAIA_NODISCARD
bool operator==(
const QueryCtx& other)
const {
1002 return m_plan.ctx == other;
1005 GAIA_NODISCARD
bool operator!=(
const QueryCtx& other)
const {
1006 return m_plan.ctx != other;
1020 query_match_scratch_release(world, keepStamps);
1034 template <
typename ArchetypeLookup>
1039 auto& ctxData = m_plan.ctx.data;
1042 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1046 if (!m_plan.vm.is_compiled())
1049 const bool hasDynamicTerms = has_dyn_terms();
1050 const bool canReuseDynamicCache = can_reuse_dyn_cache();
1051 const bool refreshDynamicCache =
1052 hasDynamicTerms && (!canReuseDynamicCache || m_state.needs_refresh() ||
1053 dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask));
1054 bool compareDynamicMembership =
false;
1057 if (refreshDynamicCache) {
1058 compareDynamicMembership = !m_state.archetypeCache.empty();
1059 if (compareDynamicMembership) {
1061 pMatchScratch = &query_match_scratch_acquire(w);
1065 reset_matching_cache(!compareDynamicMembership);
1066 }
else if (m_state.seed_dirty()) {
1067 reset_matching_cache(
true);
1068 }
else if (m_state.result_dirty()) {
1070 if (m_state.lastArchetypeId == archetypeLastId) {
1073 m_state.clear_dirty();
1079 GAIA_ASSERT(archetypeLastId >= m_state.lastArchetypeId);
1080 if (!m_state.needs_refresh() && m_state.lastArchetypeId == archetypeLastId &&
1081 (!hasDynamicTerms || canReuseDynamicCache)) {
1087 m_state.lastArchetypeId = archetypeLastId;
1089 GAIA_PROF_SCOPE(queryinfo::match);
1092 auto& matchScratch = pMatchScratch !=
nullptr ? *pMatchScratch : query_match_scratch_acquire(w);
1099 ctx.allArchetypes = allArchetypes;
1100 if constexpr (std::is_same_v<ArchetypeLookup, EntityToArchetypeMap>) {
1101 GAIA_ASSERT(pEntityToArchetypeMapVersions !=
nullptr);
1102 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap, *pEntityToArchetypeMapVersions);
1104 (void)pEntityToArchetypeMapVersions;
1105 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap);
1108 ctx.pMatchesArr = &matchScratch.matchesArr;
1109 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1110 ctx.matchesVersion = matchScratch.next_match_version();
1111 ctx.pLastMatchedArchetypeIdx_All = &ctxData.lastMatchedArchetypeIdx_All;
1112 ctx.pLastMatchedArchetypeIdx_Or = &ctxData.lastMatchedArchetypeIdx_Or;
1113 ctx.pLastMatchedArchetypeIdx_Not = &ctxData.lastMatchedArchetypeIdx_Not;
1114 ctx.queryMask = ctxData.queryMask;
1115 ctx.as_mask_0 = ctxData.as_mask_0;
1116 ctx.as_mask_1 = ctxData.as_mask_1;
1117 ctx.flags = ctxData.flags;
1118 ctx.varBindings = runtimeVarBindings;
1119 ctx.varBindingMask = runtimeVarBindingMask;
1122#if GAIA_ECS_TEST_HOOKS
1123 ++m_testMatchPassCount;
1125 m_plan.vm.exec(
ctx);
1128 const bool trackMembershipChangeOnAdd = !compareDynamicMembership;
1129 for (
const auto* pArchetype: *
ctx.pMatchesArr) {
1130 if (hasDynamicTerms) {
1138 if (compareDynamicMembership) {
1140 mark_result_cache_membership_changed();
1147 snapshot_dyn_inputs(runtimeVarBindings, runtimeVarBindingMask);
1148 m_state.clear_dirty();
1161 auto& ctxData = m_plan.ctx.data;
1164 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1168 if (!m_plan.vm.is_compiled())
1171 const bool hasDynamicTerms = has_dyn_terms();
1172 const bool canReuseDynamicCache = can_reuse_dyn_cache();
1173 if ((hasDynamicTerms && (!canReuseDynamicCache || m_state.needs_refresh() ||
1174 dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask))) ||
1175 m_state.seed_dirty()) {
1177 reset_matching_cache(
true);
1178 }
else if (m_state.result_dirty()) {
1182 GAIA_PROF_SCOPE(queryinfo::match1);
1185 auto& matchScratch = query_match_scratch_acquire(w);
1191 ctx.targetEntities = targetEntities;
1192 const auto* pArchetype = &archetype;
1194 ctx.archetypeLookup = {};
1195 ctx.pMatchesArr = &matchScratch.matchesArr;
1196 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1197 ctx.matchesVersion = matchScratch.next_match_version();
1198 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1199 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1200 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1201 ctx.queryMask = ctxData.queryMask;
1202 ctx.as_mask_0 = ctxData.as_mask_0;
1203 ctx.as_mask_1 = ctxData.as_mask_1;
1204 ctx.flags = ctxData.flags;
1205 ctx.varBindings = runtimeVarBindings;
1206 ctx.varBindingMask = runtimeVarBindingMask;
1209#if GAIA_ECS_TEST_HOOKS
1210 ++m_testMatchPassCount;
1212 m_plan.vm.exec(
ctx);
1213 const bool matched = !
ctx.pMatchesArr->empty();
1216 for (
const auto* pArch: *
ctx.pMatchesArr) {
1217 if (hasDynamicTerms) {
1224 snapshot_dyn_inputs(runtimeVarBindings, runtimeVarBindingMask);
1225 m_state.clear_dirty();
1229 void ensure_matches(
1234 entityToArchetypeMap, allArchetypes, &entityToArchetypeMapVersions, archetypeLastId, runtimeVarBindings,
1235 runtimeVarBindingMask);
1238 void ensure_matches_transient(
1240 const EntityToArchetypeVersionMap& entityToArchetypeMapVersions,
1242 auto& ctxData = m_plan.ctx.data;
1244 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1247 if (!m_plan.vm.is_compiled())
1250 m_state.clear_transient_result_cache();
1253 auto& matchScratch = query_match_scratch_acquire(w);
1254 CleanUpTmpArchetypeMatches autoCleanup(w,
true);
1256 vm::MatchingCtx
ctx{};
1258 ctx.allArchetypes = allArchetypes;
1259 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap, entityToArchetypeMapVersions);
1260 ctx.pMatchesArr = &matchScratch.matchesArr;
1261 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1262 ctx.matchesVersion = matchScratch.next_match_version();
1263 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1264 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1265 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1266 ctx.queryMask = ctxData.queryMask;
1267 ctx.as_mask_0 = ctxData.as_mask_0;
1268 ctx.as_mask_1 = ctxData.as_mask_1;
1269 ctx.flags = ctxData.flags;
1270 ctx.varBindings = runtimeVarBindings;
1271 ctx.varBindingMask = runtimeVarBindingMask;
1273 m_plan.vm.exec(
ctx);
1275 m_state.archetypeCache.reserve(
ctx.pMatchesArr->size());
1276 if (ctxData.groupBy != EntityBad)
1277 m_state.grouped.archetypeGroupIds.reserve(
ctx.pMatchesArr->size());
1278 for (
const auto* pArchetype: *
ctx.pMatchesArr)
1285 bool ensure_matches_one(
1286 const Archetype& archetype, EntitySpan targetEntities,
1287 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
1288 return match_one(archetype, targetEntities, runtimeVarBindings, runtimeVarBindingMask);
1291 bool ensure_matches_one_transient(
1292 const Archetype& archetype, EntitySpan targetEntities,
1293 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
1294 auto& ctxData = m_plan.ctx.data;
1296 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1299 if (!m_plan.vm.is_compiled())
1302 m_state.clear_transient_result_cache();
1305 auto& matchScratch = query_match_scratch_acquire(w);
1306 CleanUpTmpArchetypeMatches autoCleanup(w,
true);
1308 vm::MatchingCtx
ctx{};
1310 ctx.targetEntities = targetEntities;
1311 const auto* pArchetype = &archetype;
1312 ctx.allArchetypes =
std::span((
const Archetype**)&pArchetype, 1);
1313 ctx.archetypeLookup = {};
1314 ctx.pMatchesArr = &matchScratch.matchesArr;
1315 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1316 ctx.matchesVersion = matchScratch.next_match_version();
1317 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1318 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1319 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1320 ctx.queryMask = ctxData.queryMask;
1321 ctx.as_mask_0 = ctxData.as_mask_0;
1322 ctx.as_mask_1 = ctxData.as_mask_1;
1323 ctx.flags = ctxData.flags;
1324 ctx.varBindings = runtimeVarBindings;
1325 ctx.varBindingMask = runtimeVarBindingMask;
1327 m_plan.vm.exec(
ctx);
1328 const bool matched = !
ctx.pMatchesArr->empty();
1330 m_state.archetypeCache.reserve(
ctx.pMatchesArr->size());
1331 if (ctxData.groupBy != EntityBad)
1332 m_state.grouped.archetypeGroupIds.reserve(
ctx.pMatchesArr->size());
1333 for (
const auto* pArch: *
ctx.pMatchesArr)
1346 auto& ctxData = m_plan.ctx.data;
1349 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1355 const bool hadMatchBefore = !assumeNew && m_state.archetypeSet.contains(&archetype);
1358 bool hasOrTerms =
false;
1359 bool matchedOrTerm =
false;
1360 for (
const auto& term: ctxData.terms_view()) {
1361 if (term.id == matchedSelector) {
1362 if (term.op == QueryOpKind::Or)
1363 matchedOrTerm =
true;
1367 const bool present = usesIs ? vm::detail::match_single_id_on_archetype(*
world(), archetype, term.id)
1368 : world_component_index_match_count(*
world(), archetype, term.id) != 0;
1369 if (term.op == QueryOpKind::Or) {
1371 matchedOrTerm |= present;
1374 if (term.op == QueryOpKind::Any)
1377 const bool matched = term.op == QueryOpKind::Not ? !present : present;
1381 if (hasOrTerms && !matchedOrTerm)
1396 auto addLookupUnique = [&](
Entity key, uint16_t compIdx, uint16_t matchCount) {
1398 const auto itLookup =
1399 core::find_if(singleArchetypeLookup.begin(), singleArchetypeLookup.end(), [&](
const auto& item) {
1400 return item.matches(keyLookup);
1402 if (itLookup != singleArchetypeLookup.end()) {
1403 auto& entry = itLookup->entry;
1404 entry.matchCount = (uint16_t)(entry.matchCount + matchCount);
1405 if (compIdx != ComponentIndexBad)
1406 entry.compIdx = compIdx;
1409 singleArchetypeLookup.push_back(
1413 auto archetypeIds = archetype.ids_view();
1414 const auto cntIds = (uint32_t)archetypeIds.size();
1416 const auto entity = archetypeIds[i];
1417 singleArchetypeLookup.push_back(
1426 const auto relKind = entity.entity() ? EntityKind::EK_Uni : EntityKind::EK_Gen;
1427 const auto rel =
Entity((EntityId)entity.id(), 0,
false,
false, relKind);
1428 const auto tgt =
Entity((EntityId)entity.gen(), 0,
false,
false, entity.kind());
1429 addLookupUnique(
Pair(
All, tgt), ComponentIndexBad, 1);
1430 addLookupUnique(
Pair(rel,
All), ComponentIndexBad, 1);
1431 addLookupUnique(
Pair(
All,
All), ComponentIndexBad, 1);
1434 auto lastMatchedArchetypeIdx_All = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_All);
1435 auto lastMatchedArchetypeIdx_Or = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Or);
1436 auto lastMatchedArchetypeIdx_Not = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Not);
1437 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_All.empty());
1438 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Or.empty());
1439 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Not.empty());
1441 const auto* pArchetype = &archetype;
1444 singleArchetypeLookup,
std::span((
const Archetype**)&pArchetype, 1),
nullptr, archetype.id(),
1445 noRuntimeVarBindings, 0);
1446 ctxData.lastMatchedArchetypeIdx_All = GAIA_MOV(lastMatchedArchetypeIdx_All);
1447 ctxData.lastMatchedArchetypeIdx_Or = GAIA_MOV(lastMatchedArchetypeIdx_Or);
1448 ctxData.lastMatchedArchetypeIdx_Not = GAIA_MOV(lastMatchedArchetypeIdx_Not);
1449 const bool matched = assumeNew ? m_state.archetypeSet.contains(&archetype)
1450 : !hadMatchBefore && m_state.archetypeSet.contains(&archetype);
1463 GAIA_PROF_SCOPE(queryinfo::calc_sort_data);
1465 m_state.nonTrivial.archetypeSortData.clear();
1483 uint32_t chunkIdx = 0;
1487 auto& archetypes = m_state.archetypeCache;
1492 uint32_t currArchetypeIdx = (uint32_t)-1;
1493 Chunk* pCurrentChunk =
nullptr;
1494 uint16_t currentStartRow = 0;
1495 uint16_t currentRow = 0;
1497 const void* pDataMin =
nullptr;
1498 const void* pDataCurr =
nullptr;
1501 uint32_t minArchetypeIdx = (uint32_t)-1;
1502 Entity minEntity = EntityBad;
1505 for (uint32_t t = 0; t < archetypes.size(); ++t) {
1506 const auto* pArchetype = archetypes[t];
1507 const auto& chunks = pArchetype->chunks();
1508 auto& cur = cursors[t];
1510 while (cur.chunkIdx < chunks.size() && cur.row >= chunks[cur.chunkIdx]->size()) {
1515 if (cur.chunkIdx >= chunks.size())
1518 const auto* pChunk = pArchetype->chunks()[cur.chunkIdx];
1519 auto entity = pChunk->entity_view()[cur.row];
1521 if (m_plan.ctx.data.sortBy != ecs::EntityBad) {
1522 auto compIdx = world_component_index_comp_idx(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.sortBy);
1524 compIdx = pChunk->comp_idx(m_plan.ctx.data.sortBy);
1525 pDataCurr = pChunk->comp_ptr(compIdx, cur.row);
1527 pDataCurr = &pChunk->entity_view()[cur.row];
1529 if (minEntity == EntityBad) {
1531 minArchetypeIdx = t;
1532 pDataMin = pDataCurr;
1536 if (m_plan.ctx.data.sortByFunc(*m_plan.ctx.w, pDataCurr, pDataMin) < 0) {
1538 minArchetypeIdx = t;
1543 if (minArchetypeIdx == (uint32_t)-1)
1546 auto& cur = cursors[minArchetypeIdx];
1547 const auto& chunks = archetypes[minArchetypeIdx]->chunks();
1548 Chunk* pChunk = chunks[cur.chunkIdx];
1550 if (minArchetypeIdx == currArchetypeIdx && pChunk == pCurrentChunk) {
1554 if (pCurrentChunk !=
nullptr) {
1555 m_state.nonTrivial.archetypeSortData.push_back(
1556 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1560 currArchetypeIdx = minArchetypeIdx;
1561 pCurrentChunk = pChunk;
1562 currentStartRow = cur.row;
1566 currentRow = cur.row;
1569 if (pCurrentChunk !=
nullptr) {
1570 m_state.nonTrivial.archetypeSortData.push_back(
1571 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1577 if (m_plan.ctx.data.sortByFunc ==
nullptr)
1580 if ((m_plan.ctx.data.flags & QueryCtx::QueryFlags::SortEntities) == 0 && m_state.nonTrivial.sortVersion != 0)
1582 m_plan.ctx.data.flags &=
~QueryCtx::QueryFlags::SortEntities;
1585 for (
const auto* pArchetype: m_state.archetypeCache)
1590 m_state.nonTrivial.sortVersion = ::gaia::ecs::world_version(*
world());
1595 if ((m_plan.ctx.data.flags & QueryCtx::QueryFlags::SortGroups) == 0)
1597 m_plan.ctx.data.flags &=
~QueryCtx::QueryFlags::SortGroups;
1599 if ((m_plan.ctx.data.flags & QueryCtx::QueryFlags::OrderGroups) != 0)
1607 auto* pTmpArchetype = m_state.archetypeCache[left];
1608 m_state.archetypeCache[left] = m_state.archetypeCache[right];
1609 m_state.archetypeCache[right] = pTmpArchetype;
1611 if (left < m_state.grouped.archetypeGroupIds.size() && right < m_state.grouped.archetypeGroupIds.size()) {
1612 const auto tmp = m_state.grouped.archetypeGroupIds[left];
1613 m_state.grouped.archetypeGroupIds[left] = m_state.grouped.archetypeGroupIds[right];
1614 m_state.grouped.archetypeGroupIds[right] = tmp;
1617 if (left < m_state.exec.archetypeCompIndices.size() && right < m_state.exec.archetypeCompIndices.size()) {
1618 auto tmp = m_state.exec.archetypeCompIndices[left];
1619 m_state.exec.archetypeCompIndices[left] = m_state.exec.archetypeCompIndices[right];
1620 m_state.exec.archetypeCompIndices[right] = tmp;
1623 if (left < m_state.exec.archetypeInheritedData.size() && right < m_state.exec.archetypeInheritedData.size()) {
1624 auto tmp = m_state.exec.archetypeInheritedData[left];
1625 m_state.exec.archetypeInheritedData[left] = m_state.exec.archetypeInheritedData[right];
1626 m_state.exec.archetypeInheritedData[right] = tmp;
1629 if (left < m_state.nonTrivial.archetypeBarrierPasses.size() &&
1630 right < m_state.nonTrivial.archetypeBarrierPasses.size()) {
1631 const auto tmp = m_state.nonTrivial.archetypeBarrierPasses[left];
1632 m_state.nonTrivial.archetypeBarrierPasses[left] = m_state.nonTrivial.archetypeBarrierPasses[right];
1633 m_state.nonTrivial.archetypeBarrierPasses[right] = tmp;
1639 if (!m_state.exec.compIndicesPending)
1642 m_state.exec.archetypeCompIndices.clear();
1643 m_state.exec.archetypeCompIndices.reserve(m_state.archetypeCache.size());
1644 for (
const auto* pArchetype: m_state.archetypeCache)
1647 m_state.exec.compIndicesPending =
false;
1652 return ctx().data.
deps.has_dep_flag(QueryCtx::DependencyHasInheritedDataTerms);
1657 if (!m_state.exec.inheritedDataPending)
1661 m_state.exec.archetypeInheritedData.clear();
1662 m_state.exec.inheritedDataPending =
false;
1666 m_state.exec.archetypeInheritedData.clear();
1667 m_state.exec.archetypeInheritedData.reserve(m_state.archetypeCache.size());
1668 for (
const auto* pArchetype: m_state.archetypeCache)
1671 m_state.exec.inheritedDataPending =
false;
1678 if (m_plan.ctx.data.groupBy == EntityBad || !m_state.grouped.dataPending)
1681 if (!orderGroups && (m_plan.ctx.data.flags & QueryCtx::QueryFlags::OrderGroups) == 0)
1685 bool operator()(GroupId a, GroupId b)
const {
1690 core::sort(m_state.grouped.archetypeGroupIds, sort_cond{}, [&](uint32_t left, uint32_t right) {
1691 swap_archetype_cache_entry(left, right);
1694 m_state.grouped.archetypeGroupData.clear();
1695 m_state.grouped.selectedGroupDataValid =
false;
1697 if (m_state.grouped.archetypeGroupIds.empty()) {
1698 m_state.grouped.dataPending =
false;
1702 GroupId groupId = m_state.grouped.archetypeGroupIds[0];
1703 uint32_t idxFirst = 0;
1704 const auto cnt = (uint32_t)m_state.grouped.archetypeGroupIds.size();
1705 for (uint32_t i = 1; i < cnt; ++i) {
1706 if (m_state.grouped.archetypeGroupIds[i] == groupId)
1709 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, i - 1,
false});
1710 groupId = m_state.grouped.archetypeGroupIds[i];
1714 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, cnt - 1,
false});
1715 m_state.grouped.dataPending =
false;
1720 if (!world_depth_order_prunes_disabled_subtrees(*
world(), m_plan.ctx.data.groupBy))
1725 const auto currRelationVersion = world_rel_version(*
world(), m_plan.ctx.data.groupBy);
1726 const auto currEnabledVersion = world_enabled_hierarchy_version(*
world());
1727 if (m_state.nonTrivial.barrierRelVersion == currRelationVersion &&
1728 m_state.nonTrivial.barrierEnabledVersion == currEnabledVersion)
1731 m_state.nonTrivial.archetypeBarrierPasses.resize(m_state.archetypeCache.size(), 1);
1732 m_state.nonTrivial.barrierMayPrune = 0;
1734 const auto relation = m_plan.ctx.data.groupBy;
1735 for (uint32_t i = 0; i < m_state.archetypeCache.size(); ++i) {
1736 const auto* pArchetype = m_state.archetypeCache[i];
1737 auto& barrierPasses = m_state.nonTrivial.archetypeBarrierPasses[i];
1740 auto ids = pArchetype->ids_view();
1741 for (
auto idsIdx: pArchetype->pair_rel_indices(relation)) {
1742 const auto pair = ids[idsIdx];
1743 const auto parent = world_pair_target_if_alive(*
world(),
pair);
1744 if (parent == EntityBad || !world_entity_enabled_hierarchy(*
world(), parent, relation)) {
1746 m_state.nonTrivial.barrierMayPrune = 1;
1752 m_state.nonTrivial.barrierRelVersion = currRelationVersion;
1753 m_state.nonTrivial.barrierEnabledVersion = currEnabledVersion;
1762 const auto terms =
ctx().data.terms_view();
1763 const auto cnt = (uint32_t)terms.size();
1765 const auto& term = terms[i];
1766 const auto fieldIdx = term.fieldIndex;
1767 const auto queryId = term.id;
1768 if (!queryId.pair() && world_is_out_of_line_component(*
world(), queryId)) {
1769#if GAIA_ASSERT_ENABLED
1771 const auto compIdx = core::get_index_unsafe(pArchetype->ids_view(), queryId);
1774 cacheData.indices[fieldIdx] = 0xFF;
1778 auto compIdx = world_component_index_comp_idx(*
world(), *pArchetype, queryId);
1782 compIdx = core::get_index_unsafe(pArchetype->ids_view(), queryId);
1786 cacheData.indices[fieldIdx] = (uint8_t)compIdx;
1797 const auto terms =
ctx().data.terms_view();
1798 const auto cnt = (uint32_t)terms.size();
1800 const auto& term = terms[i];
1801 if (term.src != EntityBad || term.entTrav != EntityBad || term_has_variables(term))
1803 if (term.matchKind != QueryMatchKind::Semantic)
1805 const auto queryId = term.id;
1806 if (queryId == EntityBad || is_wildcard(queryId) || is_variable((EntityId)queryId.id()))
1808 if (world_is_out_of_line_component(*
world(), queryId))
1810 if (!world_term_uses_inherit_policy(*
world(), queryId))
1812 if (pArchetype->
has(queryId))
1815 const auto owner = world_query_first_inherited_owner(*
world(), *pArchetype, queryId);
1816 GAIA_ASSERT(owner != EntityBad);
1817 inheritedData.data[term.fieldIndex] = world_query_inherited_arg_data_const_ptr(*
world(), owner, queryId);
1820 m_state.exec.archetypeInheritedData.push_back(inheritedData);
1828 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
1829 GAIA_PROF_SCOPE(queryinfo::add_cache_ng);
1831 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
1833 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
1835 m_state.archetypeSet.emplace(pArchetype);
1836 m_state.archetypeCache.push_back(pArchetype);
1837 m_state.exec.compIndicesPending =
true;
1838 m_state.exec.inheritedDataPending =
true;
1839 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
1840 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
1841 if (trackMembershipChange)
1842 mark_result_cache_membership_changed();
1849 if (!assumeAbsent && m_state.seedArchetypeSet.contains(pArchetype))
1851 GAIA_ASSERT(assumeAbsent || !m_state.seedArchetypeSet.contains(pArchetype));
1853 m_state.seedArchetypeSet.emplace(pArchetype);
1854 m_state.seedArchetypeCache.push_back(pArchetype);
1861 GAIA_ASSERT(m_plan.ctx.data.groupBy == EntityBad);
1862 GAIA_ASSERT(m_plan.ctx.data.sortByFunc ==
nullptr);
1863 GAIA_ASSERT(!m_state.seedArchetypeSet.contains(pArchetype));
1864 GAIA_ASSERT(!m_state.archetypeSet.contains(pArchetype));
1866 m_state.seedArchetypeSet.emplace(pArchetype);
1867 m_state.seedArchetypeCache.push_back(pArchetype);
1869 m_state.archetypeSet.emplace(pArchetype);
1870 m_state.archetypeCache.push_back(pArchetype);
1871 m_state.exec.compIndicesPending =
true;
1872 m_state.exec.inheritedDataPending =
true;
1873 if (trackMembershipChange)
1874 mark_result_cache_membership_changed();
1882 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
1883 GAIA_PROF_SCOPE(queryinfo::add_cache_wg);
1885 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
1887 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
1889 m_state.grouped.selectedGroupDataValid =
false;
1891 const GroupId groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
1893 m_state.archetypeSet.emplace(pArchetype);
1894 m_state.archetypeCache.push_back(pArchetype);
1895 m_state.grouped.archetypeGroupIds.push_back(groupId);
1896 m_state.grouped.dataPending =
true;
1897 m_state.exec.compIndicesPending =
true;
1898 m_state.exec.inheritedDataPending =
true;
1899 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
1900 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
1901 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortGroups;
1902 if (trackMembershipChange)
1903 mark_result_cache_membership_changed();
1911 if (m_plan.ctx.data.sortByFunc !=
nullptr)
1912 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortEntities;
1914 if (m_plan.ctx.data.groupBy != EntityBad)
1923 m_state.archetypeCache.push_back(pArchetype);
1924 m_state.exec.compIndicesPending =
true;
1925 m_state.exec.inheritedDataPending =
true;
1926 if (m_plan.ctx.data.groupBy != EntityBad) {
1927 const auto groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
1928 m_state.grouped.archetypeGroupIds.push_back(groupId);
1929 m_state.grouped.dataPending =
true;
1939 if (m_plan.ctx.data.groupBy == EntityBad || runtimeGroupId == 0)
1942 if (!m_state.grouped.selectedGroupDataValid || m_state.grouped.selectedGroupData.groupId != runtimeGroupId) {
1944 uint32_t right = (uint32_t)m_state.grouped.archetypeGroupData.size();
1945 while (left < right) {
1946 const uint32_t mid = left + ((right - left) >> 1);
1947 const auto midGroupId = m_state.grouped.archetypeGroupData[mid].groupId;
1948 if (midGroupId < runtimeGroupId)
1954 if (left < m_state.grouped.archetypeGroupData.size() &&
1955 m_state.grouped.archetypeGroupData[left].groupId == runtimeGroupId) {
1956 m_state.grouped.selectedGroupData = m_state.grouped.archetypeGroupData[left];
1957 m_state.grouped.selectedGroupDataValid =
true;
1958 return &m_state.grouped.selectedGroupData;
1961 m_state.grouped.selectedGroupData = {};
1962 m_state.grouped.selectedGroupDataValid =
false;
1966 return &m_state.grouped.selectedGroupData;
1972 if (m_state.archetypeSet.size() != m_state.seedArchetypeSet.size())
1975 for (
const auto* pArchetype: m_state.seedArchetypeCache) {
1976 if (!m_state.archetypeSet.contains(pArchetype))
1987 if (m_state.archetypeSet.size() != archetypeCache.size())
1990 for (
const auto* pArchetype: archetypeCache) {
1991 if (!m_state.archetypeSet.contains(pArchetype))
2002 clear_result_cache();
2003 const auto cnt = (uint32_t)m_state.seedArchetypeCache.size();
2007 if (membershipChanged)
2008 mark_result_cache_membership_changed();
2015 const auto it = m_state.archetypeSet.find(pArchetype);
2016 if (it == m_state.archetypeSet.end())
2019 m_state.archetypeSet.erase(it);
2021 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2022 GAIA_ASSERT(archetypeIdx !=
BadIndex);
2026 if (m_plan.ctx.data.sortByFunc !=
nullptr)
2027 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortEntities;
2029 core::swap_erase(m_state.archetypeCache, archetypeIdx);
2030 if (archetypeIdx < m_state.exec.archetypeCompIndices.size())
2031 core::swap_erase(m_state.exec.archetypeCompIndices, archetypeIdx);
2032 if (archetypeIdx < m_state.exec.archetypeInheritedData.size())
2033 core::swap_erase(m_state.exec.archetypeInheritedData, archetypeIdx);
2034 if (archetypeIdx < m_state.grouped.archetypeGroupIds.size())
2035 core::swap_erase(m_state.grouped.archetypeGroupIds, archetypeIdx);
2036 if (archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size())
2037 core::swap_erase(m_state.nonTrivial.archetypeBarrierPasses, archetypeIdx);
2039 if (m_plan.ctx.data.groupBy != EntityBad) {
2040 m_state.grouped.selectedGroupDataValid =
false;
2041 m_state.grouped.archetypeGroupData.clear();
2042 m_state.grouped.dataPending =
true;
2043 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortGroups;
2045 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2046 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2048 mark_result_cache_membership_changed();
2056 const auto it = m_state.seedArchetypeSet.find(pArchetype);
2057 if (it == m_state.seedArchetypeSet.end())
2060 m_state.seedArchetypeSet.erase(it);
2062 const auto archetypeIdx = core::get_index(m_state.seedArchetypeCache, pArchetype);
2063 GAIA_ASSERT(archetypeIdx !=
BadIndex);
2067 core::swap_erase(m_state.seedArchetypeCache, archetypeIdx);
2073 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
2074 return const_cast<World*
>(m_plan.ctx.w);
2078 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
2079 return m_plan.ctx.w;
2084 return m_plan.ctx.q.ser_buffer(
world());
2088 m_plan.ctx.q.ser_buffer_reset(
world());
2102 return m_plan.vm.bytecode(*
world());
2107 return m_plan.vm.op_count();
2112 return m_plan.vm.op_signature();
2117 const auto& ctxData = m_plan.ctx.data;
2118 return ctxData.changedCnt > 0;
2123 const auto& ctxData = m_plan.ctx.data;
2124 return ctxData.deps.has_dep_flag(QueryCtx::DependencyHasEntityFilterTerms);
2129 const auto& ctxData = m_plan.ctx.data;
2130 return ctxData.deps.has_dep_flag(QueryCtx::DependencyHasPotentialInheritedIdTerms);
2135 return m_plan.ctx.data.directTargetEvalKind;
2140 return m_plan.ctx.data.directTargetEvalId;
2145 return m_plan.ctx.data.canDirectTargetEval;
2150 return m_plan.ctx.data.canDirectEntitySeedEvalShape;
2155 return m_plan.ctx.data.hasOnlyDirectOrTerms;
2160 const auto& ctxData = m_plan.ctx.data;
2161 return (ctxData.flags & QueryCtx::QueryFlags::MatchPrefab) != 0 ||
2162 (ctxData.flags & QueryCtx::QueryFlags::HasPrefabTerms) != 0;
2166 template <
typename... T>
2168 return (has_inter<T>(QueryOpKind::Any) || ...);
2172 template <
typename... T>
2174 return (has_inter<T>(QueryOpKind::Or) || ...);
2178 template <
typename... T>
2180 return (has_inter<T>(QueryOpKind::All) && ...);
2184 template <
typename... T>
2186 return (!has_inter<T>(QueryOpKind::Not) && ...);
2192 GAIA_PROF_SCOPE(queryinfo::remove);
2201 const auto& ctxData = m_state.exec.archetypeCompIndices[archetypeIdx];
2209 if (archetypeIdx >= m_state.exec.archetypeInheritedData.size())
2211 const auto& ctxData = m_state.exec.archetypeInheritedData[archetypeIdx];
2220 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2233 if (m_state.exec.compIndicesPending)
2235 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2246 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2254 GAIA_NODISCARD GroupId
group_id(uint32_t archetypeIdx)
const {
2256 GAIA_ASSERT(archetypeIdx < m_state.grouped.archetypeGroupIds.size());
2257 return m_state.grouped.archetypeGroupIds[archetypeIdx];
2264 if (m_state.nonTrivial.archetypeBarrierPasses.empty())
2266 GAIA_ASSERT(archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size());
2267 return m_state.nonTrivial.archetypeBarrierPasses[archetypeIdx] != 0;
2273 return m_state.nonTrivial.barrierMayPrune != 0;
2277 GAIA_NODISCARD CArchetypeDArray::iterator
begin() {
2278 return m_state.archetypeCache.begin();
2282 GAIA_NODISCARD CArchetypeDArray::const_iterator
begin()
const {
2283 return m_state.archetypeCache.begin();
2287 GAIA_NODISCARD CArchetypeDArray::const_iterator
cbegin()
const {
2288 return m_state.archetypeCache.begin();
2292 GAIA_NODISCARD CArchetypeDArray::iterator
end() {
2293 return m_state.archetypeCache.end();
2297 GAIA_NODISCARD CArchetypeDArray::const_iterator
end()
const {
2298 return m_state.archetypeCache.end();
2302 GAIA_NODISCARD CArchetypeDArray::const_iterator
cend()
const {
2303 return m_state.archetypeCache.end();
2308 return std::span{(
const Archetype**)m_state.archetypeCache.data(), m_state.archetypeCache.size()};
2313 return std::span{m_state.nonTrivial.archetypeSortData.data(), m_state.nonTrivial.archetypeSortData.size()};
2319 return std::span{m_state.grouped.archetypeGroupData.data(), m_state.grouped.archetypeGroupData.size()};
2322#if GAIA_ECS_TEST_HOOKS
2328 GAIA_NODISCARD TestDynamicCacheKind test_dynamic_cache_kind()
const {
2329 return m_plan.ctx.data.dynamicCacheKind;
2333 GAIA_NODISCARD
bool test_uses_direct_src_version_tracking()
const {
2334 return m_plan.ctx.data.uses_direct_src_version_tracking();
2338 GAIA_NODISCARD
bool test_uses_src_trav_snapshot()
const {
2339 return m_plan.ctx.data.uses_src_trav_snapshot();
2344 GAIA_NODISCARD uint32_t test_match_pass_count()
const {
2345 return m_testMatchPassCount;
2349 GAIA_NODISCARD
static constexpr uint32_t test_query_info_size() {
2350 return (uint32_t)
sizeof(QueryInfo);
2354 GAIA_NODISCARD
static constexpr uint32_t test_query_plan_size() {
2355 return (uint32_t)
sizeof(QueryPlan);
2359 GAIA_NODISCARD
static constexpr uint32_t test_query_state_size() {
2360 return (uint32_t)
sizeof(QueryState);
2364 GAIA_NODISCARD
static constexpr uint32_t test_dynamic_cache_state_size() {
2365 return (uint32_t)
sizeof(QueryState::DynamicCacheState);
2369 GAIA_NODISCARD
static constexpr uint32_t test_query_state_dynamic_offset() {
2370 return (uint32_t)offsetof(QueryState, dynamic);
2375 void test_add_transient_archetype(
const Archetype* pArchetype) {
2376 GAIA_ASSERT(pArchetype !=
nullptr);
2377 if (pArchetype ==
nullptr)
2380 m_state.clear_transient_result_cache();
Array with variable size of elements of type.
Definition darray_impl.h:25
Definition span_impl.h:99
Definition archetype.h:83
GAIA_NODISCARD bool has(Entity entity) const
Checks if an entity is a part of the archetype.
Definition archetype.h:839
void sort_entities(Entity entity, TSortByFunc func)
Sorts all entities in the archetypes according to the given function.
Definition archetype.h:1022
Definition query_info.h:100
void ensure_inherited_data()
Rebuilds inherited-data payloads for matched archetypes when query terms require them.
Definition query_info.h:1656
void add_new_archetype_to_immediate_caches(const Archetype *pArchetype, bool trackMembershipChange)
Adds a newly matched archetype to both immediate caches while reusing one computed index mapping.
Definition query_info.h:1860
GAIA_NODISCARD CArchetypeDArray::const_iterator begin() const
Returns an iterator to the first cached result archetype.
Definition query_info.h:2282
void swap_archetype_cache_entry(uint32_t left, uint32_t right)
Swaps two result-cache entries and every parallel payload array that mirrors cache order.
Definition query_info.h:1606
GAIA_NODISCARD std::span< const GroupData > group_data_view() const
Returns cached group ranges, rebuilding grouped data when needed.
Definition query_info.h:2317
GAIA_NODISCARD GroupId group_id(uint32_t archetypeIdx) const
Returns the cached group id for a matched archetype index.
Definition query_info.h:2254
GAIA_NODISCARD bool has_no() const
Returns true when none of the requested types is present as a Not term.
Definition query_info.h:2185
GAIA_NODISCARD bool can_direct_entity_seed_eval_shape() const
Returns true when the query shape is eligible for direct entity seed evaluation.
Definition query_info.h:2149
void sort_entities()
Applies query entity sorting and rebuilds sorted chunk slices when needed.
Definition query_info.h:1576
GAIA_NODISCARD const World * world() const
Returns the world owning this query.
Definition query_info.h:2077
void remove(Archetype *pArchetype)
Removes an archetype from cache.
Definition query_info.h:2191
void reset()
Resets cached query state for slot reuse while keeping the compiled context object.
Definition query_info.h:856
GAIA_NODISCARD bool has_only_direct_or_terms() const
Returns true when the query contains only direct OR/NOT terms and at least one OR term.
Definition query_info.h:2154
void calculate_sort_data()
Calculates the sort data for the archetypes in the cache. This allows us to iterate entites in the or...
Definition query_info.h:1462
GAIA_NODISCARD bool barrier_may_prune() const
Returns true when any cached archetype can be pruned by the hierarchy barrier.
Definition query_info.h:2271
GAIA_NODISCARD bool has_or() const
Returns true when any of the requested types is present as an Or term.
Definition query_info.h:2173
void recompile()
Recompile the query.
Definition query_info.h:956
GAIA_NODISCARD bool barrier_passes(uint32_t archetypeIdx) const
Returns true when the matched archetype passes the depth-order hierarchy barrier.
Definition query_info.h:2262
GAIA_NODISCARD util::str bytecode() const
Returns a textual dump of the compiled VM bytecode.
Definition query_info.h:2101
MatchArchetypeQueryRet
Query matching result.
Definition query_info.h:109
GAIA_NODISCARD std::span< const Archetype * > cache_archetype_view() const
Returns the cached result archetypes as a span.
Definition query_info.h:2307
GAIA_NODISCARD bool can_update_with_new_archetype() const
Returns true when a new archetype can be propagated into the current cache incrementally.
Definition query_info.h:984
GAIA_NODISCARD bool has_inherited_data_payload() const
Returns true when query iteration needs cached inherited data payloads.
Definition query_info.h:1651
GAIA_NODISCARD uint32_t result_cache_rev() const
Returns the result membership revision used by reverse-index cache users.
Definition query_info.h:979
static GAIA_NODISCARD QueryInfo create(uint32_t idx, uint32_t gen, void *pCtx)
Creates and compiles a query info object from slot creation context.
Definition query_info.h:921
void init(World *world)
Binds this query info to a world after slot allocation.
Definition query_info.h:851
bool del_archetype_from_cache(const Archetype *pArchetype)
Removes an archetype from the final result cache and mirrored payload arrays.
Definition query_info.h:2014
GAIA_NODISCARD QuerySerBuffer & ser_buffer()
Returns the query serialization buffer associated with the owning world.
Definition query_info.h:2083
std::span< const uint8_t > try_indices_mapping_view(const Archetype *pArchetype) const
Returns a cached indices mapping view for an exact archetype match, or an empty span when absent.
Definition query_info.h:2232
GAIA_NODISCARD bool matches_prefab_entities() const
Returns true when prefab-tagged entities should participate in query results.
Definition query_info.h:2159
void invalidate_sort()
Marks the cached sorted slices dirty without invalidating query membership.
Definition query_info.h:888
void create_inherited_data(const Archetype *pArchetype)
Builds inherited component data pointers for semantic self-source terms on one archetype.
Definition query_info.h:1793
bool del_archetype_from_seed_cache(const Archetype *pArchetype)
Removes an archetype from the structural seed cache.
Definition query_info.h:2055
void add_archetype_to_seed_cache(const Archetype *pArchetype, bool assumeAbsent=false)
Adds an archetype to the structural seed cache.
Definition query_info.h:1848
bool register_archetype(const Archetype &archetype, Entity matchedSelector=EntityBad, bool assumeNew=false)
Registers a new or updated archetype with query caches when it matches this query.
Definition query_info.h:1345
InvalidationKind
Definition query_info.h:146
@ Result
Only the final result cache is stale. Structural seed matches remain valid and can be reused.
@ All
Full invalidation of all query cache state.
@ Seed
Structural seed matches are stale. This also implies the final result cache must be rebuilt.
GAIA_NODISCARD CArchetypeDArray::const_iterator cend() const
Returns a const iterator past the last cached result archetype.
Definition query_info.h:2302
InheritedTermDataView inherited_data_view(uint32_t archetypeIdx) const
Returns cached inherited-term data for a matched archetype index.
Definition query_info.h:2207
uint32_t idx
Allocated items: index in the query slot list. Deleted items: index of the next deleted item in the s...
Definition query_info.h:104
void ser_buffer_reset()
Resets the query serialization buffer associated with the owning world.
Definition query_info.h:2087
GAIA_NODISCARD bool direct_create_archetype_match_uses_is() const
Returns whether direct create-time matching needs Is-aware id checks.
Definition query_info.h:996
void ensure_comp_indices()
Rebuilds cached component-index payloads for matched archetypes when marked pending.
Definition query_info.h:1638
GAIA_NODISCARD QueryCtx::CachePolicy cache_policy() const
Returns the query cache policy selected during compilation.
Definition query_info.h:964
void match(const ArchetypeLookup &entityToArchetypeMap, std::span< const Archetype * > allArchetypes, const EntityToArchetypeVersionMap *pEntityToArchetypeMapVersions, ArchetypeId archetypeLastId, const cnt::sarray< Entity, MaxVarCnt > &runtimeVarBindings, uint8_t runtimeVarBindingMask)
Tries to match the query against archetypes in entityToArchetypeMap. This is necessary so we do not i...
Definition query_info.h:1035
GAIA_NODISCARD bool has_filters() const
Returns true when the query has per-entity changed/filter terms.
Definition query_info.h:2116
void compile(const EntityToArchetypeMap &entityToArchetypeMap, std::span< const Archetype * > allArchetypes)
Compile the query terms into a form we can easily process.
Definition query_info.h:948
GAIA_NODISCARD std::span< const SortData > cache_sort_view() const
Returns cached sorted chunk slices.
Definition query_info.h:2312
GAIA_NODISCARD bool has_grouped_payload() const
Returns true when grouped-query payloads are active for this query.
Definition query_info.h:969
GAIA_NODISCARD bool can_use_direct_create_archetype_match() const
Returns whether create-time matching should bypass the temporary one-archetype VM path.
Definition query_info.h:991
GAIA_NODISCARD bool has_potential_inherited_id_terms() const
Returns true when the query shape can resolve through inherited-id matching.
Definition query_info.h:2128
void ensure_depth_order_hierarchy_barrier_cache_inter()
Rebuilds cached depth-order hierarchy barrier results when relation or enabled-state versions changed...
Definition query_info.h:1719
GAIA_NODISCARD World * world()
Returns the mutable world owning this query.
Definition query_info.h:2072
void sync_result_cache_from_seed_cache()
Rebuilds the final result cache from structural seed matches. Bumps result membership revision only w...
Definition query_info.h:2000
GAIA_NODISCARD bool has_all() const
Returns true when all requested types are present as All terms.
Definition query_info.h:2179
GAIA_NODISCARD CArchetypeDArray::iterator end()
Returns a mutable iterator past the last cached result archetype.
Definition query_info.h:2292
GAIA_NODISCARD Entity direct_target_eval_id() const
Returns the concrete direct target id used by direct target evaluation.
Definition query_info.h:2139
void add_ref()
Adds one external reference to this query slot.
Definition query_info.h:833
void invalidate_result()
Marks final result matches stale while preserving structural seed matches.
Definition query_info.h:883
bool match_one(const Archetype &archetype, EntitySpan targetEntities, const cnt::sarray< Entity, MaxVarCnt > &runtimeVarBindings, uint8_t runtimeVarBindingMask)
Tries to match the query against the provided archetype. This is necessary so we do not iterate all c...
Definition query_info.h:1158
GAIA_NODISCARD bool has_sorted_payload() const
Returns true when sorted-query payloads are active for this query.
Definition query_info.h:974
GAIA_NODISCARD bool has_entity_filter_terms() const
Returns true when direct non-fragmenting terms must be rechecked per entity.
Definition query_info.h:2122
void sort_cache_groups()
Sorts cached archetypes by group id when grouped iteration requested ordering.
Definition query_info.h:1594
GAIA_NODISCARD CArchetypeDArray::const_iterator end() const
Returns an iterator past the last cached result archetype.
Definition query_info.h:2297
uint32_t gen
Generation ID of the query slot.
Definition query_info.h:106
GAIA_NODISCARD bool has_any() const
Returns true when any of the requested types is present as an Any term.
Definition query_info.h:2167
GAIA_NODISCARD uint32_t op_count() const
Returns the number of VM operations in the compiled query.
Definition query_info.h:2106
GAIA_NODISCARD bool has_same_result_membership_as(const CArchetypeDArray &archetypeCache) const
Compares final result-cache membership with another archetype array.
Definition query_info.h:1986
GAIA_NODISCARD CArchetypeDArray::const_iterator cbegin() const
Returns a const iterator to the first cached result archetype.
Definition query_info.h:2287
uint32_t refs() const
Returns the current external reference count.
Definition query_info.h:845
void add_archetype_to_cache(const Archetype *pArchetype, bool trackMembershipChange, bool assumeAbsent)
Adds an archetype to the final result cache and updates derived-payload dirty flags.
Definition query_info.h:1910
GAIA_NODISCARD QueryCtx & ctx()
Returns the mutable compiled query context.
Definition query_info.h:2092
std::span< const uint8_t > indices_mapping_view(uint32_t archetypeIdx) const
Returns a view of indices mapping for component entities in a given archetype.
Definition query_info.h:2199
static GAIA_NODISCARD QueryHandle handle(const QueryInfo &info)
Builds a stable query handle from query slot metadata.
Definition query_info.h:943
GAIA_NODISCARD CArchetypeDArray::iterator begin()
Returns a mutable iterator to the first cached result archetype.
Definition query_info.h:2277
void invalidate_seed()
Marks structural seed matches stale.
Definition query_info.h:878
GAIA_NODISCARD uint64_t op_signature() const
Returns a stable signature for the compiled VM operation stream.
Definition query_info.h:2111
GAIA_NODISCARD bool has_same_result_membership_as_seed_cache() const
Compares final result-cache membership with the structural seed cache.
Definition query_info.h:1971
void ensure_depth_order_hierarchy_barrier_cache()
Ensures depth-order hierarchy barrier results are current before public reads.
Definition query_info.h:2227
ArchetypeCompIndices create_comp_indices(const Archetype *pArchetype)
Builds field-to-archetype component indices for one matched archetype.
Definition query_info.h:1759
void invalidate(InvalidationKind kind=InvalidationKind::All)
Marks cached query results stale.
Definition query_info.h:862
void ensure_group_data(bool orderGroups)
Rebuilds grouped archetype ranges when a caller needs ordered group data.
Definition query_info.h:1677
GAIA_NODISCARD const QueryCtx & ctx() const
Returns the compiled query context.
Definition query_info.h:2096
void add_archetype_to_cache_w_grouping(const Archetype *pArchetype, bool trackMembershipChange, bool assumeAbsent=false)
Adds an archetype to the final result cache and records its group id.
Definition query_info.h:1881
GAIA_NODISCARD bool can_direct_target_eval() const
Returns true when the query can evaluate concrete target entities directly.
Definition query_info.h:2144
InheritedTermDataView try_inherited_data_view(const Archetype *pArchetype) const
Returns cached inherited-term data if it is already available for a matched archetype.
Definition query_info.h:2243
InheritedTermDataView inherited_data_view(const Archetype *pArchetype) const
Returns cached inherited-term data for a matched archetype pointer.
Definition query_info.h:2217
GAIA_NODISCARD QueryCtx::DirectTargetEvalKind direct_target_eval_kind() const
Returns the direct target evaluation mode selected during compilation.
Definition query_info.h:2134
GAIA_NODISCARD const GroupData * selected_group_data(GroupId runtimeGroupId) const
Returns cached group bounds for the currently selected group filter. The cached range is invalidated ...
Definition query_info.h:1937
void add_archetype_to_transient_cache(const Archetype *pArchetype)
Adds an archetype to the transient result cache used by non-persistent matching paths.
Definition query_info.h:1922
void add_archetype_to_cache_no_grouping(const Archetype *pArchetype, bool trackMembershipChange, bool assumeAbsent=false)
Adds an archetype to the final result cache for ungrouped queries.
Definition query_info.h:1827
static GAIA_NODISCARD QueryInfo create(QueryId id, QueryCtx &&ctx, const EntityToArchetypeMap &entityToArchetypeMap, std::span< const Archetype * > allArchetypes)
Creates and compiles a query info object from a moved query context.
Definition query_info.h:898
void dec_ref()
Releases one external reference to this query slot.
Definition query_info.h:839
Wrapper for two Entities forming a relationship pair.
Definition id.h:529
Wrapper for two types forming a relationship pair. Depending on what types are used to form a pair it...
Definition id.h:224
Compiles query terms into matching bytecode and evaluates that bytecode against archetypes....
Definition vm.h:2311
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_info.h:31
Definition query_info.h:35
Definition query_match_stamps.h:13
void clear()
Definition query_match_stamps.h:64
Definition query_common.h:117
Hashmap lookup structure used for Entity.
Definition id.h:468
Dependencies deps
Explicit dependency metadata derived from query shape.
Definition query_common.h:788
Definition query_common.h:564
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.
Definition query_common.h:144
Definition query_info.h:94
Definition query_info.h:1009
Direct concrete-source payload for reusable dynamic caches.
Definition query_info.h:303
GAIA_NODISCARD bool changed(const World &world, std::span< const Entity > sourceEntities) const
Returns true when any tracked source entity changed archetype.
Definition query_info.h:308
cnt::sarray< uint32_t, MAX_ITEMS_IN_QUERY > entityVersions
Last seen archetype versions for tracked direct concrete source entities.
Definition query_info.h:305
void snapshot(const World &world, std::span< const Entity > sourceEntities)
Captures current source entity archetype versions.
Definition query_info.h:319
Relation-version payload for reusable dynamic caches with relation dependencies.
Definition query_info.h:279
GAIA_NODISCARD bool changed(const World &world, std::span< const Entity > relations) const
Returns true when any tracked relation version changed.
Definition query_info.h:284
cnt::sarray< uint32_t, MAX_ITEMS_IN_QUERY > versions
Last seen versions for tracked dynamic relation dependencies.
Definition query_info.h:281
void snapshot(const World &world, std::span< const Entity > relations)
Captures current relation versions.
Definition query_info.h:295
Traversed-source payload for reusable dynamic caches with source traversal.
Definition query_info.h:327
GAIA_NODISCARD bool changed(const cnt::darray< SrcTravSnapshotItem > &items) const
Returns true when a rebuilt traversed-source closure differs from the captured snapshot.
Definition query_info.h:357
void mark_overflowed()
Marks the traversed-source snapshot as overflowed and unusable for reuse.
Definition query_info.h:377
void clear()
Clears traversed-source snapshot state.
Definition query_info.h:334
GAIA_NODISCARD bool versions_changed(const World &world) const
Returns true when any tracked traversed source entity changed archetype.
Definition query_info.h:345
cnt::darray< SrcTravSnapshotItem > snapshot
Last seen traversed-source closure for reusable source queries.
Definition query_info.h:329
void capture(const cnt::darray< SrcTravSnapshotItem > &items)
Captures a newly built traversed-source closure snapshot.
Definition query_info.h:371
GAIA_NODISCARD bool is_overflowed() const
Returns true when the traversed-source snapshot is unusable for reuse.
Definition query_info.h:340
bool overflowed
True when the traversed source closure exceeded the configured snapshot cap.
Definition query_info.h:331
Variable-binding payload for reusable dynamic caches with runtime variables.
Definition query_info.h:384
cnt::sarray< Entity, MaxVarCnt > bindings
Snapshot of runtime variable bindings used to build the current dynamic cache.
Definition query_info.h:386
uint8_t bindingMask
Bitmask of the variable bindings captured in bindings.
Definition query_info.h:388
void clear()
Clears runtime variable binding snapshot state.
Definition query_info.h:391
GAIA_NODISCARD bool changed(const cnt::sarray< Entity, MaxVarCnt > &runtimeBindings, uint8_t runtimeBindingMask) const
Returns true when runtime variable bindings differ from the captured snapshot.
Definition query_info.h:397
void snapshot(const cnt::sarray< Entity, MaxVarCnt > &runtimeBindings, uint8_t runtimeBindingMask)
Captures runtime variable bindings.
Definition query_info.h:416
Definition query_info.h:277
DirectSourcePayload directSource
Direct concrete-source payload.
Definition query_info.h:425
TraversedSourcePayload traversedSource
Traversed-source closure payload.
Definition query_info.h:427
VariablePayload variable
Runtime variable-binding payload.
Definition query_info.h:429
RelationPayload relation
Relation-version payload.
Definition query_info.h:423
void clear_input_snapshots()
Clears transient dynamic input snapshot state while preserving fixed-size version snapshots.
Definition query_info.h:432
Definition query_info.h:205
void clear()
Releases execution payload storage and clears pending rebuild flags.
Definition query_info.h:218
bool inheritedDataPending
True when archetype membership is populated but inherited-term data still needs to be built on demand...
Definition query_info.h:215
void clear_transient()
Clears execution payload contents while preserving allocated storage.
Definition query_info.h:226
bool compIndicesPending
True when archetype membership is populated but component-index metadata still needs to be built on d...
Definition query_info.h:212
cnt::darray< ArchetypeCompIndices > archetypeCompIndices
Cached component-index mapping for each matched archetype.
Definition query_info.h:207
cnt::darray< ArchetypeInheritedData > archetypeInheritedData
Cached inherited component data pointer per query field for exact self-source semantic terms.
Definition query_info.h:209
Definition query_info.h:174
cnt::darray< GroupData > archetypeGroupData
Group data used by cache.
Definition query_info.h:178
void clear_transient()
Clears grouped payload contents while preserving allocated storage.
Definition query_info.h:196
void clear()
Releases grouped payload storage and resets cached group selection state.
Definition query_info.h:187
bool selectedGroupDataValid
True when selectedGroupData matches the active group filter.
Definition query_info.h:182
GroupData selectedGroupData
Cached range for the currently selected group id.
Definition query_info.h:180
cnt::darray< GroupId > archetypeGroupIds
Group ids for grouped queries, aligned with archetypeCache.
Definition query_info.h:176
bool dataPending
True when grouped archetype order/ranges need to be rebuilt.
Definition query_info.h:184
Definition query_info.h:234
uint8_t barrierMayPrune
True when at least one cached archetype fails the depth-order hierarchy barrier.
Definition query_info.h:247
uint32_t barrierEnabledVersion
Entity enable-state version at which the cached depth-order hierarchy barrier state was last rebuilt.
Definition query_info.h:245
cnt::darray< uint8_t > archetypeBarrierPasses
Cached depth-order hierarchy barrier result for each archetype.
Definition query_info.h:236
cnt::darray< SortData > archetypeSortData
Sort data used by cache.
Definition query_info.h:238
void clear_transient()
Clears nontrivial payload contents while preserving allocated storage.
Definition query_info.h:260
uint32_t barrierRelVersion
Relation topology version at which the cached depth-order hierarchy barrier state was last rebuilt.
Definition query_info.h:243
void clear()
Releases nontrivial execution payload storage and resets version stamps.
Definition query_info.h:250
uint32_t sortVersion
World version at which the sorted cache slices were last rebuilt. Unlike worldVersion,...
Definition query_info.h:241
Temporary VM matching buffer meant to be owned by an ECS World. QueryInfo only acquires a frame while...
Definition query_info.h:41
cnt::darr< const Archetype * > matchesArr
Ordered list of matched archetypes emitted by the VM for the current run.
Definition query_info.h:45
void clear_temporary_matches()
Clears all temporary match data, including dedup stamps.
Definition query_info.h:57
uint32_t matchVersion
Monotonic dedup stamp used when the same scratch frame is reused by later full match() calls without ...
Definition query_info.h:54
void clear_temporary_matches_keep_stamps()
Clears temporary match arrays while preserving allocated dedup stamp pages. Full match() can reuse pr...
Definition query_info.h:67
cnt::darray< const Archetype * > matchesArrDynPrev
Previous result membership used when a dynamic rebuild compares reverse-index changes.
Definition query_info.h:51
ArchetypeMatchStamps matchStamps
Paged O(1) dedup table keyed by world-local archetype ids. Pages stay allocated on the scratch frame ...
Definition query_info.h:49
GAIA_NODISCARD uint32_t next_match_version()
Advances and returns the dedup stamp for the next VM match pass.
Definition query_info.h:80
void reset_stamps()
Clears dedup stamps and resets the match-version counter.
Definition query_info.h:73
Definition query_common.h:129
Lightweight owning string container with explicit length semantics (no implicit null terminator).
Definition str.h:331