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, AllDirty = 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::AllDirty;
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::AllDirty;
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::AllDirty;
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 rel =
Entity((EntityId)entity.id(), 0,
false,
false);
1626 const auto tgt =
Entity((EntityId)entity.gen(), 0,
false,
false);
1627 addLookupUnique(
Pair(
All, tgt), ComponentIndexBad, 1);
1628 addLookupUnique(
Pair(rel,
All), ComponentIndexBad, 1);
1629 addLookupUnique(
Pair(
All,
All), ComponentIndexBad, 1);
1632 auto lastMatchedArchetypeIdx_All = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_All);
1633 auto lastMatchedArchetypeIdx_Or = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Or);
1634 auto lastMatchedArchetypeIdx_Not = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Not);
1635 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_All.empty());
1636 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Or.empty());
1637 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Not.empty());
1639 const auto* pArchetype = &archetype;
1642 singleArchetypeLookup, std::span((
const Archetype**)&pArchetype, 1),
nullptr, archetype.
id(),
1643 noRuntimeVarBindings, 0);
1644 ctxData.lastMatchedArchetypeIdx_All = GAIA_MOV(lastMatchedArchetypeIdx_All);
1645 ctxData.lastMatchedArchetypeIdx_Or = GAIA_MOV(lastMatchedArchetypeIdx_Or);
1646 ctxData.lastMatchedArchetypeIdx_Not = GAIA_MOV(lastMatchedArchetypeIdx_Not);
1647 const bool matched = assumeNew ? m_state.archetypeSet.contains(&archetype)
1648 : !hadMatchBefore && m_state.archetypeSet.contains(&archetype);
1661 GAIA_PROF_SCOPE(queryinfo::calc_sort_data);
1663 m_state.nonTrivial.archetypeSortData.clear();
1681 uint32_t chunkIdx = 0;
1685 auto& archetypes = m_state.archetypeCache;
1690 uint32_t currArchetypeIdx = (uint32_t)-1;
1691 Chunk* pCurrentChunk =
nullptr;
1692 uint16_t currentStartRow = 0;
1693 uint16_t currentRow = 0;
1695 const void* pDataMin =
nullptr;
1696 const void* pDataCurr =
nullptr;
1699 uint32_t minArchetypeIdx = (uint32_t)-1;
1700 Entity minEntity = EntityBad;
1703 for (uint32_t t = 0; t < archetypes.size(); ++t) {
1704 const auto* pArchetype = archetypes[t];
1705 const auto& chunks = pArchetype->chunks();
1706 auto& cur = cursors[t];
1708 while (cur.chunkIdx < chunks.size() && cur.row >= chunks[cur.chunkIdx]->size()) {
1713 if (cur.chunkIdx >= chunks.size())
1716 const auto* pChunk = pArchetype->chunks()[cur.chunkIdx];
1717 auto entity = pChunk->entity_view()[cur.row];
1719 if (m_plan.ctx.data.sortBy != ecs::EntityBad) {
1720 auto compIdx = world_component_index_comp_idx(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.sortBy);
1721 if (compIdx == BadIndex)
1722 compIdx = pChunk->comp_idx(m_plan.ctx.data.sortBy);
1723 pDataCurr = pChunk->comp_ptr(compIdx, cur.row);
1725 pDataCurr = &pChunk->entity_view()[cur.row];
1727 if (minEntity == EntityBad) {
1729 minArchetypeIdx = t;
1730 pDataMin = pDataCurr;
1734 if (m_plan.ctx.data.sortByFunc(*m_plan.ctx.w, pDataCurr, pDataMin) < 0) {
1736 minArchetypeIdx = t;
1741 if (minArchetypeIdx == (uint32_t)-1)
1744 auto& cur = cursors[minArchetypeIdx];
1745 const auto& chunks = archetypes[minArchetypeIdx]->chunks();
1746 Chunk* pChunk = chunks[cur.chunkIdx];
1748 if (minArchetypeIdx == currArchetypeIdx && pChunk == pCurrentChunk) {
1752 if (pCurrentChunk !=
nullptr) {
1753 m_state.nonTrivial.archetypeSortData.push_back(
1754 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1758 currArchetypeIdx = minArchetypeIdx;
1759 pCurrentChunk = pChunk;
1760 currentStartRow = cur.row;
1764 currentRow = cur.row;
1767 if (pCurrentChunk !=
nullptr) {
1768 m_state.nonTrivial.archetypeSortData.push_back(
1769 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1775 if (m_plan.ctx.data.sortByFunc ==
nullptr)
1783 for (
const auto* pArchetype: m_state.archetypeCache)
1788 m_state.nonTrivial.sortVersion = ::gaia::ecs::world_version(*
world());
1805 auto* pTmpArchetype = m_state.archetypeCache[left];
1806 m_state.archetypeCache[left] = m_state.archetypeCache[right];
1807 m_state.archetypeCache[right] = pTmpArchetype;
1809 if (left < m_state.grouped.archetypeGroupIds.size() && right < m_state.grouped.archetypeGroupIds.size()) {
1810 const auto tmp = m_state.grouped.archetypeGroupIds[left];
1811 m_state.grouped.archetypeGroupIds[left] = m_state.grouped.archetypeGroupIds[right];
1812 m_state.grouped.archetypeGroupIds[right] = tmp;
1815 if (left < m_state.exec.archetypeCompIndices.size() && right < m_state.exec.archetypeCompIndices.size()) {
1816 auto tmp = m_state.exec.archetypeCompIndices[left];
1817 m_state.exec.archetypeCompIndices[left] = m_state.exec.archetypeCompIndices[right];
1818 m_state.exec.archetypeCompIndices[right] = tmp;
1821 if (left < m_state.exec.archetypeInheritedData.size() && right < m_state.exec.archetypeInheritedData.size()) {
1822 auto tmp = m_state.exec.archetypeInheritedData[left];
1823 m_state.exec.archetypeInheritedData[left] = m_state.exec.archetypeInheritedData[right];
1824 m_state.exec.archetypeInheritedData[right] = tmp;
1827 if (left < m_state.nonTrivial.archetypeBarrierPasses.size() &&
1828 right < m_state.nonTrivial.archetypeBarrierPasses.size()) {
1829 const auto tmp = m_state.nonTrivial.archetypeBarrierPasses[left];
1830 m_state.nonTrivial.archetypeBarrierPasses[left] = m_state.nonTrivial.archetypeBarrierPasses[right];
1831 m_state.nonTrivial.archetypeBarrierPasses[right] = tmp;
1837 if (!m_state.exec.compIndicesPending)
1840 m_state.exec.archetypeCompIndices.clear();
1841 m_state.exec.archetypeCompIndices.reserve(m_state.archetypeCache.size());
1842 for (
const auto* pArchetype: m_state.archetypeCache)
1845 m_state.exec.compIndicesPending =
false;
1870 const auto* pCompIndicesData = m_state.exec.archetypeCompIndices.data();
1871 const auto dataFieldsMatch = [&]() {
1872 if (m_state.exec.directChunksDataFieldCount != dataFieldCount)
1874 GAIA_FOR(dataFieldCount) {
1875 if (m_state.exec.directChunksDataFields[i] != pDataFields[i])
1881 const auto currWorldVersion = ::gaia::ecs::world_version(*
world());
1882 const auto currEnabledVersion = world_enabled_hierarchy_version(*
world());
1883 const auto currDeleteVersion = world_archetype_delete_version(*
world());
1884 if (m_state.exec.directChunksWorldVersion == currWorldVersion &&
1885 m_state.exec.directChunksEnabledVersion == currEnabledVersion &&
1886 m_state.exec.directChunksDeleteVersion == currDeleteVersion &&
1887 m_state.exec.directChunksResultRevision == m_state.resultCacheRevision &&
1888 m_state.exec.directChunksIdxFrom == idxFrom && m_state.exec.directChunksIdxTo == idxTo &&
1889 dataFieldsMatch() && m_state.exec.directChunksCompIndicesData == pCompIndicesData)
1892 m_state.exec.directChunks.clear();
1893 m_state.exec.directChunkData.clear();
1894 m_state.exec.directChunksIdxFrom = idxFrom;
1895 m_state.exec.directChunksIdxTo = idxTo;
1896 m_state.exec.directChunksDataFieldCount = dataFieldCount;
1897 GAIA_FOR(dataFieldCount) {
1898 m_state.exec.directChunksDataFields[i] = pDataFields[i];
1900 m_state.exec.directChunksResultRevision = m_state.resultCacheRevision;
1901 m_state.exec.directChunksWorldVersion = currWorldVersion;
1902 m_state.exec.directChunksEnabledVersion = currEnabledVersion;
1903 m_state.exec.directChunksDeleteVersion = currDeleteVersion;
1904 m_state.exec.directChunksCompIndicesData = pCompIndicesData;
1906 uint32_t chunkCnt = 0;
1907 for (uint32_t i = idxFrom; i < idxTo; ++i)
1908 chunkCnt += (uint32_t)m_state.archetypeCache[i]->chunks().size();
1909 m_state.exec.directChunks.reserve(chunkCnt);
1910 m_state.exec.directChunkData.reserve(chunkCnt * dataFieldCount);
1912 for (uint32_t i = idxFrom; i < idxTo; ++i) {
1913 const auto* pArchetype = m_state.archetypeCache[i];
1914 if (pArchetype->is_req_del())
1916 const auto* pCompIndices = m_state.exec.archetypeCompIndices[i].indices;
1917 for (
auto* pChunk: pArchetype->chunks()) {
1918 const auto from = detail::ChunkIterImpl::start_index(pChunk, Constraints::EnabledOnly);
1919 const auto to = detail::ChunkIterImpl::end_index(pChunk, Constraints::EnabledOnly);
1921 const void* pData =
nullptr;
1922 uint32_t dataOffset = UINT32_MAX;
1923 if (dataFieldCount == 1) {
1928 const auto dataFieldIdx = pDataFields[0];
1929 const auto compIdx =
1930 dataFieldIdx < ChunkHeader::MAX_COMPONENTS ? pCompIndices[dataFieldIdx] : uint8_t(0xFF);
1931 if (compIdx != 0xFF)
1932 pData = pChunk->comp_rec_view()[compIdx].pData;
1933 }
else if (dataFieldCount > 1) {
1934 dataOffset = (uint32_t)m_state.exec.directChunkData.size();
1935 const auto recs = pChunk->comp_rec_view();
1936 GAIA_FOR_(dataFieldCount, fieldIdx) {
1937 const auto dataFieldIdx = pDataFields[fieldIdx];
1938 const auto compIdx =
1939 dataFieldIdx < ChunkHeader::MAX_COMPONENTS ? pCompIndices[dataFieldIdx] : uint8_t(0xFF);
1940 m_state.exec.directChunkData.push_back(compIdx != 0xFF ? recs[compIdx].pData :
nullptr);
1943 m_state.exec.directChunks.push_back({pArchetype, pChunk, pCompIndices, pData, dataOffset, from, to});
1957 if (!m_state.exec.inheritedDataPending)
1961 m_state.exec.archetypeInheritedData.clear();
1962 m_state.exec.inheritedDataPending =
false;
1966 m_state.exec.archetypeInheritedData.clear();
1967 m_state.exec.archetypeInheritedData.reserve(m_state.archetypeCache.size());
1968 for (
const auto* pArchetype: m_state.archetypeCache)
1971 m_state.exec.inheritedDataPending =
false;
1978 const auto cnt = (uint32_t)sortedKeys.size();
1990 const auto want = (uint32_t)sortedKeys[i];
1991 const auto cur = pos[want];
1996 const auto displaced = at[i];
1997 at[cur] = displaced;
1998 pos[displaced] = cur;
2008 if (m_plan.ctx.data.groupBy == EntityBad || !m_state.grouped.dataPending)
2014 const auto groupCnt = (uint32_t)m_state.grouped.archetypeGroupIds.size();
2017 sortKeys.
resize(groupCnt);
2018 GAIA_FOR(groupCnt) {
2019 sortKeys[i] = ((uint64_t)m_state.grouped.archetypeGroupIds[i] << 32U) | i;
2027 m_state.grouped.archetypeGroupData.clear();
2028 m_state.grouped.selectedGroupDataValid =
false;
2030 if (m_state.grouped.archetypeGroupIds.empty()) {
2031 m_state.grouped.dataPending =
false;
2035 GroupId groupId = m_state.grouped.archetypeGroupIds[0];
2036 uint32_t idxFirst = 0;
2037 const auto cnt = (uint32_t)m_state.grouped.archetypeGroupIds.size();
2038 for (uint32_t i = 1; i < cnt; ++i) {
2039 if (m_state.grouped.archetypeGroupIds[i] == groupId)
2042 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, i - 1,
false});
2043 groupId = m_state.grouped.archetypeGroupIds[i];
2047 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, cnt - 1,
false});
2048 m_state.grouped.dataPending =
false;
2053 if (!world_relation_depth_order_prunes_disabled_subtrees(*
world(), m_plan.ctx.data.groupBy))
2058 const auto currRelationVersion = world_rel_version(*
world(), m_plan.ctx.data.groupBy);
2059 const auto currEnabledVersion = world_enabled_hierarchy_version(*
world());
2060 if (m_state.nonTrivial.barrierRelVersion == currRelationVersion &&
2061 m_state.nonTrivial.barrierEnabledVersion == currEnabledVersion)
2064 m_state.nonTrivial.archetypeBarrierPasses.resize(m_state.archetypeCache.size(), 1);
2065 m_state.nonTrivial.barrierMayPrune = 0;
2067 const auto relation = m_plan.ctx.data.groupBy;
2068 for (uint32_t i = 0; i < m_state.archetypeCache.size(); ++i) {
2069 const auto* pArchetype = m_state.archetypeCache[i];
2070 auto& barrierPasses = m_state.nonTrivial.archetypeBarrierPasses[i];
2073 auto ids = pArchetype->ids_view();
2074 for (
auto idsIdx: pArchetype->pair_rel_indices(relation)) {
2075 const auto pair = ids[idsIdx];
2076 const auto parent = world_pair_target_if_alive(*
world(),
pair);
2077 if (parent == EntityBad || !world_entity_enabled_hierarchy(*
world(), parent, relation)) {
2079 m_state.nonTrivial.barrierMayPrune = 1;
2085 m_state.nonTrivial.barrierRelVersion = currRelationVersion;
2086 m_state.nonTrivial.barrierEnabledVersion = currEnabledVersion;
2094 core::fill(cacheData.indices, cacheData.indices + ChunkHeader::MAX_COMPONENTS, (uint8_t)0xFF);
2096 const auto cnt = (uint32_t)terms.size();
2098 const auto& term = terms[i];
2099 const auto fieldIdx = term.fieldIndex;
2100 const auto queryId = term.id;
2104 if (!query_term_maps_to_current_archetype(term))
2107 if (world_component_uses_sparse_storage(*
world(), queryId)) {
2108 cacheData.indices[fieldIdx] = 0xFF;
2112 auto compIdx = world_component_index_comp_idx(*
world(), *pArchetype, queryId);
2113 if (compIdx == BadIndex || compIdx == ComponentIndexBad) {
2117 compIdx = core::get_index(pArchetype->
ids_view(), queryId);
2120 cacheData.indices[fieldIdx] =
2121 (compIdx != BadIndex && compIdx != ComponentIndexBad && compIdx < pArchetype->
ids_view().size())
2132 core::fill(inheritedData.data, inheritedData.data + ChunkHeader::MAX_COMPONENTS,
nullptr);
2135 const auto cnt = (uint32_t)terms.size();
2137 const auto& term = terms[i];
2138 if (term.src != EntityBad || term.entTrav != EntityBad || term_has_variables(term))
2140 if (term.matchKind != QueryMatchKind::Semantic)
2142 const auto queryId = term.id;
2143 if (queryId == EntityBad || is_wildcard(queryId) || is_variable((EntityId)queryId.id()))
2145 if (world_component_uses_sparse_storage(*
world(), queryId))
2147 if (!world_term_uses_inherit_policy(*
world(), queryId))
2149 if (pArchetype->
has(queryId))
2152 const auto owner = world_query_first_inherited_owner(*
world(), *pArchetype, queryId);
2153 GAIA_ASSERT(owner != EntityBad);
2154 inheritedData.data[term.fieldIndex] = world_query_inherited_arg_data_const_ptr(*
world(), owner, queryId);
2157 m_state.exec.archetypeInheritedData.push_back(inheritedData);
2164 m_state.resultCacheMayNeedPrefabFilter = 1;
2172 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
2173 GAIA_PROF_SCOPE(queryinfo::add_cache_ng);
2175 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
2177 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
2179 m_state.archetypeSet.emplace(pArchetype);
2180 m_state.archetypeCache.push_back(pArchetype);
2182 m_state.exec.compIndicesPending =
true;
2183 m_state.exec.inheritedDataPending =
true;
2184 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2185 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2186 if (trackMembershipChange)
2187 mark_result_cache_membership_changed();
2194 if (!assumeAbsent && m_state.seedArchetypeSet.contains(pArchetype))
2196 GAIA_ASSERT(assumeAbsent || !m_state.seedArchetypeSet.contains(pArchetype));
2198 m_state.seedArchetypeSet.emplace(pArchetype);
2199 m_state.seedArchetypeCache.push_back(pArchetype);
2206 GAIA_ASSERT(m_plan.ctx.data.groupBy == EntityBad);
2207 GAIA_ASSERT(m_plan.ctx.data.sortByFunc ==
nullptr);
2208 GAIA_ASSERT(!m_state.seedArchetypeSet.contains(pArchetype));
2209 GAIA_ASSERT(!m_state.archetypeSet.contains(pArchetype));
2211 m_state.seedArchetypeSet.emplace(pArchetype);
2212 m_state.seedArchetypeCache.push_back(pArchetype);
2214 m_state.archetypeSet.emplace(pArchetype);
2215 m_state.archetypeCache.push_back(pArchetype);
2217 m_state.exec.compIndicesPending =
true;
2218 m_state.exec.inheritedDataPending =
true;
2219 if (trackMembershipChange)
2220 mark_result_cache_membership_changed();
2228 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
2229 GAIA_PROF_SCOPE(queryinfo::add_cache_wg);
2231 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
2233 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
2235 m_state.grouped.selectedGroupDataValid =
false;
2237 const GroupId groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
2239 m_state.archetypeSet.emplace(pArchetype);
2240 m_state.archetypeCache.push_back(pArchetype);
2242 m_state.grouped.archetypeGroupIds.push_back(groupId);
2243 m_state.grouped.dataPending =
true;
2244 m_state.exec.compIndicesPending =
true;
2245 m_state.exec.inheritedDataPending =
true;
2246 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2247 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2249 if (trackMembershipChange)
2250 mark_result_cache_membership_changed();
2258 if (m_plan.ctx.data.sortByFunc !=
nullptr)
2261 if (m_plan.ctx.data.groupBy != EntityBad)
2270 m_state.archetypeCache.push_back(pArchetype);
2272 m_state.exec.compIndicesPending =
true;
2273 m_state.exec.inheritedDataPending =
true;
2274 if (m_plan.ctx.data.groupBy != EntityBad) {
2275 const auto groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
2276 m_state.grouped.archetypeGroupIds.push_back(groupId);
2277 m_state.grouped.dataPending =
true;
2287 if (m_plan.ctx.data.groupBy == EntityBad || runtimeGroupId == 0)
2290 if (!m_state.grouped.selectedGroupDataValid || m_state.grouped.selectedGroupData.groupId != runtimeGroupId) {
2292 uint32_t right = (uint32_t)m_state.grouped.archetypeGroupData.size();
2293 while (left < right) {
2294 const uint32_t mid = left + ((right - left) >> 1);
2295 const auto midGroupId = m_state.grouped.archetypeGroupData[mid].groupId;
2296 if (midGroupId < runtimeGroupId)
2302 if (left < m_state.grouped.archetypeGroupData.size() &&
2303 m_state.grouped.archetypeGroupData[left].groupId == runtimeGroupId) {
2304 m_state.grouped.selectedGroupData = m_state.grouped.archetypeGroupData[left];
2305 m_state.grouped.selectedGroupDataValid =
true;
2306 return &m_state.grouped.selectedGroupData;
2309 m_state.grouped.selectedGroupData = {};
2310 m_state.grouped.selectedGroupDataValid =
false;
2314 return &m_state.grouped.selectedGroupData;
2320 if (m_state.archetypeSet.size() != m_state.seedArchetypeSet.size())
2323 for (
const auto* pArchetype: m_state.seedArchetypeCache) {
2324 if (!m_state.archetypeSet.contains(pArchetype))
2335 if (m_state.archetypeSet.size() != archetypeCache.size())
2338 for (
const auto* pArchetype: archetypeCache) {
2339 if (!m_state.archetypeSet.contains(pArchetype))
2350 clear_result_cache();
2351 const auto cnt = (uint32_t)m_state.seedArchetypeCache.size();
2355 if (membershipChanged)
2356 mark_result_cache_membership_changed();
2363 const auto it = m_state.archetypeSet.find(pArchetype);
2364 if (it == m_state.archetypeSet.end())
2367 m_state.archetypeSet.erase(it);
2369 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2370 GAIA_ASSERT(archetypeIdx != BadIndex);
2371 if (archetypeIdx == BadIndex)
2374 if (m_plan.ctx.data.sortByFunc !=
nullptr)
2377 core::swap_erase(m_state.archetypeCache, archetypeIdx);
2378 if (archetypeIdx < m_state.exec.archetypeCompIndices.size())
2379 core::swap_erase(m_state.exec.archetypeCompIndices, archetypeIdx);
2380 if (archetypeIdx < m_state.exec.archetypeInheritedData.size())
2381 core::swap_erase(m_state.exec.archetypeInheritedData, archetypeIdx);
2382 if (archetypeIdx < m_state.grouped.archetypeGroupIds.size())
2383 core::swap_erase(m_state.grouped.archetypeGroupIds, archetypeIdx);
2384 if (archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size())
2385 core::swap_erase(m_state.nonTrivial.archetypeBarrierPasses, archetypeIdx);
2387 if (m_plan.ctx.data.groupBy != EntityBad) {
2388 m_state.grouped.selectedGroupDataValid =
false;
2389 m_state.grouped.archetypeGroupData.clear();
2390 m_state.grouped.dataPending =
true;
2393 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
2394 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
2396 mark_result_cache_membership_changed();
2404 const auto it = m_state.seedArchetypeSet.find(pArchetype);
2405 if (it == m_state.seedArchetypeSet.end())
2408 m_state.seedArchetypeSet.erase(it);
2410 const auto archetypeIdx = core::get_index(m_state.seedArchetypeCache, pArchetype);
2411 GAIA_ASSERT(archetypeIdx != BadIndex);
2412 if (archetypeIdx == BadIndex)
2415 core::swap_erase(m_state.seedArchetypeCache, archetypeIdx);
2422 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
2423 return const_cast<World*
>(m_plan.ctx.w);
2428 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
2429 return m_plan.ctx.w;
2435 return m_plan.ctx.q.ser_buffer(
world());
2439 m_plan.ctx.q.ser_buffer_reset(
world());
2456 return m_plan.vm.bytecode(*
world());
2462 return m_plan.vm.op_count();
2468 return m_plan.vm.op_signature();
2474 const auto& ctxData = m_plan.ctx.data;
2475 return ctxData.changedCnt > 0;
2481 const auto& ctxData = m_plan.ctx.data;
2488 const auto& ctxData = m_plan.ctx.data;
2495 return m_plan.ctx.data.directTargetEvalKind;
2501 return m_plan.ctx.data.directTargetEvalId;
2507 return m_plan.ctx.data.canDirectTargetEval;
2513 return m_plan.ctx.data.canDirectEntitySeedEvalShape;
2519 return m_plan.ctx.data.hasOnlyDirectOrTerms;
2525 const auto& ctxData = m_plan.ctx.data;
2533 template <
typename... T>
2535 return (has_inter<T>(QueryOpKind::Any) || ...);
2541 template <
typename... T>
2543 return (has_inter<T>(QueryOpKind::Or) || ...);
2549 template <
typename... T>
2551 return (has_inter<T>(QueryOpKind::All) && ...);
2557 template <
typename... T>
2559 return (!has_inter<T>(QueryOpKind::Not) && ...);
2565 GAIA_PROF_SCOPE(queryinfo::remove);
2575 const auto& ctxData = m_state.exec.archetypeCompIndices[archetypeIdx];
2576 return {ctxData.indices, ChunkHeader::MAX_COMPONENTS};
2585 std::span<const DirectChunkEntry>
2586 direct_chunk_view(uint32_t idxFrom, uint32_t idxTo,
const uint32_t* pDataFields, uint32_t dataFieldCount)
const {
2588 return {m_state.exec.directChunks.data(), m_state.exec.directChunks.size()};
2594 return {m_state.exec.directChunkData.data(), m_state.exec.directChunkData.size()};
2602 if (archetypeIdx >= m_state.exec.archetypeInheritedData.size())
2604 const auto& ctxData = m_state.exec.archetypeInheritedData[archetypeIdx];
2605 return {ctxData.data, ChunkHeader::MAX_COMPONENTS};
2614 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2615 if (archetypeIdx == BadIndex)
2628 if (m_state.exec.compIndicesPending)
2630 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2631 if (archetypeIdx == BadIndex)
2642 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
2643 if (archetypeIdx == BadIndex)
2651 GAIA_NODISCARD GroupId
group_id(uint32_t archetypeIdx)
const {
2653 GAIA_ASSERT(archetypeIdx < m_state.grouped.archetypeGroupIds.size());
2654 return m_state.grouped.archetypeGroupIds[archetypeIdx];
2662 if (m_state.nonTrivial.archetypeBarrierPasses.empty())
2664 GAIA_ASSERT(archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size());
2665 return m_state.nonTrivial.archetypeBarrierPasses[archetypeIdx] != 0;
2672 return m_state.nonTrivial.barrierMayPrune != 0;
2677 GAIA_NODISCARD CArchetypeDArray::iterator
begin() {
2678 return m_state.archetypeCache.begin();
2683 GAIA_NODISCARD CArchetypeDArray::const_iterator
begin()
const {
2684 return m_state.archetypeCache.begin();
2689 GAIA_NODISCARD CArchetypeDArray::const_iterator
cbegin()
const {
2690 return m_state.archetypeCache.begin();
2695 GAIA_NODISCARD CArchetypeDArray::iterator
end() {
2696 return m_state.archetypeCache.end();
2701 GAIA_NODISCARD CArchetypeDArray::const_iterator
end()
const {
2702 return m_state.archetypeCache.end();
2707 GAIA_NODISCARD CArchetypeDArray::const_iterator
cend()
const {
2708 return m_state.archetypeCache.end();
2714 return std::span{(
const Archetype**)m_state.archetypeCache.data(), m_state.archetypeCache.size()};
2720 return std::span{m_state.nonTrivial.archetypeSortData.data(), m_state.nonTrivial.archetypeSortData.size()};
2727 return std::span{m_state.grouped.archetypeGroupData.data(), m_state.grouped.archetypeGroupData.size()};
2730#if GAIA_ECS_TEST_HOOKS
2736 GAIA_NODISCARD TestDynamicCacheKind test_dynamic_cache_kind()
const {
2737 return m_plan.ctx.data.dynamicCacheKind;
2741 GAIA_NODISCARD
bool test_uses_direct_src_version_tracking()
const {
2742 return m_plan.ctx.data.uses_direct_src_version_tracking();
2746 GAIA_NODISCARD
bool test_uses_src_trav_snapshot()
const {
2747 return m_plan.ctx.data.uses_src_trav_snapshot();
2752 GAIA_NODISCARD uint32_t test_match_pass_count()
const {
2753 return m_testMatchPassCount;
2757 GAIA_NODISCARD
static constexpr uint32_t test_query_info_size() {
2758 return (uint32_t)
sizeof(QueryInfo);
2762 GAIA_NODISCARD
static constexpr uint32_t test_query_plan_size() {
2763 return (uint32_t)
sizeof(QueryPlan);
2767 GAIA_NODISCARD
static constexpr uint32_t test_query_state_size() {
2768 return (uint32_t)
sizeof(QueryState);
2772 GAIA_NODISCARD
static constexpr uint32_t test_dynamic_cache_state_size() {
2773 return (uint32_t)
sizeof(QueryState::DynamicCacheState);
2777 GAIA_NODISCARD
static constexpr uint32_t test_query_state_dynamic_offset() {
2778 return (uint32_t)offsetof(QueryState, dynamic);
2783 void test_add_transient_archetype(
const Archetype* pArchetype) {
2784 GAIA_ASSERT(pArchetype !=
nullptr);
2785 if (pArchetype ==
nullptr)
2788 m_state.clear_transient_result_cache();
Array of elements of type.
Definition darray_ext_impl.h:31
GAIA_NODISCARD size_type size() const noexcept
Returns the number of elements.
Definition darray_ext_impl.h:561
GAIA_NODISCARD auto begin() noexcept
Returns an iterator to the first element.
Definition darray_ext_impl.h:613
void push_back(const T &arg)
Appends an element.
Definition darray_ext_impl.h:360
GAIA_NODISCARD auto end() noexcept
Returns an iterator one past the last element.
Definition darray_ext_impl.h:649
void resize(size_type count, ResizePolicy policy=ResizePolicy::Exact)
Changes the number of elements.
Definition darray_ext_impl.h:289
void clear() noexcept
Removes all elements.
Definition darray_ext_impl.h:518
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:800
GAIA_NODISCARD bool has(Entity entity) const
Checks if an entity is a part of the archetype.
Definition archetype.h:861
void sort_entities(Entity entity, TSortByFunc func)
Sorts all entities in the archetypes according to the given function.
Definition archetype.h:1076
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:1956
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:2205
GAIA_NODISCARD CArchetypeDArray::const_iterator begin() const
Returns an iterator to the first cached result archetype.
Definition query_info.h:2683
void apply_archetype_cache_order(std::span< const uint64_t > sortedKeys)
Reorders the archetype cache so position i holds the entry whose initial cache index is stored in the...
Definition query_info.h:1977
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:1804
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:2725
GAIA_NODISCARD GroupId group_id(uint32_t archetypeIdx) const
Returns the cached group id for a matched archetype index.
Definition query_info.h:2651
GAIA_NODISCARD bool has_no() const
Returns true when none of the requested types is present as a Not term.
Definition query_info.h:2558
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:2512
void sort_entities()
Applies query entity sorting and rebuilds sorted chunk slices when needed.
Definition query_info.h:1774
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:2427
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:2564
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:2518
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:1660
GAIA_NODISCARD bool barrier_may_prune() const
Returns true when any cached archetype can be pruned by the hierarchy barrier.
Definition query_info.h:2670
GAIA_NODISCARD bool has_or() const
Returns true when any of the requested types is present as an Or term.
Definition query_info.h:2542
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:2660
GAIA_NODISCARD util::str bytecode() const
Returns a textual dump of the compiled VM bytecode.
Definition query_info.h:2455
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:2713
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:1951
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:2362
GAIA_NODISCARD QuerySerBuffer & ser_buffer()
Returns the query serialization buffer associated with the owning world.
Definition query_info.h:2434
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:2627
GAIA_NODISCARD bool matches_prefab_entities() const
Returns true when prefab-tagged entities should participate in query results.
Definition query_info.h:2524
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:2130
bool del_archetype_from_seed_cache(const Archetype *pArchetype)
Removes an archetype from the structural seed cache.
Definition query_info.h:2403
void add_archetype_to_seed_cache(const Archetype *pArchetype, bool assumeAbsent=false)
Adds an archetype to the structural seed cache.
Definition query_info.h:2193
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:2707
std::span< const void *const > direct_chunk_data_view() const
Returns cached flattened direct chunk data pointers.
Definition query_info.h:2593
InheritedTermDataView inherited_data_view(uint32_t archetypeIdx) const
Returns cached inherited-term data for a matched archetype index.
Definition query_info.h:2600
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:2438
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:1836
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:1868
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:2473
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:2719
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:2487
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:2052
GAIA_NODISCARD World * world()
Returns the mutable world owning this query.
Definition query_info.h:2421
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:2348
GAIA_NODISCARD bool has_all() const
Returns true when all requested types are present as All terms.
Definition query_info.h:2550
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:2695
GAIA_NODISCARD Entity direct_target_eval_id() const
Returns the concrete direct target id used by direct target evaluation.
Definition query_info.h:2500
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:2480
void sort_cache_groups()
Sorts cached archetypes by group id when grouped iteration requested ordering.
Definition query_info.h:1792
GAIA_NODISCARD CArchetypeDArray::const_iterator end() const
Returns an iterator past the last cached result archetype.
Definition query_info.h:2701
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:2586
GAIA_NODISCARD bool has_any() const
Returns true when any of the requested types is present as an Any term.
Definition query_info.h:2534
GAIA_NODISCARD uint32_t op_count() const
Returns the number of VM operations in the compiled query.
Definition query_info.h:2461
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:2334
GAIA_NODISCARD CArchetypeDArray::const_iterator cbegin() const
Returns a const iterator to the first cached result archetype.
Definition query_info.h:2689
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:2257
GAIA_NODISCARD QueryCtx & ctx()
Returns the mutable compiled query context.
Definition query_info.h:2444
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:2573
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:2677
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:2467
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:2319
void ensure_depth_order_hierarchy_barrier_cache()
Ensures depth-order hierarchy barrier results are current before public reads.
Definition query_info.h:2621
ArchetypeCompIndices create_comp_indices(const Archetype *pArchetype)
Builds field-to-archetype component indices for one matched archetype.
Definition query_info.h:2092
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:2007
GAIA_NODISCARD const QueryCtx & ctx() const
Returns the compiled query context.
Definition query_info.h:2449
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:2162
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:2227
GAIA_NODISCARD bool can_direct_target_eval() const
Returns true when the query can evaluate concrete target entities directly.
Definition query_info.h:2506
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:2639
InheritedTermDataView inherited_data_view(const Archetype *pArchetype) const
Returns cached inherited-term data for a matched archetype pointer.
Definition query_info.h:2611
GAIA_NODISCARD QueryCtx::DirectTargetEvalKind direct_target_eval_kind() const
Returns the direct target evaluation mode selected during compilation.
Definition query_info.h:2494
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:2285
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:2269
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:2171
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. Conversion to Entity stores only id() of each e...
Definition id.h:559
Wrapper for two types forming a relationship pair. Depending on what types are used to form a pair it...
Definition id.h:197
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:164
Strict weak ordering functor using operator<.
Definition utility.h:1385
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:168
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:486
Identifier of an entity or component instance in the world. Packs the entity index,...
Definition id.h:231
GAIA_NODISCARD bool has_dep_flag(DependencyFlags dependency) const
Tests whether a dependency fact was recorded.
Definition query_common.h:1091
GAIA_NODISCARD std::span< const QueryTerm > terms_view() const
Returns compiled terms in execution order.
Definition query_common.h:1312
Dependencies deps
Explicit dependency metadata derived from query shape.
Definition query_common.h:1196
Authored and compiled state defining query identity and execution behavior.
Definition query_common.h:897
struct gaia::ecs::QueryCtx::Data data
Compiled query payload.
QueryFlags
Query maintenance and execution flags derived during compilation.
Definition query_common.h:908
@ HasPrefabTerms
Query explicitly mentions Prefab and therefore bypasses automatic exclusion.
Definition query_common.h:926
@ SortGroups
Cached group ranges require sorting.
Definition query_common.h:914
@ MatchPrefab
Includes prefab entities without requiring an explicit Prefab term.
Definition query_common.h:924
@ SortEntities
Cached entity slices require sorting.
Definition query_common.h:912
@ OrderGroups
Grouped archetypes are ordered by group identifier during cache refresh.
Definition query_common.h:928
@ Recompile
VM opcode recompilation is pending.
Definition query_common.h:918
@ DependencyHasSourceTerms
At least one term uses a fixed source entity.
Definition query_common.h:998
@ DependencyHasEntityFilterTerms
At least one term requires per-entity filtering.
Definition query_common.h:1016
@ DependencyHasVariableTerms
At least one term contains a runtime variable.
Definition query_common.h:1000
@ DependencyHasPotentialInheritedIdTerms
A term shape may resolve through inherited-id matching.
Definition query_common.h:1020
@ DependencyHasInheritedDataTerms
Iteration requires cached inherited component pointers.
Definition query_common.h:1018
@ DependencyHasTraversalTerms
At least one source term traverses a relation.
Definition query_common.h:1014
@ 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:970
DynamicCacheKind
Dynamic-cache dependency shape derived from compiled query metadata.
Definition query_common.h:954
@ 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:936
@ 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:349
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
bool keepStamps
True to retain allocated dedup-stamp pages while releasing the frame.
Definition query_info.h:1181
CleanUpTmpArchetypeMatches(World &w, bool keep)
Creates a guard for an already acquired matching frame.
Definition query_info.h:1186
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:326
static constexpr bool value
True when the type derives from the pair base.
Definition id.h:222
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