2#include "gaia/config/config.h"
4#include "gaia/cnt/darray.h"
5#include "gaia/cnt/darray_ext.h"
6#include "gaia/cnt/ilist.h"
7#include "gaia/config/profiler.h"
8#include "gaia/core/hashing_policy.h"
9#include "gaia/core/utility.h"
10#include "gaia/ecs/api.h"
11#include "gaia/ecs/archetype.h"
12#include "gaia/ecs/archetype_common.h"
13#include "gaia/ecs/chunk_iterator.h"
14#include "gaia/ecs/component.h"
15#include "gaia/ecs/component_cache.h"
16#include "gaia/ecs/id.h"
17#include "gaia/ecs/query_common.h"
18#include "gaia/ecs/query_match_stamps.h"
19#include "gaia/ecs/vm.h"
20#include "gaia/mem/mem_utils.h"
21#include "gaia/mem/smallblock_allocator.h"
28 uint32_t world_version(
const World& world);
29 uint32_t world_archetype_delete_version(
const World& world);
30 Entity world_query_first_inherited_owner(
const World& world,
const Archetype& archetype, Entity term);
31 const void* world_query_inherited_arg_data_const_ptr(
const World& world, Entity owner, Entity
id);
34 using EntityToArchetypeMap = cnt::map<EntityLookupKey, ComponentIndexEntryArray>;
38 uint8_t
indices[ChunkHeader::MAX_COMPONENTS];
44 const void*
data[ChunkHeader::MAX_COMPONENTS];
117 GAIA_NODISCARD QueryMatchScratch& query_match_scratch_acquire(World& world);
118 void query_match_scratch_release(World& world,
bool keepStamps);
157 uint32_t archetypeIdx;
169 struct SrcTravSnapshotItem {
170 Entity entity = EntityBad;
172 uint32_t sourceVersion = 0;
174 GAIA_NODISCARD
bool operator==(
const SrcTravSnapshotItem& other)
const {
175 return entity == other.entity && sourceVersion == other.sourceVersion;
178 GAIA_NODISCARD
bool operator!=(
const SrcTravSnapshotItem& other)
const {
179 return !operator==(other);
201 enum DirtyFlags : uint8_t { Clean = 0x00, Seed = 0x01, Result = 0x02, All = Seed | Result };
204 cnt::set<const Archetype*> seedArchetypeSet;
205 CArchetypeDArray seedArchetypeCache;
209 cnt::set<const Archetype*> archetypeSet;
211 CArchetypeDArray archetypeCache;
357 GroupedPayload grouped;
359 NonTrivialPayload nonTrivial;
373 const auto cnt = (uint32_t)relations.size();
386 const auto cnt = (uint32_t)relations.size();
402 const auto cnt = (uint32_t)sourceEntities.size();
415 const auto cnt = (uint32_t)sourceEntities.size();
453 if (item.sourceVersion != world_entity_archetype_version(
world, item.entity))
517 if (runtimeBindingMask == 0)
520 GAIA_FOR(MaxVarCnt) {
521 const auto bit = (uint8_t(1) << i);
522 if ((runtimeBindingMask & bit) == 0)
525 if (
bindings[i] != runtimeBindings[i])
558 DynamicCacheState dynamic;
561 ArchetypeId lastArchetypeId{};
564 uint32_t resultCacheRevision = 1;
566 uint8_t resultCacheMayNeedPrefabFilter = 0;
568 uint8_t dirtyFlags = DirtyFlags::All;
571 void clear_seed_cache() {
572 seedArchetypeSet = {};
573 seedArchetypeCache = {};
577 void clear_result_cache() {
580 resultCacheMayNeedPrefabFilter = 0;
587 void clear_transient_result_cache() {
588 archetypeCache.clear();
589 resultCacheMayNeedPrefabFilter = 0;
590 exec.clear_transient();
591 grouped.clear_transient();
592 nonTrivial.clear_transient();
598 clear_result_cache();
604 dynamic.clear_input_snapshots();
606 dirtyFlags = DirtyFlags::All;
610 void invalidate_seed() {
611 dirtyFlags = (uint8_t)(dirtyFlags | DirtyFlags::Seed | DirtyFlags::Result);
615 void invalidate_result() {
616 dirtyFlags = (uint8_t)(dirtyFlags | DirtyFlags::Result);
620 void invalidate_all() {
621 dirtyFlags = DirtyFlags::All;
625 GAIA_NODISCARD
bool seed_dirty()
const {
626 return (dirtyFlags & DirtyFlags::Seed) != 0;
630 GAIA_NODISCARD
bool result_dirty()
const {
631 return (dirtyFlags & DirtyFlags::Result) != 0;
635 GAIA_NODISCARD
bool needs_refresh()
const {
636 return seed_dirty() || result_dirty();
641 dirtyFlags = DirtyFlags::Clean;
646#if GAIA_ECS_TEST_HOOKS
648 uint32_t m_testMatchPassCount = 0;
654 enum QueryCmdType : uint8_t { ALL, OR, NOT };
658 void reset_matching_cache(
bool trackMembershipChange) {
659 if (trackMembershipChange && !m_state.archetypeCache.empty())
660 mark_result_cache_membership_changed();
664 auto& ctxData = m_plan.ctx.data;
665 ctxData.lastMatchedArchetypeIdx_All = {};
666 ctxData.lastMatchedArchetypeIdx_Or = {};
667 ctxData.lastMatchedArchetypeIdx_Not = {};
671 void clear_result_cache() {
672 m_state.clear_result_cache();
677 void invalidate_result_barriers() {
678 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
679 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
684 void mark_result_cache_membership_changed() {
685 invalidate_result_barriers();
686 ++m_state.resultCacheRevision;
687 if (m_state.resultCacheRevision != 0)
691 m_state.resultCacheRevision = 1;
695 GAIA_NODISCARD
bool has_dyn_terms()
const {
700 GAIA_NODISCARD
bool can_reuse_dyn_cache()
const {
701 return m_plan.ctx.data.canReuseDynamicCache;
705 GAIA_NODISCARD
bool uses_direct_src_version_tracking()
const {
706 return m_plan.ctx.data.uses_direct_src_version_tracking();
710 GAIA_NODISCARD
bool uses_src_trav_snapshot()
const {
711 return m_plan.ctx.data.uses_src_trav_snapshot();
715 GAIA_NODISCARD
bool dyn_rel_versions_changed()
const {
716 return m_state.dynamic.relation.changed(*
world(), m_plan.ctx.data.deps.relations_view());
720 GAIA_NODISCARD
bool dyn_var_bindings_changed(
721 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask)
const {
722 return m_state.dynamic.variable.changed(runtimeVarBindings, runtimeVarBindingMask);
726 GAIA_NODISCARD
bool direct_src_versions_changed()
const {
727 return m_state.dynamic.directSource.changed(*
world(), m_plan.ctx.data.deps.src_entities_view());
733 template <
typename Func>
734 void each_reusable_src_entity(Func&& func)
const {
735 const auto terms = m_plan.ctx.data.terms_view();
736 const auto cnt = (uint32_t)terms.size();
738 const auto& term = terms[i];
739 if (term.src == EntityBad || is_variable(term.src))
742 (void)vm::detail::each_lookup_src(*
world(), term, term.src, [&](Entity source) {
750 GAIA_NODISCARD
bool build_src_trav_snapshot(cnt::darray<SrcTravSnapshotItem>& items)
const {
751 const auto maxItems = (uint32_t)m_plan.ctx.data.cacheSrcTrav;
756 bool overflowed =
false;
757 each_reusable_src_entity([&](Entity source) {
758 if (items.size() >= maxItems) {
762 items.push_back({source, world_entity_archetype_version(*world(), source)});
771 GAIA_NODISCARD
bool traversed_src_versions_changed()
const {
772 return m_state.dynamic.traversedSource.versions_changed(*
world());
776 GAIA_NODISCARD
bool traversed_src_inputs_changed(
bool relationVersionsChanged) {
777 if (m_state.dynamic.traversedSource.is_overflowed())
780 if (!relationVersionsChanged)
781 return traversed_src_versions_changed();
783 cnt::darray<SrcTravSnapshotItem> scratch;
784 if (!build_src_trav_snapshot(scratch))
787 return m_state.dynamic.traversedSource.changed(*
world(), scratch);
791 GAIA_NODISCARD
bool mixed_dyn_inputs_changed(
792 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
793 const auto& deps = m_plan.ctx.data.deps;
795 dyn_var_bindings_changed(runtimeVarBindings, runtimeVarBindingMask))
798 const bool relationVersionsChanged = dyn_rel_versions_changed();
801 if (relationVersionsChanged && !(hasSourceTerms && hasTraversalTerms))
805 return relationVersionsChanged;
807 if (m_state.dynamic.traversedSource.is_overflowed())
810 if (!hasTraversalTerms)
811 return direct_src_versions_changed();
813 return traversed_src_inputs_changed(relationVersionsChanged);
818 dyn_inputs_changed(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
819 if (!can_reuse_dyn_cache())
822 switch (m_plan.ctx.data.dynamicCacheKind) {
826 return dyn_rel_versions_changed();
828 return direct_src_versions_changed();
830 return traversed_src_inputs_changed(dyn_rel_versions_changed());
832 return dyn_var_bindings_changed(runtimeVarBindings, runtimeVarBindingMask);
834 return mixed_dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask);
842 void snapshot_dyn_rel_inputs() {
843 m_state.dynamic.relation.snapshot(*
world(), m_plan.ctx.data.deps.relations_view());
847 void snapshot_dyn_direct_src_inputs() {
848 m_state.dynamic.directSource.snapshot(*
world(), m_plan.ctx.data.deps.src_entities_view());
852 void snapshot_dyn_traversed_src_inputs() {
853 cnt::darray<SrcTravSnapshotItem> scratch;
854 if (build_src_trav_snapshot(scratch))
855 m_state.dynamic.traversedSource.capture(*
world(), scratch);
857 m_state.dynamic.traversedSource.mark_overflowed();
862 snapshot_dyn_var_inputs(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
863 m_state.dynamic.variable.snapshot(runtimeVarBindings, runtimeVarBindingMask);
868 snapshot_dyn_inputs(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
869 if (!can_reuse_dyn_cache())
872 m_state.dynamic.clear_input_snapshots();
874 switch (m_plan.ctx.data.dynamicCacheKind) {
878 snapshot_dyn_rel_inputs();
881 snapshot_dyn_direct_src_inputs();
884 snapshot_dyn_rel_inputs();
885 snapshot_dyn_traversed_src_inputs();
888 snapshot_dyn_var_inputs(runtimeVarBindings, runtimeVarBindingMask);
891 const auto& deps = m_plan.ctx.data.deps;
892 snapshot_dyn_rel_inputs();
895 snapshot_dyn_traversed_src_inputs();
897 snapshot_dyn_direct_src_inputs();
900 snapshot_dyn_var_inputs(runtimeVarBindings, runtimeVarBindingMask);
911 template <
typename TType>
912 GAIA_NODISCARD
bool has_inter([[maybe_unused]] QueryOpKind op,
bool isReadWrite)
const {
913 using T = core::raw_t<TType>;
915 if constexpr (std::is_same_v<T, Entity>) {
917 GAIA_ASSERT(!isReadWrite);
924 const auto rel = m_plan.ctx.cc->get<
typename T::rel>().entity;
925 const auto tgt = m_plan.ctx.cc->get<
typename T::tgt>().entity;
926 id = (Entity)Pair(rel, tgt);
928 id = m_plan.ctx.cc->get<T>().entity;
931 const auto& ctxData = m_plan.ctx.data;
932 const auto compIdx = comp_idx<MAX_ITEMS_IN_QUERY>(ctxData.terms.data(),
id, EntityBad);
934 if (op != ctxData.terms[compIdx].op)
938 const uint32_t maskRW = (uint32_t)ctxData.readWriteMask & (1U << compIdx);
939 const uint32_t maskXX = (uint32_t)isReadWrite << compIdx;
940 return maskRW == maskXX;
947 template <
typename T>
948 GAIA_NODISCARD
bool has_inter(QueryOpKind op)
const {
950 constexpr bool isReadWrite = core::is_mut_v<T>;
951 return has_inter<T>(op, isReadWrite);
958 GAIA_ASSERT(m_refs != 0);
963 GAIA_ASSERT(m_refs > 0);
976 m_plan.ctx.w =
world;
981 reset_matching_cache(
true);
989 m_state.invalidate_result();
990 invalidate_result_barriers();
993 m_state.invalidate_seed();
996 m_state.invalidate_all();
1013 if (m_plan.ctx.data.sortByFunc !=
nullptr)
1025 std::span<const Archetype*> allArchetypes) {
1033 info.m_plan.ctx = GAIA_MOV(
ctx);
1034 info.m_plan.ctx.q.handle = {id, 0};
1037 info.
compile(entityToArchetypeMap, allArchetypes);
1049 auto& queryCtx = *pCreationCtx->pQueryCtx;
1059 info.m_plan.ctx = GAIA_MOV(queryCtx);
1060 info.m_plan.ctx.q.handle = {
idx,
gen};
1063 info.
compile(entityToArchetypeMap, pCreationCtx->allArchetypes);
1079 GAIA_PROF_SCOPE(queryinfo::compile);
1082 m_plan.vm.compile(entityToArchetypeMap, allArchetypes, m_plan.ctx);
1087 GAIA_PROF_SCOPE(queryinfo::recompile);
1090 m_plan.vm.create_opcodes(m_plan.ctx);
1096 return m_plan.ctx.data.cachePolicy;
1102 return m_plan.ctx.data.groupBy != EntityBad;
1109 template <
typename Container>
1114 const auto cnt = (uint32_t)m_state.grouped.archetypeGroupData.size();
1117 const auto groupId = m_state.grouped.archetypeGroupData[i].groupId;
1119 out.push_back(groupId);
1126 return m_plan.ctx.data.sortByFunc !=
nullptr;
1132 return m_state.resultCacheRevision;
1138 return m_state.resultCacheMayNeedPrefabFilter != 0;
1146 !m_state.needs_refresh();
1158 const auto& ctxData = m_plan.ctx.data;
1159 return (ctxData.as_mask_0 + ctxData.as_mask_1) != 0;
1166 return m_plan.ctx == other;
1173 return m_plan.ctx != other;
1207 template <
typename ArchetypeLookup>
1209 const ArchetypeLookup& entityToArchetypeMap, std::span<const Archetype*> allArchetypes,
1212 auto& ctxData = m_plan.ctx.data;
1219 if (!m_plan.vm.is_compiled())
1222 const bool hasDynamicTerms = has_dyn_terms();
1223 const bool canReuseDynamicCache = can_reuse_dyn_cache();
1224 const bool refreshDynamicCache =
1225 hasDynamicTerms && (!canReuseDynamicCache || m_state.needs_refresh() ||
1226 dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask));
1227 bool compareDynamicMembership =
false;
1230 if (refreshDynamicCache) {
1231 compareDynamicMembership = !m_state.archetypeCache.empty();
1232 if (compareDynamicMembership) {
1234 pMatchScratch = &query_match_scratch_acquire(w);
1238 reset_matching_cache(!compareDynamicMembership);
1239 }
else if (m_state.seed_dirty()) {
1240 reset_matching_cache(
true);
1241 }
else if (m_state.result_dirty()) {
1243 if (m_state.lastArchetypeId == archetypeLastId) {
1246 m_state.clear_dirty();
1252 GAIA_ASSERT(archetypeLastId >= m_state.lastArchetypeId);
1253 if (!m_state.needs_refresh() && m_state.lastArchetypeId == archetypeLastId &&
1254 (!hasDynamicTerms || canReuseDynamicCache)) {
1260 m_state.lastArchetypeId = archetypeLastId;
1262 GAIA_PROF_SCOPE(queryinfo::match);
1265 auto& matchScratch = pMatchScratch !=
nullptr ? *pMatchScratch : query_match_scratch_acquire(w);
1272 ctx.allArchetypes = allArchetypes;
1273 if constexpr (std::is_same_v<ArchetypeLookup, EntityToArchetypeMap>) {
1274 GAIA_ASSERT(pEntityToArchetypeMapVersions !=
nullptr);
1275 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap, *pEntityToArchetypeMapVersions);
1277 (void)pEntityToArchetypeMapVersions;
1278 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap);
1281 ctx.pMatchesArr = &matchScratch.matchesArr;
1282 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1283 ctx.matchesVersion = matchScratch.next_match_version();
1284 ctx.pLastMatchedArchetypeIdx_All = &ctxData.lastMatchedArchetypeIdx_All;
1285 ctx.pLastMatchedArchetypeIdx_Or = &ctxData.lastMatchedArchetypeIdx_Or;
1286 ctx.pLastMatchedArchetypeIdx_Not = &ctxData.lastMatchedArchetypeIdx_Not;
1287 ctx.queryMask = ctxData.queryMask;
1288 ctx.as_mask_0 = ctxData.as_mask_0;
1289 ctx.as_mask_1 = ctxData.as_mask_1;
1290 ctx.flags = ctxData.flags;
1291 ctx.varBindings = runtimeVarBindings;
1292 ctx.varBindingMask = runtimeVarBindingMask;
1295#if GAIA_ECS_TEST_HOOKS
1296 ++m_testMatchPassCount;
1298 m_plan.vm.exec(
ctx);
1301 const bool trackMembershipChangeOnAdd = !compareDynamicMembership;
1302 for (
const auto* pArchetype: *
ctx.pMatchesArr) {
1303 if (hasDynamicTerms) {
1311 if (compareDynamicMembership) {
1313 mark_result_cache_membership_changed();
1320 snapshot_dyn_inputs(runtimeVarBindings, runtimeVarBindingMask);
1321 m_state.clear_dirty();
1333 const Archetype& archetype, EntitySpan targetEntities,
1335 auto& ctxData = m_plan.ctx.data;
1342 if (!m_plan.vm.is_compiled())
1345 const bool hasDynamicTerms = has_dyn_terms();
1346 const bool canReuseDynamicCache = can_reuse_dyn_cache();
1347 if ((hasDynamicTerms && (!canReuseDynamicCache || m_state.needs_refresh() ||
1348 dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask))) ||
1349 m_state.seed_dirty()) {
1351 reset_matching_cache(
true);
1352 }
else if (m_state.result_dirty()) {
1356 GAIA_PROF_SCOPE(queryinfo::match1);
1359 auto& matchScratch = query_match_scratch_acquire(w);
1365 ctx.targetEntities = targetEntities;
1366 const auto* pArchetype = &archetype;
1367 ctx.allArchetypes = std::span((
const Archetype**)&pArchetype, 1);
1368 ctx.archetypeLookup = {};
1369 ctx.pMatchesArr = &matchScratch.matchesArr;
1370 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1371 ctx.matchesVersion = matchScratch.next_match_version();
1372 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1373 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1374 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1375 ctx.queryMask = ctxData.queryMask;
1376 ctx.as_mask_0 = ctxData.as_mask_0;
1377 ctx.as_mask_1 = ctxData.as_mask_1;
1378 ctx.flags = ctxData.flags;
1379 ctx.varBindings = runtimeVarBindings;
1380 ctx.varBindingMask = runtimeVarBindingMask;
1383#if GAIA_ECS_TEST_HOOKS
1384 ++m_testMatchPassCount;
1386 m_plan.vm.exec(
ctx);
1387 const bool matched = !
ctx.pMatchesArr->empty();
1390 for (
const auto* pArch: *
ctx.pMatchesArr) {
1391 if (hasDynamicTerms) {
1398 snapshot_dyn_inputs(runtimeVarBindings, runtimeVarBindingMask);
1399 m_state.clear_dirty();
1415 entityToArchetypeMap, allArchetypes, &entityToArchetypeMapVersions, archetypeLastId, runtimeVarBindings,
1416 runtimeVarBindingMask);
1429 auto& ctxData = m_plan.ctx.data;
1434 if (!m_plan.vm.is_compiled())
1437 m_state.clear_transient_result_cache();
1440 auto& matchScratch = query_match_scratch_acquire(w);
1445 ctx.allArchetypes = allArchetypes;
1446 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap, entityToArchetypeMapVersions);
1447 ctx.pMatchesArr = &matchScratch.matchesArr;
1448 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1449 ctx.matchesVersion = matchScratch.next_match_version();
1450 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1451 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1452 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1453 ctx.queryMask = ctxData.queryMask;
1454 ctx.as_mask_0 = ctxData.as_mask_0;
1455 ctx.as_mask_1 = ctxData.as_mask_1;
1456 ctx.flags = ctxData.flags;
1457 ctx.varBindings = runtimeVarBindings;
1458 ctx.varBindingMask = runtimeVarBindingMask;
1460 m_plan.vm.exec(
ctx);
1462 m_state.archetypeCache.reserve(
ctx.pMatchesArr->size());
1463 if (ctxData.groupBy != EntityBad)
1464 m_state.grouped.archetypeGroupIds.reserve(
ctx.pMatchesArr->size());
1465 for (
const auto* pArchetype: *
ctx.pMatchesArr)
1479 const Archetype& archetype, EntitySpan targetEntities,
1481 return match_one(archetype, targetEntities, runtimeVarBindings, runtimeVarBindingMask);
1491 const Archetype& archetype, EntitySpan targetEntities,
1493 auto& ctxData = m_plan.ctx.data;
1498 if (!m_plan.vm.is_compiled())
1501 m_state.clear_transient_result_cache();
1504 auto& matchScratch = query_match_scratch_acquire(w);
1509 ctx.targetEntities = targetEntities;
1510 const auto* pArchetype = &archetype;
1511 ctx.allArchetypes = std::span((
const Archetype**)&pArchetype, 1);
1512 ctx.archetypeLookup = {};
1513 ctx.pMatchesArr = &matchScratch.matchesArr;
1514 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1515 ctx.matchesVersion = matchScratch.next_match_version();
1516 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1517 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1518 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1519 ctx.queryMask = ctxData.queryMask;
1520 ctx.as_mask_0 = ctxData.as_mask_0;
1521 ctx.as_mask_1 = ctxData.as_mask_1;
1522 ctx.flags = ctxData.flags;
1523 ctx.varBindings = runtimeVarBindings;
1524 ctx.varBindingMask = runtimeVarBindingMask;
1526 m_plan.vm.exec(
ctx);
1527 const bool matched = !
ctx.pMatchesArr->empty();
1529 m_state.archetypeCache.reserve(
ctx.pMatchesArr->size());
1530 if (ctxData.groupBy != EntityBad)
1531 m_state.grouped.archetypeGroupIds.reserve(
ctx.pMatchesArr->size());
1532 for (
const auto* pArch: *
ctx.pMatchesArr)
1545 auto& ctxData = m_plan.ctx.data;
1554 const bool hadMatchBefore = !assumeNew && m_state.archetypeSet.contains(&archetype);
1557 bool hasOrTerms =
false;
1558 bool matchedOrTerm =
false;
1559 for (
const auto& term: ctxData.terms_view()) {
1560 if (term.id == matchedSelector) {
1561 if (term.op == QueryOpKind::Or)
1562 matchedOrTerm =
true;
1566 const bool present = usesIs ? vm::detail::match_single_id_on_archetype(*
world(), archetype, term.
id)
1567 : world_component_index_match_count(*
world(), archetype, term.
id) != 0;
1568 if (term.op == QueryOpKind::Or) {
1570 matchedOrTerm |= present;
1573 if (term.op == QueryOpKind::Any)
1576 const bool matched = term.op == QueryOpKind::Not ? !present : present;
1580 if (hasOrTerms && !matchedOrTerm)
1595 auto addLookupUnique = [&](
Entity key, uint16_t compIdx, uint16_t matchCount) {
1597 const auto itLookup =
1598 core::find_if(singleArchetypeLookup.
begin(), singleArchetypeLookup.
end(), [&](
const auto& item) {
1599 return item.matches(keyLookup);
1601 if (itLookup != singleArchetypeLookup.
end()) {
1602 auto& entry = itLookup->entry;
1603 entry.matchCount = (uint16_t)(entry.matchCount + matchCount);
1604 if (compIdx != ComponentIndexBad)
1605 entry.compIdx = compIdx;
1612 auto archetypeIds = archetype.
ids_view();
1613 const auto cntIds = (uint32_t)archetypeIds.size();
1615 const auto entity = archetypeIds[i];
1625 const auto relKind = entity.entity() ? EntityKind::EK_Uni : EntityKind::EK_Gen;
1626 const auto rel =
Entity((EntityId)entity.id(), 0,
false,
false, relKind);
1627 const auto tgt =
Entity((EntityId)entity.gen(), 0,
false,
false, entity.kind());
1628 addLookupUnique(
Pair(
All, tgt), ComponentIndexBad, 1);
1629 addLookupUnique(
Pair(rel,
All), ComponentIndexBad, 1);
1630 addLookupUnique(
Pair(
All,
All), ComponentIndexBad, 1);
1633 auto lastMatchedArchetypeIdx_All = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_All);
1634 auto lastMatchedArchetypeIdx_Or = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Or);
1635 auto lastMatchedArchetypeIdx_Not = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Not);
1636 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_All.empty());
1637 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Or.empty());
1638 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Not.empty());
1640 const auto* pArchetype = &archetype;
1643 singleArchetypeLookup, std::span((
const Archetype**)&pArchetype, 1),
nullptr, archetype.
id(),
1644 noRuntimeVarBindings, 0);
1645 ctxData.lastMatchedArchetypeIdx_All = GAIA_MOV(lastMatchedArchetypeIdx_All);
1646 ctxData.lastMatchedArchetypeIdx_Or = GAIA_MOV(lastMatchedArchetypeIdx_Or);
1647 ctxData.lastMatchedArchetypeIdx_Not = GAIA_MOV(lastMatchedArchetypeIdx_Not);
1648 const bool matched = assumeNew ? m_state.archetypeSet.contains(&archetype)
1649 : !hadMatchBefore && m_state.archetypeSet.contains(&archetype);
1662 GAIA_PROF_SCOPE(queryinfo::calc_sort_data);
1664 m_state.nonTrivial.archetypeSortData.clear();
1682 uint32_t chunkIdx = 0;
1686 auto& archetypes = m_state.archetypeCache;
1691 uint32_t currArchetypeIdx = (uint32_t)-1;
1692 Chunk* pCurrentChunk =
nullptr;
1693 uint16_t currentStartRow = 0;
1694 uint16_t currentRow = 0;
1696 const void* pDataMin =
nullptr;
1697 const void* pDataCurr =
nullptr;
1700 uint32_t minArchetypeIdx = (uint32_t)-1;
1701 Entity minEntity = EntityBad;
1704 for (uint32_t t = 0; t < archetypes.size(); ++t) {
1705 const auto* pArchetype = archetypes[t];
1706 const auto& chunks = pArchetype->chunks();
1707 auto& cur = cursors[t];
1709 while (cur.chunkIdx < chunks.size() && cur.row >= chunks[cur.chunkIdx]->size()) {
1714 if (cur.chunkIdx >= chunks.size())
1717 const auto* pChunk = pArchetype->chunks()[cur.chunkIdx];
1718 auto entity = pChunk->entity_view()[cur.row];
1720 if (m_plan.ctx.data.sortBy != ecs::EntityBad) {
1721 auto compIdx = world_component_index_comp_idx(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.sortBy);
1722 if (compIdx == BadIndex)
1723 compIdx = pChunk->comp_idx(m_plan.ctx.data.sortBy);
1724 pDataCurr = pChunk->comp_ptr(compIdx, cur.row);
1726 pDataCurr = &pChunk->entity_view()[cur.row];
1728 if (minEntity == EntityBad) {
1730 minArchetypeIdx = t;
1731 pDataMin = pDataCurr;
1735 if (m_plan.ctx.data.sortByFunc(*m_plan.ctx.w, pDataCurr, pDataMin) < 0) {
1737 minArchetypeIdx = t;
1742 if (minArchetypeIdx == (uint32_t)-1)
1745 auto& cur = cursors[minArchetypeIdx];
1746 const auto& chunks = archetypes[minArchetypeIdx]->chunks();
1747 Chunk* pChunk = chunks[cur.chunkIdx];
1749 if (minArchetypeIdx == currArchetypeIdx && pChunk == pCurrentChunk) {
1753 if (pCurrentChunk !=
nullptr) {
1754 m_state.nonTrivial.archetypeSortData.push_back(
1755 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1759 currArchetypeIdx = minArchetypeIdx;
1760 pCurrentChunk = pChunk;
1761 currentStartRow = cur.row;
1765 currentRow = cur.row;
1768 if (pCurrentChunk !=
nullptr) {
1769 m_state.nonTrivial.archetypeSortData.push_back(
1770 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1776 if (m_plan.ctx.data.sortByFunc ==
nullptr)
1781 m_plan.ctx.data.flags &=
~QueryCtx::QueryFlags::SortEntities;
1784 for (
const auto* pArchetype: m_state.archetypeCache)
1789 m_state.nonTrivial.sortVersion = ::gaia::ecs::world_version(*
world());
1796 m_plan.ctx.data.flags &=
~QueryCtx::QueryFlags::SortGroups;
1806 auto* pTmpArchetype = m_state.archetypeCache[left];
1807 m_state.archetypeCache[left] = m_state.archetypeCache[right];
1808 m_state.archetypeCache[right] = pTmpArchetype;
1810 if (left < m_state.grouped.archetypeGroupIds.size() && right < m_state.grouped.archetypeGroupIds.size()) {
1811 const auto tmp = m_state.grouped.archetypeGroupIds[left];
1812 m_state.grouped.archetypeGroupIds[left] = m_state.grouped.archetypeGroupIds[right];
1813 m_state.grouped.archetypeGroupIds[right] = tmp;
1816 if (left < m_state.exec.archetypeCompIndices.size() && right < m_state.exec.archetypeCompIndices.size()) {
1817 auto tmp = m_state.exec.archetypeCompIndices[left];
1818 m_state.exec.archetypeCompIndices[left] = m_state.exec.archetypeCompIndices[right];
1819 m_state.exec.archetypeCompIndices[right] = tmp;
1822 if (left < m_state.exec.archetypeInheritedData.size() && right < m_state.exec.archetypeInheritedData.size()) {
1823 auto tmp = m_state.exec.archetypeInheritedData[left];
1824 m_state.exec.archetypeInheritedData[left] = m_state.exec.archetypeInheritedData[right];
1825 m_state.exec.archetypeInheritedData[right] = tmp;
1828 if (left < m_state.nonTrivial.archetypeBarrierPasses.size() &&
1829 right < m_state.nonTrivial.archetypeBarrierPasses.size()) {
1830 const auto tmp = m_state.nonTrivial.archetypeBarrierPasses[left];
1831 m_state.nonTrivial.archetypeBarrierPasses[left] = m_state.nonTrivial.archetypeBarrierPasses[right];
1832 m_state.nonTrivial.archetypeBarrierPasses[right] = tmp;
1838 if (!m_state.exec.compIndicesPending)
1841 m_state.exec.archetypeCompIndices.clear();
1842 m_state.exec.archetypeCompIndices.reserve(m_state.archetypeCache.size());
1843 for (
const auto* pArchetype: m_state.archetypeCache)
1846 m_state.exec.compIndicesPending =
false;
1871 const auto* pCompIndicesData = m_state.exec.archetypeCompIndices.data();
1872 const auto dataFieldsMatch = [&]() {
1873 if (m_state.exec.directChunksDataFieldCount != dataFieldCount)
1875 GAIA_FOR(dataFieldCount) {
1876 if (m_state.exec.directChunksDataFields[i] != pDataFields[i])
1882 const auto currWorldVersion = ::gaia::ecs::world_version(*
world());
1883 const auto currEnabledVersion = world_enabled_hierarchy_version(*
world());
1884 const auto currDeleteVersion = world_archetype_delete_version(*
world());
1885 if (m_state.exec.directChunksWorldVersion == currWorldVersion &&
1886 m_state.exec.directChunksEnabledVersion == currEnabledVersion &&
1887 m_state.exec.directChunksDeleteVersion == currDeleteVersion &&
1888 m_state.exec.directChunksResultRevision == m_state.resultCacheRevision &&
1889 m_state.exec.directChunksIdxFrom == idxFrom && m_state.exec.directChunksIdxTo == idxTo &&
1890 dataFieldsMatch() && m_state.exec.directChunksCompIndicesData == pCompIndicesData)
1893 m_state.exec.directChunks.clear();
1894 m_state.exec.directChunkData.clear();
1895 m_state.exec.directChunksIdxFrom = idxFrom;
1896 m_state.exec.directChunksIdxTo = idxTo;
1897 m_state.exec.directChunksDataFieldCount = dataFieldCount;
1898 GAIA_FOR(dataFieldCount) {
1899 m_state.exec.directChunksDataFields[i] = pDataFields[i];
1901 m_state.exec.directChunksResultRevision = m_state.resultCacheRevision;
1902 m_state.exec.directChunksWorldVersion = currWorldVersion;
1903 m_state.exec.directChunksEnabledVersion = currEnabledVersion;
1904 m_state.exec.directChunksDeleteVersion = currDeleteVersion;
1905 m_state.exec.directChunksCompIndicesData = pCompIndicesData;
1907 uint32_t chunkCnt = 0;
1908 for (uint32_t i = idxFrom; i < idxTo; ++i)
1909 chunkCnt += (uint32_t)m_state.archetypeCache[i]->chunks().size();
1910 m_state.exec.directChunks.reserve(chunkCnt);
1911 m_state.exec.directChunkData.reserve(chunkCnt * dataFieldCount);
1913 for (uint32_t i = idxFrom; i < idxTo; ++i) {
1914 const auto* pArchetype = m_state.archetypeCache[i];
1915 if (pArchetype->is_req_del())
1917 const auto* pCompIndices = m_state.exec.archetypeCompIndices[i].indices;
1918 for (
auto* pChunk: pArchetype->chunks()) {
1919 const auto from = detail::ChunkIterImpl::start_index(pChunk, Constraints::EnabledOnly);
1920 const auto to = detail::ChunkIterImpl::end_index(pChunk, Constraints::EnabledOnly);
1922 const void* pData =
nullptr;
1923 uint32_t dataOffset = UINT32_MAX;
1924 if (dataFieldCount == 1) {
1929 const auto dataFieldIdx = pDataFields[0];
1930 const auto compIdx =
1931 dataFieldIdx < ChunkHeader::MAX_COMPONENTS ? pCompIndices[dataFieldIdx] : uint8_t(0xFF);
1932 if (compIdx != 0xFF)
1933 pData = pChunk->comp_rec_view()[compIdx].pData;
1934 }
else if (dataFieldCount > 1) {
1935 dataOffset = (uint32_t)m_state.exec.directChunkData.size();
1936 const auto recs = pChunk->comp_rec_view();
1937 GAIA_FOR(dataFieldCount) {
1938 const auto dataFieldIdx = pDataFields[i];
1939 const auto compIdx =
1940 dataFieldIdx < ChunkHeader::MAX_COMPONENTS ? pCompIndices[dataFieldIdx] : uint8_t(0xFF);
1941 m_state.exec.directChunkData.push_back(compIdx != 0xFF ? recs[compIdx].pData :
nullptr);
1944 m_state.exec.directChunks.push_back({pArchetype, pChunk, pCompIndices, pData, dataOffset, from, to});
1958 if (!m_state.exec.inheritedDataPending)
1962 m_state.exec.archetypeInheritedData.clear();
1963 m_state.exec.inheritedDataPending =
false;
1967 m_state.exec.archetypeInheritedData.clear();
1968 m_state.exec.archetypeInheritedData.reserve(m_state.archetypeCache.size());
1969 for (
const auto* pArchetype: m_state.archetypeCache)
1972 m_state.exec.inheritedDataPending =
false;
1979 if (m_plan.ctx.data.groupBy == EntityBad || !m_state.grouped.dataPending)
1985 const auto groupCnt = (uint32_t)m_state.grouped.archetypeGroupIds.size();
1988 sortKeys.
resize(groupCnt);
1989 GAIA_FOR(groupCnt) {
1990 sortKeys[i] = ((uint64_t)m_state.grouped.archetypeGroupIds[i] << 32U) | i;
1994 bool operator()(uint64_t a, uint64_t b)
const {
1999 core::sort(sortKeys, sort_cond{}, [&](uint32_t left, uint32_t right) {
2000 const auto tmp = sortKeys[left];
2001 sortKeys[left] = sortKeys[right];
2002 sortKeys[right] = tmp;
2006 m_state.grouped.archetypeGroupData.clear();
2007 m_state.grouped.selectedGroupDataValid =
false;
2009 if (m_state.grouped.archetypeGroupIds.empty()) {
2010 m_state.grouped.dataPending =
false;
2014 GroupId groupId = m_state.grouped.archetypeGroupIds[0];
2015 uint32_t idxFirst = 0;
2016 const auto cnt = (uint32_t)m_state.grouped.archetypeGroupIds.size();
2017 for (uint32_t i = 1; i < cnt; ++i) {
2018 if (m_state.grouped.archetypeGroupIds[i] == groupId)
2021 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, i - 1,
false});
2022 groupId = m_state.grouped.archetypeGroupIds[i];
2026 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, cnt - 1,
false});
2027 m_state.grouped.dataPending =
false;
2032 if (!world_relation_depth_order_prunes_disabled_subtrees(*
world(), m_plan.ctx.data.groupBy))
2037 const auto currRelationVersion = world_rel_version(*
world(), m_plan.ctx.data.groupBy);
2038 const auto currEnabledVersion = world_enabled_hierarchy_version(*
world());
2039 if (m_state.nonTrivial.barrierRelVersion == currRelationVersion &&
2040 m_state.nonTrivial.barrierEnabledVersion == currEnabledVersion)
2043 m_state.nonTrivial.archetypeBarrierPasses.resize(m_state.archetypeCache.size(), 1);
2044 m_state.nonTrivial.barrierMayPrune = 0;
2046 const auto relation = m_plan.ctx.data.groupBy;
2047 for (uint32_t i = 0; i < m_state.archetypeCache.size(); ++i) {
2048 const auto* pArchetype = m_state.archetypeCache[i];
2049 auto& barrierPasses = m_state.nonTrivial.archetypeBarrierPasses[i];
2052 auto ids = pArchetype->ids_view();
2053 for (
auto idsIdx: pArchetype->pair_rel_indices(relation)) {
2054 const auto pair = ids[idsIdx];
2055 const auto parent = world_pair_target_if_alive(*
world(),
pair);
2056 if (parent == EntityBad || !world_entity_enabled_hierarchy(*
world(), parent, relation)) {
2058 m_state.nonTrivial.barrierMayPrune = 1;
2064 m_state.nonTrivial.barrierRelVersion = currRelationVersion;
2065 m_state.nonTrivial.barrierEnabledVersion = currEnabledVersion;
2073 core::fill(cacheData.indices, cacheData.indices + ChunkHeader::MAX_COMPONENTS, (uint8_t)0xFF);
2075 const auto cnt = (uint32_t)terms.size();
2077 const auto& term = terms[i];
2078 const auto fieldIdx = term.fieldIndex;
2079 const auto queryId = term.id;
2083 if (!query_term_maps_to_current_archetype(term))
2086 if (!queryId.pair() && world_component_uses_sparse_storage(*
world(), queryId)) {
2087#if GAIA_ASSERT_ENABLED
2089 const auto compIdx = core::get_index_unsafe(pArchetype->
ids_view(), queryId);
2090 GAIA_ASSERT(compIdx != BadIndex);
2092 cacheData.indices[fieldIdx] = 0xFF;
2096 auto compIdx = world_component_index_comp_idx(*
world(), *pArchetype, queryId);
2097 if (compIdx == BadIndex) {
2101 compIdx = core::get_index(pArchetype->
ids_view(), queryId);
2104 cacheData.indices[fieldIdx] = compIdx != BadIndex ? (uint8_t)compIdx : (uint8_t)0xFF;
2113 core::fill(inheritedData.data, inheritedData.data + ChunkHeader::MAX_COMPONENTS,
nullptr);
2116 const auto cnt = (uint32_t)terms.size();
2118 const auto& term = terms[i];
2119 if (term.src != EntityBad || term.entTrav != EntityBad || term_has_variables(term))
2121 if (term.matchKind != QueryMatchKind::Semantic)
2123 const auto queryId = term.id;
2124 if (queryId == EntityBad || is_wildcard(queryId) || is_variable((EntityId)queryId.id()))
2126 if (world_component_uses_sparse_storage(*
world(), queryId))
2128 if (!world_term_uses_inherit_policy(*
world(), queryId))
2130 if (pArchetype->
has(queryId))
2133 const auto owner = world_query_first_inherited_owner(*
world(), *pArchetype, queryId);
2134 GAIA_ASSERT(owner != EntityBad);
2135 inheritedData.data[term.fieldIndex] = world_query_inherited_arg_data_const_ptr(*
world(), owner, queryId);
2138 m_state.exec.archetypeInheritedData.push_back(inheritedData);
2145 m_state.resultCacheMayNeedPrefabFilter = 1;
2153 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
2154 GAIA_PROF_SCOPE(queryinfo::add_cache_ng);
2156 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
2158 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
2160 m_state.archetypeSet.emplace(pArchetype);
2161 m_state.archetypeCache.push_back(pArchetype);
2163 m_state.exec.compIndicesPending =
true;
2164 m_state.exec.inheritedDataPending =
true;
2165 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2166 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2167 if (trackMembershipChange)
2168 mark_result_cache_membership_changed();
2175 if (!assumeAbsent && m_state.seedArchetypeSet.contains(pArchetype))
2177 GAIA_ASSERT(assumeAbsent || !m_state.seedArchetypeSet.contains(pArchetype));
2179 m_state.seedArchetypeSet.emplace(pArchetype);
2180 m_state.seedArchetypeCache.push_back(pArchetype);
2187 GAIA_ASSERT(m_plan.ctx.data.groupBy == EntityBad);
2188 GAIA_ASSERT(m_plan.ctx.data.sortByFunc ==
nullptr);
2189 GAIA_ASSERT(!m_state.seedArchetypeSet.contains(pArchetype));
2190 GAIA_ASSERT(!m_state.archetypeSet.contains(pArchetype));
2192 m_state.seedArchetypeSet.emplace(pArchetype);
2193 m_state.seedArchetypeCache.push_back(pArchetype);
2195 m_state.archetypeSet.emplace(pArchetype);
2196 m_state.archetypeCache.push_back(pArchetype);
2198 m_state.exec.compIndicesPending =
true;
2199 m_state.exec.inheritedDataPending =
true;
2200 if (trackMembershipChange)
2201 mark_result_cache_membership_changed();
2209 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
2210 GAIA_PROF_SCOPE(queryinfo::add_cache_wg);
2212 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
2214 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
2216 m_state.grouped.selectedGroupDataValid =
false;
2218 const GroupId groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
2220 m_state.archetypeSet.emplace(pArchetype);
2221 m_state.archetypeCache.push_back(pArchetype);
2223 m_state.grouped.archetypeGroupIds.push_back(groupId);
2224 m_state.grouped.dataPending =
true;
2225 m_state.exec.compIndicesPending =
true;
2226 m_state.exec.inheritedDataPending =
true;
2227 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2228 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2230 if (trackMembershipChange)
2231 mark_result_cache_membership_changed();
2239 if (m_plan.ctx.data.sortByFunc !=
nullptr)
2242 if (m_plan.ctx.data.groupBy != EntityBad)
2251 m_state.archetypeCache.push_back(pArchetype);
2253 m_state.exec.compIndicesPending =
true;
2254 m_state.exec.inheritedDataPending =
true;
2255 if (m_plan.ctx.data.groupBy != EntityBad) {
2256 const auto groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
2257 m_state.grouped.archetypeGroupIds.push_back(groupId);
2258 m_state.grouped.dataPending =
true;
2268 if (m_plan.ctx.data.groupBy == EntityBad || runtimeGroupId == 0)
2271 if (!m_state.grouped.selectedGroupDataValid || m_state.grouped.selectedGroupData.groupId != runtimeGroupId) {
2273 uint32_t right = (uint32_t)m_state.grouped.archetypeGroupData.size();
2274 while (left < right) {
2275 const uint32_t mid = left + ((right - left) >> 1);
2276 const auto midGroupId = m_state.grouped.archetypeGroupData[mid].groupId;
2277 if (midGroupId < runtimeGroupId)
2283 if (left < m_state.grouped.archetypeGroupData.size() &&
2284 m_state.grouped.archetypeGroupData[left].groupId == runtimeGroupId) {
2285 m_state.grouped.selectedGroupData = m_state.grouped.archetypeGroupData[left];
2286 m_state.grouped.selectedGroupDataValid =
true;
2287 return &m_state.grouped.selectedGroupData;
2290 m_state.grouped.selectedGroupData = {};
2291 m_state.grouped.selectedGroupDataValid =
false;
2295 return &m_state.grouped.selectedGroupData;
2301 if (m_state.archetypeSet.size() != m_state.seedArchetypeSet.size())
2304 for (
const auto* pArchetype: m_state.seedArchetypeCache) {
2305 if (!m_state.archetypeSet.contains(pArchetype))
2316 if (m_state.archetypeSet.size() != archetypeCache.size())
2319 for (
const auto* pArchetype: archetypeCache) {
2320 if (!m_state.archetypeSet.contains(pArchetype))
2331 clear_result_cache();
2332 const auto cnt = (uint32_t)m_state.seedArchetypeCache.size();
2336 if (membershipChanged)
2337 mark_result_cache_membership_changed();
2344 const auto it = m_state.archetypeSet.find(pArchetype);
2345 if (it == m_state.archetypeSet.end())
2348 m_state.archetypeSet.erase(it);
2350 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2351 GAIA_ASSERT(archetypeIdx != BadIndex);
2352 if (archetypeIdx == BadIndex)
2355 if (m_plan.ctx.data.sortByFunc !=
nullptr)
2358 core::swap_erase(m_state.archetypeCache, archetypeIdx);
2359 if (archetypeIdx < m_state.exec.archetypeCompIndices.size())
2360 core::swap_erase(m_state.exec.archetypeCompIndices, archetypeIdx);
2361 if (archetypeIdx < m_state.exec.archetypeInheritedData.size())
2362 core::swap_erase(m_state.exec.archetypeInheritedData, archetypeIdx);
2363 if (archetypeIdx < m_state.grouped.archetypeGroupIds.size())
2364 core::swap_erase(m_state.grouped.archetypeGroupIds, archetypeIdx);
2365 if (archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size())
2366 core::swap_erase(m_state.nonTrivial.archetypeBarrierPasses, archetypeIdx);
2368 if (m_plan.ctx.data.groupBy != EntityBad) {
2369 m_state.grouped.selectedGroupDataValid =
false;
2370 m_state.grouped.archetypeGroupData.clear();
2371 m_state.grouped.dataPending =
true;
2374 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2375 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2377 mark_result_cache_membership_changed();
2385 const auto it = m_state.seedArchetypeSet.find(pArchetype);
2386 if (it == m_state.seedArchetypeSet.end())
2389 m_state.seedArchetypeSet.erase(it);
2391 const auto archetypeIdx = core::get_index(m_state.seedArchetypeCache, pArchetype);
2392 GAIA_ASSERT(archetypeIdx != BadIndex);
2393 if (archetypeIdx == BadIndex)
2396 core::swap_erase(m_state.seedArchetypeCache, archetypeIdx);
2403 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
2404 return const_cast<World*
>(m_plan.ctx.w);
2409 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
2410 return m_plan.ctx.w;
2416 return m_plan.ctx.q.ser_buffer(
world());
2420 m_plan.ctx.q.ser_buffer_reset(
world());
2437 return m_plan.vm.bytecode(*
world());
2443 return m_plan.vm.op_count();
2449 return m_plan.vm.op_signature();
2455 const auto& ctxData = m_plan.ctx.data;
2456 return ctxData.changedCnt > 0;
2462 const auto& ctxData = m_plan.ctx.data;
2469 const auto& ctxData = m_plan.ctx.data;
2476 return m_plan.ctx.data.directTargetEvalKind;
2482 return m_plan.ctx.data.directTargetEvalId;
2488 return m_plan.ctx.data.canDirectTargetEval;
2494 return m_plan.ctx.data.canDirectEntitySeedEvalShape;
2500 return m_plan.ctx.data.hasOnlyDirectOrTerms;
2506 const auto& ctxData = m_plan.ctx.data;
2514 template <
typename... T>
2516 return (has_inter<T>(QueryOpKind::Any) || ...);
2522 template <
typename... T>
2524 return (has_inter<T>(QueryOpKind::Or) || ...);
2530 template <
typename... T>
2532 return (has_inter<T>(QueryOpKind::All) && ...);
2538 template <
typename... T>
2540 return (!has_inter<T>(QueryOpKind::Not) && ...);
2546 GAIA_PROF_SCOPE(queryinfo::remove);
2556 const auto& ctxData = m_state.exec.archetypeCompIndices[archetypeIdx];
2557 return {ctxData.indices, ChunkHeader::MAX_COMPONENTS};
2566 std::span<const DirectChunkEntry>
2567 direct_chunk_view(uint32_t idxFrom, uint32_t idxTo,
const uint32_t* pDataFields, uint32_t dataFieldCount)
const {
2569 return {m_state.exec.directChunks.data(), m_state.exec.directChunks.size()};
2575 return {m_state.exec.directChunkData.data(), m_state.exec.directChunkData.size()};
2583 if (archetypeIdx >= m_state.exec.archetypeInheritedData.size())
2585 const auto& ctxData = m_state.exec.archetypeInheritedData[archetypeIdx];
2586 return {ctxData.data, ChunkHeader::MAX_COMPONENTS};
2595 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2596 if (archetypeIdx == BadIndex)
2609 if (m_state.exec.compIndicesPending)
2611 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2612 if (archetypeIdx == BadIndex)
2623 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2624 if (archetypeIdx == BadIndex)
2632 GAIA_NODISCARD GroupId
group_id(uint32_t archetypeIdx)
const {
2634 GAIA_ASSERT(archetypeIdx < m_state.grouped.archetypeGroupIds.size());
2635 return m_state.grouped.archetypeGroupIds[archetypeIdx];
2643 if (m_state.nonTrivial.archetypeBarrierPasses.empty())
2645 GAIA_ASSERT(archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size());
2646 return m_state.nonTrivial.archetypeBarrierPasses[archetypeIdx] != 0;
2653 return m_state.nonTrivial.barrierMayPrune != 0;
2658 GAIA_NODISCARD CArchetypeDArray::iterator
begin() {
2659 return m_state.archetypeCache.begin();
2664 GAIA_NODISCARD CArchetypeDArray::const_iterator
begin()
const {
2665 return m_state.archetypeCache.begin();
2670 GAIA_NODISCARD CArchetypeDArray::const_iterator
cbegin()
const {
2671 return m_state.archetypeCache.begin();
2676 GAIA_NODISCARD CArchetypeDArray::iterator
end() {
2677 return m_state.archetypeCache.end();
2682 GAIA_NODISCARD CArchetypeDArray::const_iterator
end()
const {
2683 return m_state.archetypeCache.end();
2688 GAIA_NODISCARD CArchetypeDArray::const_iterator
cend()
const {
2689 return m_state.archetypeCache.end();
2695 return std::span{(
const Archetype**)m_state.archetypeCache.data(), m_state.archetypeCache.size()};
2701 return std::span{m_state.nonTrivial.archetypeSortData.data(), m_state.nonTrivial.archetypeSortData.size()};
2708 return std::span{m_state.grouped.archetypeGroupData.data(), m_state.grouped.archetypeGroupData.size()};
2711#if GAIA_ECS_TEST_HOOKS
2717 GAIA_NODISCARD TestDynamicCacheKind test_dynamic_cache_kind()
const {
2718 return m_plan.ctx.data.dynamicCacheKind;
2722 GAIA_NODISCARD
bool test_uses_direct_src_version_tracking()
const {
2723 return m_plan.ctx.data.uses_direct_src_version_tracking();
2727 GAIA_NODISCARD
bool test_uses_src_trav_snapshot()
const {
2728 return m_plan.ctx.data.uses_src_trav_snapshot();
2733 GAIA_NODISCARD uint32_t test_match_pass_count()
const {
2734 return m_testMatchPassCount;
2738 GAIA_NODISCARD
static constexpr uint32_t test_query_info_size() {
2739 return (uint32_t)
sizeof(QueryInfo);
2743 GAIA_NODISCARD
static constexpr uint32_t test_query_plan_size() {
2744 return (uint32_t)
sizeof(QueryPlan);
2748 GAIA_NODISCARD
static constexpr uint32_t test_query_state_size() {
2749 return (uint32_t)
sizeof(QueryState);
2753 GAIA_NODISCARD
static constexpr uint32_t test_dynamic_cache_state_size() {
2754 return (uint32_t)
sizeof(QueryState::DynamicCacheState);
2758 GAIA_NODISCARD
static constexpr uint32_t test_query_state_dynamic_offset() {
2759 return (uint32_t)offsetof(QueryState, dynamic);
2764 void test_add_transient_archetype(
const Archetype* pArchetype) {
2765 GAIA_ASSERT(pArchetype !=
nullptr);
2766 if (pArchetype ==
nullptr)
2769 m_state.clear_transient_result_cache();
Array with variable size of elements of type.
Definition darray_impl.h:27
GAIA_NODISCARD size_type size() const noexcept
Returns the number of elements.
Definition darray_impl.h:504
void clear() noexcept
Removes all elements.
Definition darray_impl.h:449
GAIA_NODISCARD auto begin() noexcept
Returns an iterator to the first element.
Definition darray_impl.h:556
void resize(size_type count)
Changes the number of elements.
Definition darray_impl.h:240
void push_back(const T &arg)
Appends an element.
Definition darray_impl.h:309
GAIA_NODISCARD auto end() noexcept
Returns an iterator one past the last element.
Definition darray_impl.h:592
GAIA_NODISCARD ArchetypeId id() const
Archetype id used to address the archetype in the world list.
Definition archetype.h:72
Fixed-shape group of chunks storing entities that share the same component layout....
Definition archetype.h:97
GAIA_NODISCARD EntitySpan ids_view() const
Span over the component and entity identifiers defining the archetype shape.
Definition archetype.h:831
GAIA_NODISCARD bool has(Entity entity) const
Checks if an entity is a part of the archetype.
Definition archetype.h:892
void sort_entities(Entity entity, TSortByFunc func)
Sorts all entities in the archetypes according to the given function.
Definition archetype.h:1079
Fixed-capacity archetype storage unit holding entities and their component columns.
Definition chunk.h:36
Compiled query plan and its incrementally maintained result caches.
Definition query_info.h:131
void ensure_inherited_data()
Rebuilds inherited-data payloads for matched archetypes when query terms require them.
Definition query_info.h:1957
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:2186
GAIA_NODISCARD CArchetypeDArray::const_iterator begin() const
Returns an iterator to the first cached result archetype.
Definition query_info.h:2664
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:1805
bool ensure_matches_one_transient(const Archetype &archetype, EntitySpan targetEntities, const cnt::sarray< Entity, MaxVarCnt > &runtimeVarBindings, uint8_t runtimeVarBindingMask)
Rebuilds transient result membership by evaluating one target archetype.
Definition query_info.h:1490
GAIA_NODISCARD std::span< const GroupData > group_data_view() const
Returns cached group ranges, rebuilding grouped data when needed.
Definition query_info.h:2706
GAIA_NODISCARD GroupId group_id(uint32_t archetypeIdx) const
Returns the cached group id for a matched archetype index.
Definition query_info.h:2632
GAIA_NODISCARD bool has_no() const
Returns true when none of the requested types is present as a Not term.
Definition query_info.h:2539
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:2493
void sort_entities()
Applies query entity sorting and rebuilds sorted chunk slices when needed.
Definition query_info.h:1775
bool ensure_matches_one(const Archetype &archetype, EntitySpan targetEntities, const cnt::sarray< Entity, MaxVarCnt > &runtimeVarBindings, uint8_t runtimeVarBindingMask)
Ensures persistent result membership for one target archetype.
Definition query_info.h:1478
GAIA_NODISCARD const World * world() const
Returns the world owning this query.
Definition query_info.h:2408
void ensure_matches(const EntityToArchetypeMap &entityToArchetypeMap, std::span< const Archetype * > allArchetypes, const EntityToArchetypeVersionMap &entityToArchetypeMapVersions, ArchetypeId archetypeLastId, const cnt::sarray< Entity, MaxVarCnt > &runtimeVarBindings, uint8_t runtimeVarBindingMask)
Refreshes persistent query matches when cache state or world archetypes changed.
Definition query_info.h:1410
void remove(Archetype *pArchetype)
Removes an archetype from cache.
Definition query_info.h:2545
void reset()
Resets cached query state for slot reuse while keeping the compiled context object.
Definition query_info.h:980
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:2499
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:1661
GAIA_NODISCARD bool barrier_may_prune() const
Returns true when any cached archetype can be pruned by the hierarchy barrier.
Definition query_info.h:2651
GAIA_NODISCARD bool has_or() const
Returns true when any of the requested types is present as an Or term.
Definition query_info.h:2523
void recompile()
Recompile the query.
Definition query_info.h:1086
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:2641
GAIA_NODISCARD util::str bytecode() const
Returns a textual dump of the compiled VM bytecode.
Definition query_info.h:2436
MatchArchetypeQueryRet
Result of evaluating one archetype for cache insertion.
Definition query_info.h:140
@ Skip
Archetype requires no cache action for this evaluation path.
@ Ok
Archetype satisfies the query and should be cached.
@ Fail
Archetype does not satisfy the query.
GAIA_NODISCARD std::span< const Archetype * > cache_archetype_view() const
Returns the cached result archetypes as a span.
Definition query_info.h:2694
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:1143
GAIA_NODISCARD bool has_inherited_data_payload() const
Returns true when query iteration needs cached inherited data payloads.
Definition query_info.h:1952
GAIA_NODISCARD bool operator!=(const QueryCtx &other) const
Compares this compiled plan with an authored query context for inequality.
Definition query_info.h:1172
GAIA_NODISCARD uint32_t result_cache_rev() const
Returns the result membership revision used by reverse-index cache users.
Definition query_info.h:1131
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:1047
void group_ids(Container &out, bool sortGroups)
Collects the query's active non-zero group ids.
Definition query_info.h:1110
void init(World *world)
Binds this query info to a world after slot allocation.
Definition query_info.h:975
GAIA_NODISCARD bool result_cache_may_need_prefab_filter() const
Returns true when the result cache contains archetypes that need default prefab filtering.
Definition query_info.h:1137
bool del_archetype_from_cache(const Archetype *pArchetype)
Removes an archetype from the final result cache and mirrored payload arrays.
Definition query_info.h:2343
GAIA_NODISCARD QuerySerBuffer & ser_buffer()
Returns the query serialization buffer associated with the owning world.
Definition query_info.h:2415
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:2608
GAIA_NODISCARD bool matches_prefab_entities() const
Returns true when prefab-tagged entities should participate in query results.
Definition query_info.h:2505
void invalidate_sort()
Marks the cached sorted slices dirty without invalidating query membership.
Definition query_info.h:1012
void create_inherited_data(const Archetype *pArchetype)
Builds inherited component data pointers for semantic self-source terms on one archetype.
Definition query_info.h:2111
bool del_archetype_from_seed_cache(const Archetype *pArchetype)
Removes an archetype from the structural seed cache.
Definition query_info.h:2384
void add_archetype_to_seed_cache(const Archetype *pArchetype, bool assumeAbsent=false)
Adds an archetype to the structural seed cache.
Definition query_info.h:2174
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:1544
InvalidationKind
Cache layer invalidated after query inputs or world state change.
Definition query_info.h:185
@ 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:2688
std::span< const void *const > direct_chunk_data_view() const
Returns cached flattened direct chunk data pointers.
Definition query_info.h:2574
InheritedTermDataView inherited_data_view(uint32_t archetypeIdx) const
Returns cached inherited-term data for a matched archetype index.
Definition query_info.h:2581
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:135
void ser_buffer_reset()
Resets the query serialization buffer associated with the owning world.
Definition query_info.h:2419
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:1157
void ensure_comp_indices()
Rebuilds cached component-index payloads for matched archetypes when marked pending.
Definition query_info.h:1837
GAIA_NODISCARD QueryCtx::CachePolicy cache_policy() const
Returns the query cache policy selected during compilation.
Definition query_info.h:1095
void ensure_direct_chunks(uint32_t idxFrom, uint32_t idxTo, const uint32_t *pDataFields, uint32_t dataFieldCount)
Rebuilds flattened direct chunk cache when result membership, world structure, selected rows,...
Definition query_info.h:1869
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:1208
GAIA_NODISCARD bool has_filters() const
Returns true when the query has per-entity changed/filter terms.
Definition query_info.h:2454
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:1078
GAIA_NODISCARD std::span< const SortData > cache_sort_view() const
Returns cached sorted chunk slices.
Definition query_info.h:2700
GAIA_NODISCARD bool has_grouped_payload() const
Returns true when grouped-query payloads are active for this query.
Definition query_info.h:1101
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:1151
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:2468
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:2031
GAIA_NODISCARD World * world()
Returns the mutable world owning this query.
Definition query_info.h:2402
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:2329
GAIA_NODISCARD bool has_all() const
Returns true when all requested types are present as All terms.
Definition query_info.h:2531
GAIA_NODISCARD bool operator==(const QueryCtx &other) const
Compares this compiled plan with an authored query context.
Definition query_info.h:1165
GAIA_NODISCARD CArchetypeDArray::iterator end()
Returns a mutable iterator past the last cached result archetype.
Definition query_info.h:2676
GAIA_NODISCARD Entity direct_target_eval_id() const
Returns the concrete direct target id used by direct target evaluation.
Definition query_info.h:2481
void add_ref()
Adds one external reference to this query slot.
Definition query_info.h:956
void invalidate_result()
Marks final result matches stale while preserving structural seed matches.
Definition query_info.h:1007
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:1332
GAIA_NODISCARD bool has_sorted_payload() const
Returns true when sorted-query payloads are active for this query.
Definition query_info.h:1125
GAIA_NODISCARD bool has_entity_filter_terms() const
Returns true when direct non-fragmenting terms must be rechecked per entity.
Definition query_info.h:2461
void sort_cache_groups()
Sorts cached archetypes by group id when grouped iteration requested ordering.
Definition query_info.h:1793
GAIA_NODISCARD CArchetypeDArray::const_iterator end() const
Returns an iterator past the last cached result archetype.
Definition query_info.h:2682
uint32_t gen
Generation ID of the query slot.
Definition query_info.h:137
std::span< const DirectChunkEntry > direct_chunk_view(uint32_t idxFrom, uint32_t idxTo, const uint32_t *pDataFields, uint32_t dataFieldCount) const
Returns a flattened chunk view for a direct-dense result-cache range.
Definition query_info.h:2567
GAIA_NODISCARD bool has_any() const
Returns true when any of the requested types is present as an Any term.
Definition query_info.h:2515
GAIA_NODISCARD uint32_t op_count() const
Returns the number of VM operations in the compiled query.
Definition query_info.h:2442
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:2315
GAIA_NODISCARD CArchetypeDArray::const_iterator cbegin() const
Returns a const iterator to the first cached result archetype.
Definition query_info.h:2670
uint32_t refs() const
Returns the current external reference count.
Definition query_info.h:969
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:2238
GAIA_NODISCARD QueryCtx & ctx()
Returns the mutable compiled query context.
Definition query_info.h:2425
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:2554
static GAIA_NODISCARD QueryHandle handle(const QueryInfo &info)
Builds a stable query handle from query slot metadata.
Definition query_info.h:1071
GAIA_NODISCARD CArchetypeDArray::iterator begin()
Returns a mutable iterator to the first cached result archetype.
Definition query_info.h:2658
void ensure_matches_transient(const EntityToArchetypeMap &entityToArchetypeMap, std::span< const Archetype * > allArchetypes, const EntityToArchetypeVersionMap &entityToArchetypeMapVersions, const cnt::sarray< Entity, MaxVarCnt > &runtimeVarBindings, uint8_t runtimeVarBindingMask)
Rebuilds transient result membership without retaining persistent seed-cache state.
Definition query_info.h:1425
void invalidate_seed()
Marks structural seed matches stale.
Definition query_info.h:1002
GAIA_NODISCARD uint64_t op_signature() const
Returns a stable signature for the compiled VM operation stream.
Definition query_info.h:2448
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:2300
void ensure_depth_order_hierarchy_barrier_cache()
Ensures depth-order hierarchy barrier results are current before public reads.
Definition query_info.h:2602
ArchetypeCompIndices create_comp_indices(const Archetype *pArchetype)
Builds field-to-archetype component indices for one matched archetype.
Definition query_info.h:2071
void invalidate(InvalidationKind kind=InvalidationKind::All)
Marks cached query results stale.
Definition query_info.h:986
void ensure_group_data(bool orderGroups)
Rebuilds grouped archetype ranges when a caller needs ordered group data.
Definition query_info.h:1978
GAIA_NODISCARD const QueryCtx & ctx() const
Returns the compiled query context.
Definition query_info.h:2430
void update_result_cache_prefab_filter_state(const Archetype *pArchetype)
Records whether pArchetype requires the default prefab filter during result-cache iteration.
Definition query_info.h:2143
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:2208
GAIA_NODISCARD bool can_direct_target_eval() const
Returns true when the query can evaluate concrete target entities directly.
Definition query_info.h:2487
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:2620
InheritedTermDataView inherited_data_view(const Archetype *pArchetype) const
Returns cached inherited-term data for a matched archetype pointer.
Definition query_info.h:2592
GAIA_NODISCARD QueryCtx::DirectTargetEvalKind direct_target_eval_kind() const
Returns the direct target evaluation mode selected during compilation.
Definition query_info.h:2475
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:2266
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:2250
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:2152
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:1023
void dec_ref()
Releases one external reference to this query slot.
Definition query_info.h:962
Owns entities, components, archetypes, queries, observers, and systems.
Definition world.h:80
Wrapper for two Entities forming a relationship pair.
Definition id.h:614
Wrapper for two types forming a relationship pair. Depending on what types are used to form a pair it...
Definition id.h:262
Compiles query terms into matching bytecode and evaluates that bytecode against archetypes....
Definition vm.h:2343
Same API as ser_buffer_binary, but backed by fully dynamic storage.
Definition ser_buffer_binary.h:161
Query-field to archetype-component column mapping for one matched archetype.
Definition query_info.h:36
uint8_t indices[ChunkHeader::MAX_COMPONENTS]
Component column per query field, with invalid entries encoded by the mapping builder.
Definition query_info.h:38
Cached inherited component data pointers for one matched archetype.
Definition query_info.h:42
const void * data[ChunkHeader::MAX_COMPONENTS]
Component data pointer per query field, or null when the field is not inherited.
Definition query_info.h:44
One archetype record stored in the entity-to-archetype reverse index.
Definition query_common.h:175
Cached archetype/chunk pair used by repeated direct-dense scans over highly fragmented result caches.
Definition query_info.h:48
const uint8_t * pCompIndices
Prepared query-field to chunk-column mapping for pArchetype, or null when not available.
Definition query_info.h:54
const void * pData
Cached base data pointer for the common single selected field, or null when unavailable/not single-fi...
Definition query_info.h:56
uint32_t dataOffset
Offset into ExecPayload::directChunkData for this entry, or UINT32_MAX when no pointers are cached.
Definition query_info.h:58
Chunk * pChunk
Chunk supplying entity and component rows.
Definition query_info.h:52
uint16_t rowFrom
First enabled row in pChunk processed by direct-dense iteration.
Definition query_info.h:60
const Archetype * pArchetype
Archetype owning the chunk.
Definition query_info.h:50
uint16_t rowTo
One-past-the-end enabled row in pChunk processed by direct-dense iteration.
Definition query_info.h:62
Hashmap lookup structure used for Entity.
Definition id.h:543
Identifier of an entity or component instance in the world. Packs the entity index,...
Definition id.h:296
GAIA_NODISCARD bool has_dep_flag(DependencyFlags dependency) const
Tests whether a dependency fact was recorded.
Definition query_common.h:1065
GAIA_NODISCARD std::span< const QueryTerm > terms_view() const
Returns compiled terms in execution order.
Definition query_common.h:1270
Dependencies deps
Explicit dependency metadata derived from query shape.
Definition query_common.h:1170
Authored and compiled state defining query identity and execution behavior.
Definition query_common.h:885
struct gaia::ecs::QueryCtx::Data data
Compiled query payload.
@ HasPrefabTerms
Query explicitly mentions Prefab and therefore bypasses automatic exclusion.
Definition query_common.h:914
@ SortGroups
Cached group ranges require sorting.
Definition query_common.h:902
@ MatchPrefab
Includes prefab entities without requiring an explicit Prefab term.
Definition query_common.h:912
@ SortEntities
Cached entity slices require sorting.
Definition query_common.h:900
@ OrderGroups
Grouped archetypes are ordered by group identifier during cache refresh.
Definition query_common.h:916
@ Recompile
VM opcode recompilation is pending.
Definition query_common.h:906
@ DependencyHasSourceTerms
At least one term uses a fixed source entity.
Definition query_common.h:972
@ DependencyHasEntityFilterTerms
At least one term requires per-entity filtering.
Definition query_common.h:990
@ DependencyHasVariableTerms
At least one term contains a runtime variable.
Definition query_common.h:974
@ DependencyHasPotentialInheritedIdTerms
A term shape may resolve through inherited-id matching.
Definition query_common.h:994
@ DependencyHasInheritedDataTerms
Iteration requires cached inherited component pointers.
Definition query_common.h:992
@ DependencyHasTraversalTerms
At least one source term traverses a relation.
Definition query_common.h:988
@ DirectStructuralTerms
Evaluates a small immediate ALL, OR, and NOT query directly on the archetype.
DirectTargetEvalKind
Specialized evaluation shape for concrete target entities.
Definition query_common.h:954
DynamicCacheKind
Dynamic-cache dependency shape derived from compiled query metadata.
Definition query_common.h:938
@ 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.
CachePolicy
Strategy used to maintain cached archetype matches.
Definition query_common.h:920
@ Immediate
Updates a structural query immediately when an archetype is created.
@ Dynamic
Repairs source- or variable-dependent cached state on demand.
Stable query-slot identifier combining a slot index and generation.
Definition query_common.h:356
Inputs passed through query-slot allocation to construct a QueryInfo instance.
Definition query_info.h:121
const EntityToArchetypeMap * pEntityToArchetypeMap
World reverse index used to compile initial archetype matching operations.
Definition query_info.h:125
std::span< const Archetype * > allArchetypes
Archetypes present in the world when the query is compiled.
Definition query_info.h:127
QueryCtx * pQueryCtx
Authored query context transferred into the allocated slot.
Definition query_info.h:123
Scope guard that releases the world-owned temporary VM matching frame.
Definition query_info.h:1177
CleanUpTmpArchetypeMatches(World &world, bool keepStamps)
Creates a guard for an already acquired matching frame.
Definition query_info.h:1186
bool keepStamps
True to retain allocated dedup-stamp pages while releasing the frame.
Definition query_info.h:1181
World & world
World owning the acquired scratch frame.
Definition query_info.h:1179
Direct concrete-source payload for reusable dynamic caches.
Definition query_info.h:393
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:401
cnt::sarray< uint32_t, MAX_ITEMS_IN_QUERY > entityVersions
Last seen archetype versions for tracked direct concrete source entities.
Definition query_info.h:395
void snapshot(const World &world, std::span< const Entity > sourceEntities)
Captures current source entity archetype versions.
Definition query_info.h:414
Relation-version payload for reusable dynamic caches with relation dependencies.
Definition query_info.h:364
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:372
cnt::sarray< uint32_t, MAX_ITEMS_IN_QUERY > versions
Last seen versions for tracked dynamic relation dependencies.
Definition query_info.h:366
void snapshot(const World &world, std::span< const Entity > relations)
Captures current relation versions.
Definition query_info.h:385
Traversed-source payload for reusable dynamic caches with source traversal.
Definition query_info.h:422
void mark_overflowed()
Marks the traversed-source snapshot as overflowed and unusable for reuse.
Definition query_info.h:490
uint32_t enabledVersion
Entity enable-state version captured with the traversed-source closure.
Definition query_info.h:426
void clear()
Clears traversed-source snapshot state.
Definition query_info.h:431
GAIA_NODISCARD bool changed(const World &world, const cnt::darray< SrcTravSnapshotItem > &items) const
Returns true when a rebuilt traversed-source closure differs from the captured snapshot.
Definition query_info.h:464
GAIA_NODISCARD bool versions_changed(const World &world) const
Returns true when any tracked traversed source entity changed archetype.
Definition query_info.h:446
cnt::darray< SrcTravSnapshotItem > snapshot
Last seen traversed-source closure for reusable source queries.
Definition query_info.h:424
GAIA_NODISCARD bool is_overflowed() const
Returns true when the traversed-source snapshot is unusable for reuse.
Definition query_info.h:439
void capture(const World &world, const cnt::darray< SrcTravSnapshotItem > &items)
Captures a newly built traversed-source closure snapshot.
Definition query_info.h:483
bool overflowed
True when the traversed source closure exceeded the configured snapshot cap.
Definition query_info.h:428
Variable-binding payload for reusable dynamic caches with runtime variables.
Definition query_info.h:498
cnt::sarray< Entity, MaxVarCnt > bindings
Snapshot of runtime variable bindings used to build the current dynamic cache.
Definition query_info.h:500
uint8_t bindingMask
Bitmask of the variable bindings captured in bindings.
Definition query_info.h:502
void clear()
Clears runtime variable binding snapshot state.
Definition query_info.h:505
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:514
void snapshot(const cnt::sarray< Entity, MaxVarCnt > &runtimeBindings, uint8_t runtimeBindingMask)
Captures runtime variable bindings.
Definition query_info.h:535
Runtime dependency snapshots used to validate reusable dynamic results.
Definition query_info.h:362
DirectSourcePayload directSource
Direct concrete-source payload.
Definition query_info.h:544
TraversedSourcePayload traversedSource
Traversed-source closure payload.
Definition query_info.h:546
VariablePayload variable
Runtime variable-binding payload.
Definition query_info.h:548
RelationPayload relation
Relation-version payload.
Definition query_info.h:542
void clear_input_snapshots()
Clears transient dynamic input snapshot state while preserving fixed-size version snapshots.
Definition query_info.h:551
Component mappings and flattened chunks prepared for query iteration.
Definition query_info.h:246
void clear()
Releases execution payload storage and clears pending rebuild flags.
Definition query_info.h:281
bool inheritedDataPending
True when archetype membership is populated but inherited-term data still needs to be built on demand...
Definition query_info.h:278
cnt::darray< DirectChunkEntry > directChunks
Flattened chunk cache for read-only direct dense iteration over highly fragmented result caches.
Definition query_info.h:252
void clear_transient()
Clears execution payload contents while preserving allocated storage.
Definition query_info.h:299
bool compIndicesPending
True when archetype membership is populated but component-index metadata still needs to be built on d...
Definition query_info.h:275
uint32_t directChunksIdxTo
One-past-the-end result-cache archetype index captured when directChunks was built.
Definition query_info.h:266
uint32_t directChunksDataFieldCount
Number of valid entries in directChunksDataFields.
Definition query_info.h:270
uint32_t directChunksResultRevision
Result membership revision captured when directChunks was built.
Definition query_info.h:262
cnt::darray< ArchetypeCompIndices > archetypeCompIndices
Cached component-index mapping for each matched archetype.
Definition query_info.h:248
uint32_t directChunksDeleteVersion
Archetype deletion-request version captured when directChunks was built.
Definition query_info.h:260
const void * directChunksCompIndicesData
Component-index mapping storage captured by DirectChunkEntry::pCompIndices pointers.
Definition query_info.h:272
cnt::darray< ArchetypeInheritedData > archetypeInheritedData
Cached inherited component data pointer per query field for exact self-source semantic terms.
Definition query_info.h:250
uint32_t directChunksEnabledVersion
Enabled hierarchy version captured when directChunks was built.
Definition query_info.h:258
uint32_t directChunksWorldVersion
World version captured when directChunks was built.
Definition query_info.h:256
uint32_t directChunksIdxFrom
First result-cache archetype index captured when directChunks was built.
Definition query_info.h:264
cnt::darray< const void * > directChunkData
Contiguous cached component data pointers for DirectChunkEntry pointer blocks.
Definition query_info.h:254
uint32_t directChunksDataFields[MAX_ITEMS_IN_QUERY]
Query fields whose component data pointers were captured in DirectChunkEntry pointer blocks.
Definition query_info.h:268
Storage used only by grouped query result caches.
Definition query_info.h:214
cnt::darray< GroupData > archetypeGroupData
Group data used by cache.
Definition query_info.h:218
void clear_transient()
Clears grouped payload contents while preserving allocated storage.
Definition query_info.h:236
void clear()
Releases grouped payload storage and resets cached group selection state.
Definition query_info.h:227
bool selectedGroupDataValid
True when selectedGroupData matches the active group filter.
Definition query_info.h:222
GroupData selectedGroupData
Cached range for the currently selected group id.
Definition query_info.h:220
cnt::darray< GroupId > archetypeGroupIds
Group ids for grouped queries, aligned with archetypeCache.
Definition query_info.h:216
bool dataPending
True when grouped archetype order/ranges need to be rebuilt.
Definition query_info.h:224
Sorting and hierarchy-barrier state for nontrivial iteration paths.
Definition query_info.h:318
uint8_t barrierMayPrune
True when at least one cached archetype fails the depth-order hierarchy barrier.
Definition query_info.h:331
uint32_t barrierEnabledVersion
Entity enable-state version at which the cached depth-order hierarchy barrier state was last rebuilt.
Definition query_info.h:329
cnt::darray< uint8_t > archetypeBarrierPasses
Cached depth-order hierarchy barrier result for each archetype.
Definition query_info.h:320
cnt::darray< SortData > archetypeSortData
Sort data used by cache.
Definition query_info.h:322
void clear_transient()
Clears nontrivial payload contents while preserving allocated storage.
Definition query_info.h:344
uint32_t barrierRelVersion
Relation topology version at which the cached depth-order hierarchy barrier state was last rebuilt.
Definition query_info.h:327
void clear()
Releases nontrivial execution payload storage and resets version stamps.
Definition query_info.h:334
uint32_t sortVersion
World version at which the sorted cache slices were last rebuilt. Unlike worldVersion,...
Definition query_info.h:325
Temporary VM matching buffer meant to be owned by an ECS World. QueryInfo only acquires a frame while...
Definition query_info.h:67
cnt::darr< const Archetype * > matchesArr
Ordered list of matched archetypes emitted by the VM for the current run.
Definition query_info.h:71
void clear_temporary_matches()
Clears all temporary match data, including dedup stamps.
Definition query_info.h:83
uint32_t matchVersion
Monotonic dedup stamp used when the same scratch frame is reused by later full match() calls without ...
Definition query_info.h:80
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:93
cnt::darray< const Archetype * > matchesArrDynPrev
Previous result membership used when a dynamic rebuild compares reverse-index changes.
Definition query_info.h:77
ArchetypeMatchStamps matchStamps
Paged O(1) dedup table keyed by world-local archetype ids. Pages stay allocated on the scratch frame ...
Definition query_info.h:75
GAIA_NODISCARD uint32_t next_match_version()
Advances and returns the dedup stamp for the next VM match pass.
Definition query_info.h:106
void reset_stamps()
Clears dedup stamps and resets the match-version counter.
Definition query_info.h:99
One lookup-key record collected while indexing a single archetype.
Definition query_common.h:333
static constexpr bool value
True when the type derives from the pair base.
Definition id.h:287
Mutable execution context used while matching query bytecode.
Definition vm.h:88
Lightweight owning string container with explicit length semantics (no implicit null terminator).
Definition str.h:332