105 uint32_t archetypeIdx;
117 struct SrcTravSnapshotItem {
118 Entity entity = EntityBad;
120 uint32_t sourceVersion = 0;
122 GAIA_NODISCARD
bool operator==(
const SrcTravSnapshotItem& other)
const {
123 return entity == other.entity && sourceVersion == other.sourceVersion;
126 GAIA_NODISCARD
bool operator!=(
const SrcTravSnapshotItem& other)
const {
127 return !operator==(other);
148 enum DirtyFlags : uint8_t { Clean = 0x00, Seed = 0x01, Result = 0x02, All = Seed | Result };
151 cnt::set<const Archetype*> seedArchetypeSet;
152 CArchetypeDArray seedArchetypeCache;
156 cnt::set<const Archetype*> archetypeSet;
158 CArchetypeDArray archetypeCache;
180 void clear_transient() {
208 void clear_transient() {
237 void clear_transient() {
249 GroupedPayload grouped;
251 NonTrivialPayload nonTrivial;
254 ArchetypeId lastArchetypeId{};
262 bool srcTravSnapshotOverflowed =
false;
266 uint8_t varBindingMask = 0;
269 uint32_t resultCacheRevision = 1;
271 uint8_t dirtyFlags = DirtyFlags::All;
273 void clear_seed_cache() {
274 seedArchetypeSet = {};
275 seedArchetypeCache = {};
278 void clear_result_cache() {
286 void clear_transient_result_cache() {
287 archetypeCache.clear();
288 exec.clear_transient();
289 grouped.clear_transient();
290 nonTrivial.clear_transient();
295 clear_result_cache();
300 srcTravSnapshot.clear();
301 srcTravSnapshotOverflowed =
false;
303 dirtyFlags = DirtyFlags::All;
306 void invalidate_seed() {
307 dirtyFlags = (uint8_t)(dirtyFlags | DirtyFlags::Seed | DirtyFlags::Result);
310 void invalidate_result() {
311 dirtyFlags = (uint8_t)(dirtyFlags | DirtyFlags::Result);
314 void invalidate_all() {
315 dirtyFlags = DirtyFlags::All;
318 GAIA_NODISCARD
bool seed_dirty()
const {
319 return (dirtyFlags & DirtyFlags::Seed) != 0;
322 GAIA_NODISCARD
bool result_dirty()
const {
323 return (dirtyFlags & DirtyFlags::Result) != 0;
326 GAIA_NODISCARD
bool needs_refresh()
const {
327 return seed_dirty() || result_dirty();
331 dirtyFlags = DirtyFlags::Clean;
340 enum QueryCmdType : uint8_t { ALL, OR, NOT };
342 void reset_matching_cache() {
343 if (!m_state.archetypeCache.empty())
344 mark_result_cache_membership_changed();
348 auto& ctxData = m_plan.ctx.data;
349 ctxData.lastMatchedArchetypeIdx_All = {};
350 ctxData.lastMatchedArchetypeIdx_Or = {};
351 ctxData.lastMatchedArchetypeIdx_Not = {};
354 void clear_result_cache() {
355 m_state.clear_result_cache();
358 void mark_result_cache_membership_changed() {
359 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
360 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
361 ++m_state.resultCacheRevision;
362 if (m_state.resultCacheRevision != 0)
366 m_state.resultCacheRevision = 1;
370 GAIA_NODISCARD
bool has_dyn_terms()
const {
371 return m_plan.ctx.data.cachePolicy == QueryCtx::CachePolicy::Dynamic;
375 GAIA_NODISCARD
bool can_reuse_dyn_cache()
const {
376 if (!has_dyn_terms())
379 const auto& deps = m_plan.ctx.data.deps;
380 if (!deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms))
383 if (!deps.can_reuse_src_cache())
387 if (!deps.has_dep_flag(QueryCtx::DependencyHasTraversalTerms))
390 return m_plan.ctx.data.cacheSrcTrav != 0;
394 GAIA_NODISCARD
bool uses_direct_src_version_tracking()
const {
395 const auto& deps = m_plan.ctx.data.deps;
396 return !deps.has_dep_flag(QueryCtx::DependencyHasTraversalTerms) &&
397 can_reuse_dyn_cache();
401 GAIA_NODISCARD
bool uses_src_trav_snapshot()
const {
402 const auto& deps = m_plan.ctx.data.deps;
403 return deps.has_dep_flag(QueryCtx::DependencyHasTraversalTerms) &&
404 can_reuse_dyn_cache();
408 GAIA_NODISCARD
bool dyn_rel_versions_changed()
const {
409 const auto relations = m_plan.ctx.data.deps.relations_view();
410 const auto cnt = (uint32_t)relations.size();
412 if (m_state.relationVersions[i] != world_rel_version(*world(), relations[i]))
420 GAIA_NODISCARD
bool dyn_var_bindings_changed(
421 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask)
const {
422 if (m_state.varBindingMask != runtimeVarBindingMask)
425 GAIA_FOR(MaxVarCnt) {
426 const auto bit = (uint8_t(1) << i);
427 if ((runtimeVarBindingMask & bit) == 0)
430 if (m_state.varBindings[i] != runtimeVarBindings[i])
438 GAIA_NODISCARD
bool direct_src_versions_changed()
const {
439 if (!uses_direct_src_version_tracking())
442 const auto& deps = m_plan.ctx.data.deps;
443 const auto sourceEntities = deps.src_entities_view();
444 const auto cnt = (uint32_t)sourceEntities.size();
446 if (m_state.directSrcEntityVersions[i] != world_entity_archetype_version(*world(), sourceEntities[i]))
454 template <
typename Func>
455 void each_reusable_src_entity(Func&& func)
const {
456 const auto terms = m_plan.ctx.data.terms_view();
457 const auto cnt = (uint32_t)terms.size();
459 const auto& term = terms[i];
460 if (term.src == EntityBad || is_variable(term.src))
463 (void)vm::detail::each_lookup_src(*world(), term, term.src, [&](Entity source) {
470 GAIA_NODISCARD
static cnt::darray<SrcTravSnapshotItem>& src_trav_snapshot_scratch() {
471 static thread_local cnt::darray<SrcTravSnapshotItem> scratch;
477 GAIA_NODISCARD
bool build_src_trav_snapshot(cnt::darray<SrcTravSnapshotItem>& items)
const {
478 const auto maxItems = (uint32_t)m_plan.ctx.data.cacheSrcTrav;
483 bool overflowed =
false;
484 each_reusable_src_entity([&](Entity source) {
485 if (items.size() >= maxItems) {
489 items.push_back({source, world_entity_archetype_version(*world(), source)});
498 GAIA_NODISCARD
bool traversed_src_versions_changed()
const {
499 const auto cnt = (uint32_t)m_state.srcTravSnapshot.size();
501 const auto& item = m_state.srcTravSnapshot[i];
502 if (item.sourceVersion != world_entity_archetype_version(*world(), item.entity))
510 GAIA_NODISCARD
bool dyn_src_inputs_changed(
bool relationVersionsChanged) {
511 const auto& deps = m_plan.ctx.data.deps;
512 if (!deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms))
515 if (!deps.has_dep_flag(QueryCtx::DependencyHasTraversalTerms))
516 return direct_src_versions_changed();
518 if (m_state.srcTravSnapshotOverflowed)
521 if (!relationVersionsChanged)
522 return traversed_src_versions_changed();
524 auto& scratch = src_trav_snapshot_scratch();
525 if (!build_src_trav_snapshot(scratch))
528 if (scratch.size() != m_state.srcTravSnapshot.size())
531 const auto cnt = (uint32_t)m_state.srcTravSnapshot.size();
533 if (scratch[i] != m_state.srcTravSnapshot[i])
542 dyn_inputs_changed(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
543 if (!can_reuse_dyn_cache())
546 if (dyn_var_bindings_changed(runtimeVarBindings, runtimeVarBindingMask))
549 const bool relationVersionsChanged = dyn_rel_versions_changed();
550 if (relationVersionsChanged && !uses_src_trav_snapshot())
553 const auto& deps = m_plan.ctx.data.deps;
554 if (!deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms))
555 return relationVersionsChanged;
557 if (m_state.srcTravSnapshotOverflowed)
560 return dyn_src_inputs_changed(relationVersionsChanged);
565 snapshot_dyn_inputs(
const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
566 if (!can_reuse_dyn_cache())
569 const auto relations = m_plan.ctx.data.deps.relations_view();
570 const auto cnt = (uint32_t)relations.size();
572 m_state.relationVersions[i] = world_rel_version(*world(), relations[i]);
574 const auto& deps = m_plan.ctx.data.deps;
575 if (uses_direct_src_version_tracking()) {
576 const auto sourceEntities = deps.src_entities_view();
577 const auto sourceCnt = (uint32_t)sourceEntities.size();
579 m_state.directSrcEntityVersions[i] = world_entity_archetype_version(*world(), sourceEntities[i]);
582 if (uses_src_trav_snapshot()) {
583 auto& scratch = src_trav_snapshot_scratch();
584 if (build_src_trav_snapshot(scratch)) {
585 m_state.srcTravSnapshot = scratch;
586 m_state.srcTravSnapshotOverflowed =
false;
588 m_state.srcTravSnapshot.clear();
589 m_state.srcTravSnapshotOverflowed =
true;
592 m_state.srcTravSnapshot.clear();
593 m_state.srcTravSnapshotOverflowed =
false;
596 m_state.varBindings = runtimeVarBindings;
597 m_state.varBindingMask = runtimeVarBindingMask;
600 template <
typename TType>
601 GAIA_NODISCARD
bool has_inter([[maybe_unused]] QueryOpKind op,
bool isReadWrite)
const {
602 using T = core::raw_t<TType>;
604 if constexpr (std::is_same_v<T, Entity>) {
606 GAIA_ASSERT(!isReadWrite);
612 if constexpr (is_pair<T>::value) {
613 const auto rel = m_plan.ctx.cc->get<
typename T::rel>().entity;
614 const auto tgt = m_plan.ctx.cc->get<
typename T::tgt>().entity;
615 id = (Entity)Pair(rel, tgt);
617 id = m_plan.ctx.cc->get<T>().entity;
620 const auto& ctxData = m_plan.ctx.data;
621 const auto compIdx = comp_idx<MAX_ITEMS_IN_QUERY>(ctxData.terms.data(),
id, EntityBad);
623 if (op != ctxData.terms[compIdx].op)
627 const uint32_t maskRW = (uint32_t)ctxData.readWriteMask & (1U << compIdx);
628 const uint32_t maskXX = (uint32_t)isReadWrite << compIdx;
629 return maskRW == maskXX;
633 template <
typename T>
634 GAIA_NODISCARD
bool has_inter(QueryOpKind op)
const {
636 constexpr bool isReadWrite = core::is_mut_v<T>;
637 return has_inter<T>(op, isReadWrite);
643 GAIA_ASSERT(m_refs != 0);
647 GAIA_ASSERT(m_refs > 0);
651 uint32_t refs()
const {
655 void init(World* world) {
656 m_plan.ctx.w = world;
660 reset_matching_cache();
666 m_state.invalidate_result();
669 m_state.invalidate_seed();
672 m_state.invalidate_all();
677 void invalidate_seed() {
681 void invalidate_result() {
687 if (m_plan.ctx.data.sortByFunc !=
nullptr)
688 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortEntities;
701 info.m_plan.ctx = GAIA_MOV(ctx);
702 info.m_plan.ctx.q.handle = {id, 0};
705 info.
compile(entityToArchetypeMap, allArchetypes);
710 GAIA_NODISCARD
static QueryInfo create(uint32_t
idx, uint32_t
gen,
void* pCtx) {
711 auto* pCreationCtx = (QueryInfoCreationCtx*)pCtx;
712 auto& queryCtx = *pCreationCtx->pQueryCtx;
713 auto& entityToArchetypeMap = (EntityToArchetypeMap&)*pCreationCtx->pEntityToArchetypeMap;
722 info.m_plan.ctx = GAIA_MOV(queryCtx);
723 info.m_plan.ctx.q.handle = {
idx,
gen};
726 info.
compile(entityToArchetypeMap, pCreationCtx->allArchetypes);
731 GAIA_NODISCARD
static QueryHandle handle(
const QueryInfo& info) {
732 return QueryHandle(info.idx, info.gen);
737 GAIA_PROF_SCOPE(queryinfo::compile);
740 m_plan.vm.compile(entityToArchetypeMap, allArchetypes, m_plan.ctx);
745 GAIA_PROF_SCOPE(queryinfo::recompile);
748 m_plan.vm.create_opcodes(m_plan.ctx);
751 GAIA_NODISCARD QueryCtx::CachePolicy cache_policy()
const {
752 return m_plan.ctx.data.cachePolicy;
755 GAIA_NODISCARD
bool has_grouped_payload()
const {
756 return m_plan.ctx.data.groupBy != EntityBad;
759 GAIA_NODISCARD
bool has_sorted_payload()
const {
760 return m_plan.ctx.data.sortByFunc !=
nullptr;
763 GAIA_NODISCARD uint32_t reverse_index_revision()
const {
764 return m_state.resultCacheRevision;
767 GAIA_NODISCARD
bool can_update_with_new_archetype()
const {
769 return m_plan.vm.is_compiled() && cache_policy() == QueryCtx::CachePolicy::Immediate &&
770 !m_state.needs_refresh();
775 return m_plan.ctx.data.createArchetypeMatchKind == QueryCtx::CreateArchetypeMatchKind::DirectStructuralTerms;
780 const auto& ctxData = m_plan.ctx.data;
781 return (ctxData.as_mask_0 + ctxData.as_mask_1) != 0;
784 GAIA_NODISCARD
bool operator==(
const QueryCtx& other)
const {
785 return m_plan.ctx == other;
788 GAIA_NODISCARD
bool operator!=(
const QueryCtx& other)
const {
789 return m_plan.ctx != other;
803 query_match_scratch_release(world, keepStamps);
813 template <
typename ArchetypeLookup>
816 const ArchetypeLookup& entityToArchetypeMap,
821 uint8_t runtimeVarBindingMask) {
822 auto& ctxData = m_plan.ctx.data;
825 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
829 if (!m_plan.vm.is_compiled())
832 const bool hasDynamicTerms = has_dyn_terms();
833 if (hasDynamicTerms && (!can_reuse_dyn_cache() || m_state.needs_refresh() ||
834 dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask))) {
838 reset_matching_cache();
839 }
else if (m_state.seed_dirty()) {
840 reset_matching_cache();
841 }
else if (m_state.result_dirty()) {
842 sync_result_cache_from_seed_cache();
843 if (m_state.lastArchetypeId == archetypeLastId) {
846 m_state.clear_dirty();
852 GAIA_ASSERT(archetypeLastId >= m_state.lastArchetypeId);
853 if (!hasDynamicTerms && !m_state.needs_refresh() && m_state.lastArchetypeId == archetypeLastId) {
859 m_state.lastArchetypeId = archetypeLastId;
861 GAIA_PROF_SCOPE(queryinfo::match);
864 auto& matchScratch = query_match_scratch_acquire(w);
869 ctx.pWorld = world();
871 ctx.allArchetypes = allArchetypes;
872 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap);
873 ctx.pMatchesArr = &matchScratch.matchesArr;
874 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
875 ctx.matchesVersion = matchScratch.next_match_version();
876 ctx.pLastMatchedArchetypeIdx_All = &ctxData.lastMatchedArchetypeIdx_All;
877 ctx.pLastMatchedArchetypeIdx_Or = &ctxData.lastMatchedArchetypeIdx_Or;
878 ctx.pLastMatchedArchetypeIdx_Not = &ctxData.lastMatchedArchetypeIdx_Not;
879 ctx.queryMask = ctxData.queryMask;
880 ctx.as_mask_0 = ctxData.as_mask_0;
881 ctx.as_mask_1 = ctxData.as_mask_1;
882 ctx.flags = ctxData.flags;
883 ctx.varBindings = runtimeVarBindings;
884 ctx.varBindingMask = runtimeVarBindingMask;
890 for (
const auto* pArchetype: *ctx.pMatchesArr) {
891 if (hasDynamicTerms) {
892 add_archetype_to_cache(pArchetype,
true);
894 add_archetype_to_seed_cache(pArchetype);
895 add_archetype_to_cache(pArchetype,
true);
903 snapshot_dyn_inputs(runtimeVarBindings, runtimeVarBindingMask);
904 m_state.clear_dirty();
915 auto& ctxData = m_plan.ctx.data;
918 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
922 if (!m_plan.vm.is_compiled())
925 const bool hasDynamicTerms = has_dyn_terms();
926 if ((hasDynamicTerms && (!can_reuse_dyn_cache() || m_state.needs_refresh() ||
927 dyn_inputs_changed(runtimeVarBindings, runtimeVarBindingMask))) ||
928 m_state.seed_dirty()) {
932 reset_matching_cache();
933 }
else if (m_state.result_dirty()) {
934 sync_result_cache_from_seed_cache();
937 GAIA_PROF_SCOPE(queryinfo::match1);
940 auto& matchScratch = query_match_scratch_acquire(w);
945 ctx.pWorld = world();
946 ctx.targetEntities = targetEntities;
947 const auto* pArchetype = &archetype;
949 ctx.archetypeLookup = {};
950 ctx.pMatchesArr = &matchScratch.matchesArr;
951 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
952 ctx.matchesVersion = matchScratch.next_match_version();
953 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
954 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
955 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
956 ctx.queryMask = ctxData.queryMask;
957 ctx.as_mask_0 = ctxData.as_mask_0;
958 ctx.as_mask_1 = ctxData.as_mask_1;
959 ctx.flags = ctxData.flags;
960 ctx.varBindings = runtimeVarBindings;
961 ctx.varBindingMask = runtimeVarBindingMask;
965 const bool matched = !ctx.pMatchesArr->empty();
968 for (
const auto* pArch: *ctx.pMatchesArr) {
969 if (hasDynamicTerms) {
970 add_archetype_to_cache(pArch,
true);
972 add_archetype_to_seed_cache(pArch);
973 add_archetype_to_cache(pArch,
true);
976 snapshot_dyn_inputs(runtimeVarBindings, runtimeVarBindingMask);
977 m_state.clear_dirty();
984 uint8_t runtimeVarBindingMask) {
985 match(entityToArchetypeMap, allArchetypes, archetypeLastId, runtimeVarBindings, runtimeVarBindingMask);
988 void ensure_matches_transient(
991 auto& ctxData = m_plan.ctx.data;
993 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
996 if (!m_plan.vm.is_compiled())
999 m_state.clear_transient_result_cache();
1002 auto& matchScratch = query_match_scratch_acquire(w);
1003 CleanUpTmpArchetypeMatches autoCleanup(w,
true);
1005 vm::MatchingCtx ctx{};
1006 ctx.pWorld = world();
1007 ctx.allArchetypes = allArchetypes;
1008 ctx.archetypeLookup = vm::make_archetype_lookup_view(entityToArchetypeMap);
1009 ctx.pMatchesArr = &matchScratch.matchesArr;
1010 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1011 ctx.matchesVersion = matchScratch.next_match_version();
1012 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1013 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1014 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1015 ctx.queryMask = ctxData.queryMask;
1016 ctx.as_mask_0 = ctxData.as_mask_0;
1017 ctx.as_mask_1 = ctxData.as_mask_1;
1018 ctx.flags = ctxData.flags;
1019 ctx.varBindings = runtimeVarBindings;
1020 ctx.varBindingMask = runtimeVarBindingMask;
1022 m_plan.vm.exec(ctx);
1024 m_state.archetypeCache.reserve(ctx.pMatchesArr->size());
1025 if (ctxData.groupBy != EntityBad)
1026 m_state.grouped.archetypeGroupIds.reserve(ctx.pMatchesArr->size());
1027 for (
const auto* pArchetype: *ctx.pMatchesArr)
1028 add_archetype_to_transient_cache(pArchetype);
1031 ensure_group_data();
1034 bool ensure_matches_one(
1035 const Archetype& archetype, EntitySpan targetEntities,
1036 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
1037 return match_one(archetype, targetEntities, runtimeVarBindings, runtimeVarBindingMask);
1040 bool ensure_matches_one_transient(
1041 const Archetype& archetype, EntitySpan targetEntities,
1042 const cnt::sarray<Entity, MaxVarCnt>& runtimeVarBindings, uint8_t runtimeVarBindingMask) {
1043 auto& ctxData = m_plan.ctx.data;
1045 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1048 if (!m_plan.vm.is_compiled())
1051 m_state.clear_transient_result_cache();
1054 auto& matchScratch = query_match_scratch_acquire(w);
1055 CleanUpTmpArchetypeMatches autoCleanup(w,
true);
1057 vm::MatchingCtx ctx{};
1058 ctx.pWorld = world();
1059 ctx.targetEntities = targetEntities;
1060 const auto* pArchetype = &archetype;
1061 ctx.allArchetypes =
std::span((
const Archetype**)&pArchetype, 1);
1062 ctx.archetypeLookup = {};
1063 ctx.pMatchesArr = &matchScratch.matchesArr;
1064 ctx.pMatchesStampByArchetypeId = &matchScratch.matchStamps;
1065 ctx.matchesVersion = matchScratch.next_match_version();
1066 ctx.pLastMatchedArchetypeIdx_All =
nullptr;
1067 ctx.pLastMatchedArchetypeIdx_Or =
nullptr;
1068 ctx.pLastMatchedArchetypeIdx_Not =
nullptr;
1069 ctx.queryMask = ctxData.queryMask;
1070 ctx.as_mask_0 = ctxData.as_mask_0;
1071 ctx.as_mask_1 = ctxData.as_mask_1;
1072 ctx.flags = ctxData.flags;
1073 ctx.varBindings = runtimeVarBindings;
1074 ctx.varBindingMask = runtimeVarBindingMask;
1076 m_plan.vm.exec(ctx);
1077 const bool matched = !ctx.pMatchesArr->empty();
1079 m_state.archetypeCache.reserve(ctx.pMatchesArr->size());
1080 if (ctxData.groupBy != EntityBad)
1081 m_state.grouped.archetypeGroupIds.reserve(ctx.pMatchesArr->size());
1082 for (
const auto* pArch: *ctx.pMatchesArr)
1083 add_archetype_to_transient_cache(pArch);
1085 ensure_group_data();
1089 bool register_archetype(
const Archetype& archetype, Entity matchedSelector = EntityBad,
bool assumeNew =
false) {
1090 auto& ctxData = m_plan.ctx.data;
1093 if ((ctxData.flags & QueryCtx::QueryFlags::Recompile) != 0)
1096 if (!can_update_with_new_archetype())
1099 const bool hadMatchBefore = !assumeNew && m_state.archetypeSet.contains(&archetype);
1102 bool hasOrTerms =
false;
1103 bool matchedOrTerm =
false;
1104 for (
const auto& term: ctxData.terms_view()) {
1105 if (term.id == matchedSelector) {
1106 if (term.op == QueryOpKind::Or)
1107 matchedOrTerm =
true;
1111 const bool present = usesIs ? vm::detail::match_single_id_on_archetype(*world(), archetype, term.id)
1112 : world_component_index_match_count(*world(), archetype, term.id) != 0;
1113 if (term.op == QueryOpKind::Or) {
1115 matchedOrTerm |= present;
1118 if (term.op == QueryOpKind::Any)
1121 const bool matched = term.op == QueryOpKind::Not ? !present : present;
1125 if (hasOrTerms && !matchedOrTerm)
1133 add_archetype_to_seed_cache(&archetype,
false);
1134 add_archetype_to_cache(&archetype,
true,
false);
1139 SingleArchetypeLookup singleArchetypeLookup;
1140 auto addLookupUnique = [&](Entity key, uint16_t compIdx, uint16_t matchCount) {
1141 const auto keyLookup = EntityLookupKey(key);
1142 const auto itLookup =
1143 core::find_if(singleArchetypeLookup.begin(), singleArchetypeLookup.end(), [&](
const auto& item) {
1144 return item.matches(keyLookup);
1146 if (itLookup != singleArchetypeLookup.end()) {
1147 auto& entry = itLookup->entry;
1148 entry.matchCount = (uint16_t)(entry.matchCount + matchCount);
1149 if (compIdx != ComponentIndexBad)
1150 entry.compIdx = compIdx;
1153 singleArchetypeLookup.push_back(
1154 SingleArchetypeLookupItem{
1155 keyLookup, ComponentIndexEntry{
const_cast<Archetype*
>(&archetype), compIdx, matchCount}});
1157 auto archetypeIds = archetype.ids_view();
1158 const auto cntIds = (uint32_t)archetypeIds.size();
1160 const auto entity = archetypeIds[i];
1161 singleArchetypeLookup.push_back(
1162 SingleArchetypeLookupItem{
1163 EntityLookupKey(entity), ComponentIndexEntry{
const_cast<Archetype*
>(&archetype), (uint16_t)i, 1}});
1170 const auto relKind = entity.entity() ? EntityKind::EK_Uni : EntityKind::EK_Gen;
1171 const auto rel = Entity((EntityId)entity.id(), 0,
false,
false, relKind);
1172 const auto tgt = Entity((EntityId)entity.gen(), 0,
false,
false, entity.kind());
1173 addLookupUnique(Pair(
All, tgt), ComponentIndexBad, 1);
1174 addLookupUnique(Pair(rel,
All), ComponentIndexBad, 1);
1175 addLookupUnique(Pair(
All,
All), ComponentIndexBad, 1);
1178 auto lastMatchedArchetypeIdx_All = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_All);
1179 auto lastMatchedArchetypeIdx_Or = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Or);
1180 auto lastMatchedArchetypeIdx_Not = GAIA_MOV(ctxData.lastMatchedArchetypeIdx_Not);
1181 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_All.empty());
1182 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Or.empty());
1183 GAIA_ASSERT(ctxData.lastMatchedArchetypeIdx_Not.empty());
1185 const auto* pArchetype = &archetype;
1186 const cnt::sarray<Entity, MaxVarCnt> noRuntimeVarBindings{};
1188 singleArchetypeLookup,
std::span((
const Archetype**)&pArchetype, 1), archetype.id(), noRuntimeVarBindings,
1190 ctxData.lastMatchedArchetypeIdx_All = GAIA_MOV(lastMatchedArchetypeIdx_All);
1191 ctxData.lastMatchedArchetypeIdx_Or = GAIA_MOV(lastMatchedArchetypeIdx_Or);
1192 ctxData.lastMatchedArchetypeIdx_Not = GAIA_MOV(lastMatchedArchetypeIdx_Not);
1193 const bool matched = assumeNew ? m_state.archetypeSet.contains(&archetype)
1194 : !hadMatchBefore && m_state.archetypeSet.contains(&archetype);
1200 sort_cache_groups();
1207 GAIA_PROF_SCOPE(queryinfo::calc_sort_data);
1209 m_state.nonTrivial.archetypeSortData.clear();
1227 uint32_t chunkIdx = 0;
1231 auto& archetypes = m_state.archetypeCache;
1236 uint32_t currArchetypeIdx = (uint32_t)-1;
1237 Chunk* pCurrentChunk =
nullptr;
1238 uint16_t currentStartRow = 0;
1239 uint16_t currentRow = 0;
1241 const void* pDataMin =
nullptr;
1242 const void* pDataCurr =
nullptr;
1245 uint32_t minArchetypeIdx = (uint32_t)-1;
1246 Entity minEntity = EntityBad;
1249 for (uint32_t t = 0; t < archetypes.size(); ++t) {
1250 const auto* pArchetype = archetypes[t];
1251 const auto& chunks = pArchetype->chunks();
1252 auto& cur = cursors[t];
1254 while (cur.chunkIdx < chunks.size() && cur.row >= chunks[cur.chunkIdx]->size()) {
1259 if (cur.chunkIdx >= chunks.size())
1262 const auto* pChunk = pArchetype->chunks()[cur.chunkIdx];
1263 auto entity = pChunk->entity_view()[cur.row];
1265 if (m_plan.ctx.data.sortBy != ecs::EntityBad) {
1266 auto compIdx = world_component_index_comp_idx(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.sortBy);
1267 if (compIdx == BadIndex)
1268 compIdx = pChunk->comp_idx(m_plan.ctx.data.sortBy);
1269 pDataCurr = pChunk->comp_ptr(compIdx, cur.row);
1271 pDataCurr = &pChunk->entity_view()[cur.row];
1273 if (minEntity == EntityBad) {
1275 minArchetypeIdx = t;
1276 pDataMin = pDataCurr;
1280 if (m_plan.ctx.data.sortByFunc(*m_plan.ctx.w, pDataCurr, pDataMin) < 0) {
1282 minArchetypeIdx = t;
1287 if (minArchetypeIdx == (uint32_t)-1)
1290 auto& cur = cursors[minArchetypeIdx];
1291 const auto& chunks = archetypes[minArchetypeIdx]->chunks();
1292 Chunk* pChunk = chunks[cur.chunkIdx];
1294 if (minArchetypeIdx == currArchetypeIdx && pChunk == pCurrentChunk) {
1298 if (pCurrentChunk !=
nullptr) {
1299 m_state.nonTrivial.archetypeSortData.push_back(
1300 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1304 currArchetypeIdx = minArchetypeIdx;
1305 pCurrentChunk = pChunk;
1306 currentStartRow = cur.row;
1310 currentRow = cur.row;
1313 if (pCurrentChunk !=
nullptr) {
1314 m_state.nonTrivial.archetypeSortData.push_back(
1315 {pCurrentChunk, currArchetypeIdx, currentStartRow, (uint16_t)(currentRow - currentStartRow)});
1319 void sort_entities() {
1320 if (m_plan.ctx.data.sortByFunc ==
nullptr)
1323 if ((m_plan.ctx.data.flags & QueryCtx::QueryFlags::SortEntities) == 0 && m_state.nonTrivial.sortVersion != 0)
1325 m_plan.ctx.data.flags &=
~QueryCtx::QueryFlags::SortEntities;
1328 for (
const auto* pArchetype: m_state.archetypeCache)
1329 const_cast<
Archetype*>(pArchetype)->sort_entities(m_plan.ctx.data.sortBy, m_plan.ctx.data.sortByFunc);
1333 m_state.nonTrivial.sortVersion = ::gaia::ecs::world_version(*world());
1336 void sort_cache_groups() {
1337 if ((m_plan.ctx.data.flags & QueryCtx::QueryFlags::SortGroups) == 0)
1339 m_plan.ctx.data.flags &= ~QueryCtx::QueryFlags::SortGroups;
1341 ensure_group_data();
1344 void swap_archetype_cache_entry(uint32_t left, uint32_t right) {
1345 auto* pTmpArchetype = m_state.archetypeCache[left];
1346 m_state.archetypeCache[left] = m_state.archetypeCache[right];
1347 m_state.archetypeCache[right] = pTmpArchetype;
1349 if (left < m_state.grouped.archetypeGroupIds.size() && right < m_state.grouped.archetypeGroupIds.size()) {
1350 const auto tmp = m_state.grouped.archetypeGroupIds[left];
1351 m_state.grouped.archetypeGroupIds[left] = m_state.grouped.archetypeGroupIds[right];
1352 m_state.grouped.archetypeGroupIds[right] = tmp;
1355 if (left < m_state.exec.archetypeCompIndices.size() && right < m_state.exec.archetypeCompIndices.size()) {
1356 auto tmp = m_state.exec.archetypeCompIndices[left];
1357 m_state.exec.archetypeCompIndices[left] = m_state.exec.archetypeCompIndices[right];
1358 m_state.exec.archetypeCompIndices[right] = tmp;
1361 if (left < m_state.exec.archetypeInheritedData.size() && right < m_state.exec.archetypeInheritedData.size()) {
1362 auto tmp = m_state.exec.archetypeInheritedData[left];
1363 m_state.exec.archetypeInheritedData[left] = m_state.exec.archetypeInheritedData[right];
1364 m_state.exec.archetypeInheritedData[right] = tmp;
1367 if (left < m_state.nonTrivial.archetypeBarrierPasses.size() &&
1368 right < m_state.nonTrivial.archetypeBarrierPasses.size()) {
1369 const auto tmp = m_state.nonTrivial.archetypeBarrierPasses[left];
1370 m_state.nonTrivial.archetypeBarrierPasses[left] = m_state.nonTrivial.archetypeBarrierPasses[right];
1371 m_state.nonTrivial.archetypeBarrierPasses[right] = tmp;
1375 void ensure_comp_indices() {
1376 if (!m_state.exec.compIndicesPending)
1379 m_state.exec.archetypeCompIndices.clear();
1380 m_state.exec.archetypeCompIndices.reserve(m_state.archetypeCache.size());
1381 for (
const auto* pArchetype: m_state.archetypeCache)
1382 m_state.exec.archetypeCompIndices.push_back(create_comp_indices(pArchetype));
1384 m_state.exec.compIndicesPending =
false;
1387 GAIA_NODISCARD
bool has_inherited_data_payload()
const {
1388 return ctx().data.
deps.has_dep_flag(QueryCtx::DependencyHasInheritedDataTerms);
1391 void ensure_inherited_data() {
1392 if (!m_state.exec.inheritedDataPending)
1395 if (!has_inherited_data_payload()) {
1396 m_state.exec.archetypeInheritedData.clear();
1397 m_state.exec.inheritedDataPending =
false;
1401 m_state.exec.archetypeInheritedData.clear();
1402 m_state.exec.archetypeInheritedData.reserve(m_state.archetypeCache.size());
1403 for (
const auto* pArchetype: m_state.archetypeCache)
1404 create_inherited_data(pArchetype);
1406 m_state.exec.inheritedDataPending =
false;
1409 void ensure_group_data() {
1410 if (m_plan.ctx.data.groupBy == EntityBad || !m_state.grouped.dataPending)
1414 bool operator()(GroupId a, GroupId b)
const {
1419 core::sort(m_state.grouped.archetypeGroupIds, sort_cond{}, [&](uint32_t left, uint32_t right) {
1420 swap_archetype_cache_entry(left, right);
1423 m_state.grouped.archetypeGroupData.clear();
1424 m_state.grouped.selectedGroupDataValid =
false;
1426 if (m_state.grouped.archetypeGroupIds.empty()) {
1427 m_state.grouped.dataPending =
false;
1431 GroupId groupId = m_state.grouped.archetypeGroupIds[0];
1432 uint32_t idxFirst = 0;
1433 const auto cnt = (uint32_t)m_state.grouped.archetypeGroupIds.size();
1434 for (uint32_t i = 1; i < cnt; ++i) {
1435 if (m_state.grouped.archetypeGroupIds[i] == groupId)
1438 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, i - 1,
false});
1439 groupId = m_state.grouped.archetypeGroupIds[i];
1443 m_state.grouped.archetypeGroupData.push_back({groupId, idxFirst, cnt - 1,
false});
1444 m_state.grouped.dataPending =
false;
1447 void ensure_depth_order_hierarchy_barrier_cache_inter() {
1448 if (!world_depth_order_prunes_disabled_subtrees(*world(), m_plan.ctx.data.groupBy))
1451 ensure_group_data();
1453 const auto currRelationVersion = world_rel_version(*world(), m_plan.ctx.data.groupBy);
1454 const auto currEnabledVersion = world_enabled_hierarchy_version(*world());
1455 if (m_state.nonTrivial.barrierRelVersion == currRelationVersion &&
1456 m_state.nonTrivial.barrierEnabledVersion == currEnabledVersion)
1459 m_state.nonTrivial.archetypeBarrierPasses.resize(m_state.archetypeCache.size(), 1);
1461 const auto relation = m_plan.ctx.data.groupBy;
1462 for (uint32_t i = 0; i < m_state.archetypeCache.size(); ++i) {
1463 const auto* pArchetype = m_state.archetypeCache[i];
1464 auto& barrierPasses = m_state.nonTrivial.archetypeBarrierPasses[i];
1467 auto ids = pArchetype->ids_view();
1468 for (
auto idsIdx: pArchetype->pair_rel_indices(relation)) {
1469 const auto pair = ids[idsIdx];
1470 const auto parent = world_pair_target_if_alive(*world(), pair);
1471 if (parent == EntityBad || !world_entity_enabled_hierarchy(*world(), parent, relation)) {
1478 m_state.nonTrivial.barrierRelVersion = currRelationVersion;
1479 m_state.nonTrivial.barrierEnabledVersion = currEnabledVersion;
1482 ArchetypeCompIndices create_comp_indices(
const Archetype* pArchetype) {
1483 ArchetypeCompIndices cacheData{};
1485 const auto terms = ctx().data.terms_view();
1486 const auto cnt = (uint32_t)terms.size();
1488 const auto& term = terms[i];
1489 const auto fieldIdx = term.fieldIndex;
1490 const auto queryId = term.id;
1491 if (!queryId.pair() && world_is_out_of_line_component(*world(), queryId)) {
1492 const auto compIdx = core::get_index_unsafe(pArchetype->ids_view(), queryId);
1493 GAIA_ASSERT(compIdx != BadIndex);
1494 cacheData.indices[fieldIdx] = 0xFF;
1498 auto compIdx = world_component_index_comp_idx(*world(), *pArchetype, queryId);
1499 if (compIdx == BadIndex) {
1502 compIdx = core::get_index_unsafe(pArchetype->ids_view(), queryId);
1504 GAIA_ASSERT(compIdx != BadIndex);
1506 cacheData.indices[fieldIdx] = (uint8_t)compIdx;
1511 void create_inherited_data(
const Archetype* pArchetype) {
1512 ArchetypeInheritedData inheritedData{};
1515 const auto terms = ctx().data.terms_view();
1516 const auto cnt = (uint32_t)terms.size();
1518 const auto& term = terms[i];
1519 if (term.src != EntityBad || term.entTrav != EntityBad || term_has_variables(term))
1521 if (term.matchKind != QueryMatchKind::Semantic)
1523 const auto queryId = term.id;
1524 if (queryId == EntityBad || is_wildcard(queryId) || is_variable((EntityId)queryId.id()))
1526 if (world_is_out_of_line_component(*world(), queryId))
1528 if (!world_term_uses_inherit_policy(*world(), queryId))
1530 if (pArchetype->has(queryId))
1533 const auto owner = world_query_first_inherited_owner(*world(), *pArchetype, queryId);
1534 GAIA_ASSERT(owner != EntityBad);
1535 inheritedData.data[term.fieldIndex] = world_query_inherited_arg_data_const_ptr(*world(), owner, queryId);
1538 m_state.exec.archetypeInheritedData.push_back(inheritedData);
1541 void add_archetype_to_cache_no_grouping(
1542 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
1543 GAIA_PROF_SCOPE(queryinfo::add_cache_ng);
1545 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
1547 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
1549 m_state.archetypeSet.emplace(pArchetype);
1550 m_state.archetypeCache.push_back(pArchetype);
1551 m_state.exec.compIndicesPending =
true;
1552 m_state.exec.inheritedDataPending =
true;
1553 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
1554 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
1555 if (trackMembershipChange)
1556 mark_result_cache_membership_changed();
1559 void add_archetype_to_seed_cache(
const Archetype* pArchetype,
bool assumeAbsent =
false) {
1560 if (!assumeAbsent && m_state.seedArchetypeSet.contains(pArchetype))
1562 GAIA_ASSERT(assumeAbsent || !m_state.seedArchetypeSet.contains(pArchetype));
1564 m_state.seedArchetypeSet.emplace(pArchetype);
1565 m_state.seedArchetypeCache.push_back(pArchetype);
1570 GAIA_ASSERT(m_plan.ctx.data.groupBy == EntityBad);
1571 GAIA_ASSERT(m_plan.ctx.data.sortByFunc ==
nullptr);
1572 GAIA_ASSERT(!m_state.seedArchetypeSet.contains(pArchetype));
1573 GAIA_ASSERT(!m_state.archetypeSet.contains(pArchetype));
1575 m_state.seedArchetypeSet.emplace(pArchetype);
1576 m_state.seedArchetypeCache.push_back(pArchetype);
1578 m_state.archetypeSet.emplace(pArchetype);
1579 m_state.archetypeCache.push_back(pArchetype);
1580 m_state.exec.compIndicesPending =
true;
1581 m_state.exec.inheritedDataPending =
true;
1582 if (trackMembershipChange)
1583 mark_result_cache_membership_changed();
1586 void add_archetype_to_cache_w_grouping(
1587 const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
1588 GAIA_PROF_SCOPE(queryinfo::add_cache_wg);
1590 if (!assumeAbsent && m_state.archetypeSet.contains(pArchetype))
1592 GAIA_ASSERT(assumeAbsent || !m_state.archetypeSet.contains(pArchetype));
1594 m_state.grouped.selectedGroupDataValid =
false;
1596 const GroupId groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
1598 m_state.archetypeSet.emplace(pArchetype);
1599 m_state.archetypeCache.push_back(pArchetype);
1600 m_state.grouped.archetypeGroupIds.push_back(groupId);
1601 m_state.grouped.dataPending =
true;
1602 m_state.exec.compIndicesPending =
true;
1603 m_state.exec.inheritedDataPending =
true;
1604 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
1605 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
1606 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortGroups;
1607 if (trackMembershipChange)
1608 mark_result_cache_membership_changed();
1611 void add_archetype_to_cache(
const Archetype* pArchetype,
bool trackMembershipChange,
bool assumeAbsent =
false) {
1612 if (m_plan.ctx.data.sortByFunc !=
nullptr)
1613 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortEntities;
1615 if (m_plan.ctx.data.groupBy != EntityBad)
1616 add_archetype_to_cache_w_grouping(pArchetype, trackMembershipChange, assumeAbsent);
1618 add_archetype_to_cache_no_grouping(pArchetype, trackMembershipChange, assumeAbsent);
1621 void add_archetype_to_transient_cache(
const Archetype* pArchetype) {
1622 m_state.archetypeCache.push_back(pArchetype);
1623 m_state.exec.compIndicesPending =
true;
1624 m_state.exec.inheritedDataPending =
true;
1625 if (m_plan.ctx.data.groupBy != EntityBad) {
1626 const auto groupId = m_plan.ctx.data.groupByFunc(*m_plan.ctx.w, *pArchetype, m_plan.ctx.data.groupBy);
1627 m_state.grouped.archetypeGroupIds.push_back(groupId);
1628 m_state.grouped.dataPending =
true;
1635 const_cast<QueryInfo*
>(
this)->ensure_group_data();
1636 if (m_plan.ctx.data.groupBy == EntityBad || runtimeGroupId == 0)
1639 if (!m_state.grouped.selectedGroupDataValid || m_state.grouped.selectedGroupData.groupId != runtimeGroupId) {
1641 uint32_t right = (uint32_t)m_state.grouped.archetypeGroupData.size();
1642 while (left < right) {
1643 const uint32_t mid = left + ((right - left) >> 1);
1644 const auto midGroupId = m_state.grouped.archetypeGroupData[mid].groupId;
1645 if (midGroupId < runtimeGroupId)
1651 if (left < m_state.grouped.archetypeGroupData.size() &&
1652 m_state.grouped.archetypeGroupData[left].groupId == runtimeGroupId) {
1653 m_state.grouped.selectedGroupData = m_state.grouped.archetypeGroupData[left];
1654 m_state.grouped.selectedGroupDataValid =
true;
1655 return &m_state.grouped.selectedGroupData;
1658 m_state.grouped.selectedGroupData = {};
1659 m_state.grouped.selectedGroupDataValid =
false;
1663 return &m_state.grouped.selectedGroupData;
1666 GAIA_NODISCARD
bool has_same_result_membership_as_seed_cache()
const {
1667 if (m_state.archetypeSet.size() != m_state.seedArchetypeSet.size())
1670 for (
const auto* pArchetype: m_state.seedArchetypeCache) {
1671 if (!m_state.archetypeSet.contains(pArchetype))
1678 void sync_result_cache_from_seed_cache() {
1679 const bool membershipChanged = !has_same_result_membership_as_seed_cache();
1680 clear_result_cache();
1681 const auto cnt = (uint32_t)m_state.seedArchetypeCache.size();
1683 add_archetype_to_cache(m_state.seedArchetypeCache[i],
false);
1685 if (membershipChanged)
1686 mark_result_cache_membership_changed();
1689 bool del_archetype_from_cache(
const Archetype* pArchetype) {
1690 const auto it = m_state.archetypeSet.find(pArchetype);
1691 if (it == m_state.archetypeSet.end())
1694 m_state.archetypeSet.erase(it);
1696 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
1697 GAIA_ASSERT(archetypeIdx != BadIndex);
1698 if (archetypeIdx == BadIndex)
1701 if (m_plan.ctx.data.sortByFunc !=
nullptr)
1702 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortEntities;
1704 core::swap_erase(m_state.archetypeCache, archetypeIdx);
1705 if (archetypeIdx < m_state.exec.archetypeCompIndices.size())
1706 core::swap_erase(m_state.exec.archetypeCompIndices, archetypeIdx);
1707 if (archetypeIdx < m_state.exec.archetypeInheritedData.size())
1708 core::swap_erase(m_state.exec.archetypeInheritedData, archetypeIdx);
1709 if (archetypeIdx < m_state.grouped.archetypeGroupIds.size())
1710 core::swap_erase(m_state.grouped.archetypeGroupIds, archetypeIdx);
1711 if (archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size())
1712 core::swap_erase(m_state.nonTrivial.archetypeBarrierPasses, archetypeIdx);
1714 if (m_plan.ctx.data.groupBy != EntityBad) {
1715 m_state.grouped.selectedGroupDataValid =
false;
1716 m_state.grouped.archetypeGroupData.clear();
1717 m_state.grouped.dataPending =
true;
1718 m_plan.ctx.data.flags |= QueryCtx::QueryFlags::SortGroups;
1720 m_state.nonTrivial.barrierRelVersion = UINT32_MAX;
1721 m_state.nonTrivial.barrierEnabledVersion = UINT32_MAX;
1723 mark_result_cache_membership_changed();
1727 bool del_archetype_from_seed_cache(
const Archetype* pArchetype) {
1728 const auto it = m_state.seedArchetypeSet.find(pArchetype);
1729 if (it == m_state.seedArchetypeSet.end())
1732 m_state.seedArchetypeSet.erase(it);
1734 const auto archetypeIdx = core::get_index(m_state.seedArchetypeCache, pArchetype);
1735 GAIA_ASSERT(archetypeIdx != BadIndex);
1736 if (archetypeIdx == BadIndex)
1739 core::swap_erase(m_state.seedArchetypeCache, archetypeIdx);
1743 GAIA_NODISCARD World* world() {
1744 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
1745 return const_cast<World*
>(m_plan.ctx.w);
1747 GAIA_NODISCARD
const World* world()
const {
1748 GAIA_ASSERT(m_plan.ctx.w !=
nullptr);
1749 return m_plan.ctx.w;
1752 GAIA_NODISCARD QuerySerBuffer& ser_buffer() {
1753 return m_plan.ctx.q.ser_buffer(world());
1755 void ser_buffer_reset() {
1756 m_plan.ctx.q.ser_buffer_reset(world());
1759 GAIA_NODISCARD QueryCtx& ctx() {
1762 GAIA_NODISCARD
const QueryCtx& ctx()
const {
1766 GAIA_NODISCARD util::str bytecode()
const {
1767 return m_plan.vm.bytecode(*world());
1770 GAIA_NODISCARD uint32_t op_count()
const {
1771 return m_plan.vm.op_count();
1774 GAIA_NODISCARD uint64_t op_signature()
const {
1775 return m_plan.vm.op_signature();
1778 GAIA_NODISCARD
bool has_filters()
const {
1779 const auto& ctxData = m_plan.ctx.data;
1780 return ctxData.changedCnt > 0;
1785 const auto& ctxData = m_plan.ctx.data;
1786 return ctxData.deps.has_dep_flag(QueryCtx::DependencyHasEntityFilterTerms);
1789 GAIA_NODISCARD QueryCtx::DirectTargetEvalKind direct_target_eval_kind()
const {
1790 return m_plan.ctx.data.directTargetEvalKind;
1793 GAIA_NODISCARD Entity direct_target_eval_id()
const {
1794 return m_plan.ctx.data.directTargetEvalId;
1799 const auto& ctxData = m_plan.ctx.data;
1800 return (ctxData.flags & QueryCtx::QueryFlags::MatchPrefab) != 0 ||
1801 (ctxData.flags & QueryCtx::QueryFlags::HasPrefabTerms) != 0;
1804 template <
typename... T>
1805 GAIA_NODISCARD
bool has_any()
const {
1806 return (has_inter<T>(QueryOpKind::Any) || ...);
1809 template <
typename... T>
1810 GAIA_NODISCARD
bool has_or()
const {
1811 return (has_inter<T>(QueryOpKind::Or) || ...);
1814 template <
typename... T>
1815 GAIA_NODISCARD
bool has_all()
const {
1816 return (has_inter<T>(QueryOpKind::All) && ...);
1819 template <
typename... T>
1820 GAIA_NODISCARD
bool has_no()
const {
1821 return (!has_inter<T>(QueryOpKind::Not) && ...);
1827 GAIA_PROF_SCOPE(queryinfo::remove);
1829 const bool removedFromSeed = del_archetype_from_seed_cache(pArchetype);
1830 const bool removedFromResult = del_archetype_from_cache(pArchetype);
1831 if (!removedFromSeed && !removedFromResult)
1837 for (
auto&
pair: matches) {
1838 auto& lastMatchedArchetypeIdx =
pair.second;
1839 if (lastMatchedArchetypeIdx > 0)
1840 --lastMatchedArchetypeIdx;
1843 clearMatches(m_plan.ctx.data.lastMatchedArchetypeIdx_All);
1844 clearMatches(m_plan.ctx.data.lastMatchedArchetypeIdx_Or);
1845 clearMatches(m_plan.ctx.data.lastMatchedArchetypeIdx_Not);
1850 const_cast<QueryInfo*
>(
this)->ensure_comp_indices();
1851 const auto& ctxData = m_state.exec.archetypeCompIndices[archetypeIdx];
1855 InheritedTermDataView inherited_data_view(uint32_t archetypeIdx)
const {
1856 const_cast<QueryInfo*
>(
this)->ensure_inherited_data();
1857 if (archetypeIdx >= m_state.exec.archetypeInheritedData.size())
1859 const auto& ctxData = m_state.exec.archetypeInheritedData[archetypeIdx];
1863 InheritedTermDataView inherited_data_view(
const Archetype* pArchetype)
const {
1864 if (!has_inherited_data_payload())
1866 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
1867 if (archetypeIdx == BadIndex)
1869 return inherited_data_view((uint32_t)archetypeIdx);
1872 void ensure_depth_order_hierarchy_barrier_cache() {
1873 ensure_depth_order_hierarchy_barrier_cache_inter();
1878 if (m_state.exec.compIndicesPending)
1880 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
1881 if (archetypeIdx == BadIndex)
1886 InheritedTermDataView try_inherited_data_view(
const Archetype* pArchetype)
const {
1887 if (!has_inherited_data_payload() || m_state.exec.inheritedDataPending)
1889 const auto archetypeIdx = core::get_index(m_state.archetypeCache, pArchetype);
1890 if (archetypeIdx == BadIndex)
1892 return inherited_data_view((uint32_t)archetypeIdx);
1895 GAIA_NODISCARD GroupId group_id(uint32_t archetypeIdx)
const {
1896 const_cast<QueryInfo*
>(
this)->ensure_group_data();
1897 GAIA_ASSERT(archetypeIdx < m_state.grouped.archetypeGroupIds.size());
1898 return m_state.grouped.archetypeGroupIds[archetypeIdx];
1901 GAIA_NODISCARD
bool barrier_passes(uint32_t archetypeIdx)
const {
1902 const_cast<QueryInfo*
>(
this)->ensure_depth_order_hierarchy_barrier_cache();
1903 if (m_state.nonTrivial.archetypeBarrierPasses.empty())
1905 GAIA_ASSERT(archetypeIdx < m_state.nonTrivial.archetypeBarrierPasses.size());
1906 return m_state.nonTrivial.archetypeBarrierPasses[archetypeIdx] != 0;
1909 GAIA_NODISCARD CArchetypeDArray::iterator begin() {
1910 return m_state.archetypeCache.begin();
1913 GAIA_NODISCARD CArchetypeDArray::const_iterator begin()
const {
1914 return m_state.archetypeCache.begin();
1917 GAIA_NODISCARD CArchetypeDArray::const_iterator cbegin()
const {
1918 return m_state.archetypeCache.begin();
1921 GAIA_NODISCARD CArchetypeDArray::iterator end() {
1922 return m_state.archetypeCache.end();
1925 GAIA_NODISCARD CArchetypeDArray::const_iterator end()
const {
1926 return m_state.archetypeCache.end();
1929 GAIA_NODISCARD CArchetypeDArray::const_iterator cend()
const {
1930 return m_state.archetypeCache.end();
1934 return std::span{(
const Archetype**)m_state.archetypeCache.data(), m_state.archetypeCache.size()};
1938 return std::span{m_state.nonTrivial.archetypeSortData.data(), m_state.nonTrivial.archetypeSortData.size()};
1942 const_cast<QueryInfo*
>(
this)->ensure_group_data();
1943 return std::span{m_state.grouped.archetypeGroupData.data(), m_state.grouped.archetypeGroupData.size()};