2#include "gaia/config/config.h"
4#include "gaia/cnt/darray.h"
5#include "gaia/cnt/map.h"
6#include "gaia/cnt/paged_storage.h"
7#include "gaia/core/utility.h"
8#include "gaia/ecs/component.h"
9#include "gaia/ecs/id.h"
10#include "gaia/ecs/query_common.h"
11#include "gaia/ecs/query_info.h"
17 struct to_page_storage_id<ecs::QueryInfo> {
21 static page_storage_id
get(
const ecs::QueryInfo& item)
noexcept {
28 class QueryLookupKey {
29 QueryLookupHash m_hash;
30 const QueryCtx* m_pCtx;
33 static constexpr bool IsDirectHashKey =
true;
35 QueryLookupKey(): m_hash({0}), m_pCtx(
nullptr) {}
36 explicit QueryLookupKey(QueryLookupHash hash,
const QueryCtx* pCtx): m_hash(hash), m_pCtx(pCtx) {}
41 return (
size_t)m_hash.hash;
44 bool operator==(
const QueryLookupKey& other)
const {
47 if GAIA_LIKELY (m_hash != other.m_hash)
50 if (m_pCtx == other.m_pCtx)
53 const auto lhsReal = m_pCtx->q.handle.
id() != QueryIdBad;
54 const auto rhsReal = other.m_pCtx->q.handle.
id() != QueryIdBad;
58 if (lhsReal && rhsReal)
63 return QueryCtx::equals_no_handle_assumption(*m_pCtx, *other.m_pCtx);
70 enum class ChangeKind : uint8_t {
84 QueryInfo& register_query_info(QueryHandle handle, QueryInfo& info) {
86 add_entity_to_query_pairs(info.ctx().data.ids_view(), handle);
87 add_rel_to_query_pairs(info.ctx(), handle);
88 add_sort_to_query_pairs(info.ctx(), handle);
89 add_sorted_query(info.ctx(), handle);
90 add_create_to_query_pairs(info.ctx(), handle);
97 struct CreateQueryCandidate {
99 Entity matchedSelector = EntityBad;
104 enum class CreateSelectorKind : uint8_t {
114 struct TrackedArchetypes {
115 cnt::darray<const Archetype*> archetypes;
116 uint32_t syncedRevision = 0;
120 cnt::map<QueryLookupKey, QueryInfo*> m_pCache;
122 cnt::paged_ilist<QueryInfo, QueryHandle> m_queryArr;
124 uint64_t m_epoch = 0;
127 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_entityToQuery;
129 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_relationToQuery;
131 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_sortEntityToQuery;
133 cnt::darray<QueryHandle> m_sortedQueries;
135 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_entityToCreateQuery;
137 cnt::map<ArchetypeIdLookupKey, cnt::darray<QueryHandle>> m_archetypeToQuery;
139 cnt::map<QueryHandleLookupKey, TrackedArchetypes> m_queryToArchetype;
141 cnt::darray<CreateQueryCandidate> m_createQueryHandleScratch;
143 cnt::darray<uint32_t> m_createQueryHandleStampById;
144 uint32_t m_createQueryHandleStamp = 1;
146 uint32_t m_createQuerySelectorCnt[(size_t)CreateSelectorKind::Count] = {};
150 m_queryArr.reserve(256);
153 ~QueryCache() =
default;
155 QueryCache(QueryCache&&) =
delete;
156 QueryCache(
const QueryCache&) =
delete;
157 QueryCache& operator=(QueryCache&&) =
delete;
158 QueryCache& operator=(
const QueryCache&) =
delete;
163 GAIA_NODISCARD
bool valid(QueryHandle handle)
const {
164 if (handle.id() == QueryIdBad)
167 if (!m_queryArr.has(handle.id()))
170 const auto& h = m_queryArr[handle.id()];
171 return h.idx == handle.id() && h.gen == handle.gen();
179 m_entityToQuery.clear();
180 m_relationToQuery.clear();
181 m_sortEntityToQuery.clear();
182 m_sortedQueries.clear();
183 m_entityToCreateQuery.clear();
184 m_archetypeToQuery.clear();
185 m_queryToArchetype.clear();
186 m_createQueryHandleScratch.clear();
187 m_createQueryHandleStampById.clear();
188 m_createQueryHandleStamp = 1;
189 for (
auto& cnt: m_createQuerySelectorCnt)
195 GAIA_NODISCARD uint64_t epoch()
const {
201 void clear_archetype_tracking() {
202 m_archetypeToQuery.clear();
203 m_queryToArchetype.clear();
209 QueryInfo* try_get(QueryHandle handle) {
213 auto& info = m_queryArr[handle.id()];
214 GAIA_ASSERT(info.idx == handle.id());
215 GAIA_ASSERT(info.gen == handle.gen());
222 const QueryInfo* try_get(QueryHandle handle)
const {
226 const auto& info = m_queryArr[handle.id()];
227 GAIA_ASSERT(info.idx == handle.id());
228 GAIA_ASSERT(info.gen == handle.gen());
232#if GAIA_ECS_TEST_HOOKS
234 GAIA_NODISCARD
bool verify_archetype_tracking()
const {
235 for (
const auto& pair: m_queryToArchetype) {
236 const auto handle = pair.first.handle();
237 const auto* pInfo = try_get(handle);
238 if (pInfo ==
nullptr || pInfo->refs() == 0)
241 const auto& tracked = pair.second.archetypes;
242 for (uint32_t i = 0; i < tracked.size(); ++i) {
243 const auto* pArchetype = tracked[i];
244 if (pArchetype ==
nullptr)
247 for (uint32_t j = i + 1; j < tracked.size(); ++j) {
248 if (tracked[j] == pArchetype)
252 if (!archetype_span_contains(pInfo->cache_archetype_view(), pArchetype))
255 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
256 const auto reverseIt = m_archetypeToQuery.find(archetypeKey);
257 if (reverseIt == m_archetypeToQuery.end() || !core::has(reverseIt->second, handle))
262 for (
const auto& pair: m_archetypeToQuery) {
263 const auto& handles = pair.second;
264 for (uint32_t i = 0; i < handles.size(); ++i) {
265 const auto handle = handles[i];
266 const auto* pInfo = try_get(handle);
267 if (pInfo ==
nullptr || pInfo->refs() == 0)
270 for (uint32_t j = i + 1; j < handles.size(); ++j) {
271 if (handles[j] == handle)
275 const auto trackedIt = m_queryToArchetype.find(QueryHandleLookupKey(handle));
276 if (trackedIt == m_queryToArchetype.end())
279 if (!tracked_archetypes_contain(trackedIt->second.archetypes, pair.first))
289 GAIA_NODISCARD uint32_t test_query_count()
const {
290 return (uint32_t)m_queryArr.item_count();
297 QueryInfo& get(QueryHandle handle) {
298 GAIA_ASSERT(valid(handle));
300 auto& info = m_queryArr[handle.id()];
301 GAIA_ASSERT(info.idx == handle.id());
302 GAIA_ASSERT(info.gen == handle.gen());
313 const EntityToArchetypeMap& entityToArchetypeMap,
314 std::span<const Archetype*> allArchetypes) {
315 GAIA_ASSERT(ctx.hashLookup.hash != 0);
318 auto ret = m_pCache.try_emplace(QueryLookupKey(ctx.hashLookup, &ctx),
nullptr);
320 auto* pInfo = ret.first->second;
321 GAIA_ASSERT(pInfo !=
nullptr);
327 QueryInfoCreationCtx creationCtx{};
328 creationCtx.pQueryCtx = &ctx;
329 creationCtx.pEntityToArchetypeMap = &entityToArchetypeMap;
330 creationCtx.allArchetypes = allArchetypes;
331 auto handle = m_queryArr.alloc(&creationCtx);
335 auto& info = get(handle);
337 ret.first->second = &info;
338 auto new_p = robin_hood::pair(std::make_pair(QueryLookupKey(ctx.hashLookup, &info.ctx()), &info));
339 ret.first->swap(new_p);
341 return register_query_info(handle, info);
349 QueryInfo& add_local(
351 const EntityToArchetypeMap& entityToArchetypeMap,
352 std::span<const Archetype*> allArchetypes) {
353 QueryInfoCreationCtx creationCtx{};
354 creationCtx.pQueryCtx = &ctx;
355 creationCtx.pEntityToArchetypeMap = &entityToArchetypeMap;
356 creationCtx.allArchetypes = allArchetypes;
357 auto handle = m_queryArr.alloc(&creationCtx);
359 auto& info = get(handle);
361 return register_query_info(handle, info);
367 bool del(QueryHandle handle) {
368 auto* pInfo = try_get(handle);
369 if (pInfo ==
nullptr)
373 if (pInfo->refs() != 0)
376 unregister_query_archetypes(handle);
379 auto it = m_pCache.find(QueryLookupKey(pInfo->ctx().hashLookup, &pInfo->ctx()));
380 if (it != m_pCache.end())
384 del_entity_to_query_pairs(pInfo->ctx().data.ids_view(), handle);
385 del_rel_to_query_pairs(pInfo->ctx(), handle);
386 del_sort_to_query_pairs(pInfo->ctx(), handle);
387 del_sorted_query(pInfo->ctx(), handle);
388 del_create_to_query_pairs(pInfo->ctx(), handle);
389 m_queryArr.free(handle);
396 return m_queryArr.begin();
401 return m_queryArr.end();
406 GAIA_NODISCARD
bool has_relation_query_dependencies()
const {
407 return !m_relationToQuery.empty();
417 void invalidate_queries_for_entity(EntityLookupKey entityKey, ChangeKind changeKind) {
418 auto it = m_entityToQuery.find(entityKey);
419 if (it == m_entityToQuery.end())
422 const auto& handles = it->second;
423 for (
const auto& handle: handles) {
424 auto& info = get(handle);
427 info.invalidate(select_invalidation_kind(info, changeKind));
434 void invalidate_queries_for_rel(Entity relation, ChangeKind changeKind) {
435 auto it = m_relationToQuery.find(EntityLookupKey(relation));
436 if (it == m_relationToQuery.end())
439 for (
const auto handle: it->second) {
440 auto& info = get(handle);
442 info.invalidate(select_invalidation_kind(info, changeKind));
448 GAIA_NODISCARD
bool has_sorted_queries()
const {
449 return !m_sortedQueries.empty();
455 GAIA_NODISCARD
bool has_sorted_queries_for_entity(Entity entity)
const {
456 const auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
457 return it != m_sortEntityToQuery.end() && !it->second.empty();
462 void invalidate_sorted_queries_for_entity(Entity entity) {
463 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
464 if (it == m_sortEntityToQuery.end())
467 for (
const auto handle: it->second) {
468 auto* pInfo = try_get(handle);
469 if (pInfo ==
nullptr || pInfo->refs() == 0)
472 pInfo->invalidate_sort();
477 void invalidate_sorted_queries() {
478 for (
const auto handle: m_sortedQueries) {
479 auto* pInfo = try_get(handle);
480 if (pInfo ==
nullptr || pInfo->refs() == 0)
483 pInfo->invalidate_sort();
489 void sync_archetype_cache(QueryInfo& queryInfo) {
490 const auto handle = QueryInfo::handle(queryInfo);
494 const auto archetypes = queryInfo.cache_archetype_view();
495 const auto key = QueryHandleLookupKey(handle);
496 auto it = m_queryToArchetype.find(key);
497 if (it != m_queryToArchetype.end() && it->second.syncedRevision == queryInfo.result_cache_rev())
500 unregister_query_archetypes(handle);
502 if (archetypes.empty())
505 auto [trackedIt, inserted] = m_queryToArchetype.try_emplace(key);
506 auto& tracked = trackedIt->second.archetypes;
510 tracked.reserve((uint32_t)archetypes.size());
511 for (
const auto* pArchetype: archetypes) {
512 tracked.push_back(pArchetype);
513 add_archetype_query_pair(pArchetype, handle);
515 trackedIt->second.syncedRevision = queryInfo.result_cache_rev();
520 void remove_archetype_from_queries(Archetype* pArchetype) {
521 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
522 auto it = m_archetypeToQuery.find(archetypeKey);
523 if (it == m_archetypeToQuery.end())
526 const auto handles = it->second;
527 for (
const auto handle: handles) {
528 auto* pInfo = try_get(handle);
529 if (pInfo !=
nullptr && pInfo->refs() != 0)
530 pInfo->remove(pArchetype);
532 auto trackedIt = m_queryToArchetype.find(QueryHandleLookupKey(handle));
533 if (trackedIt == m_queryToArchetype.end())
536 auto& tracked = trackedIt->second.archetypes;
537 core::swap_erase(tracked, core::get_index(tracked, pArchetype));
539 m_queryToArchetype.erase(trackedIt);
542 m_archetypeToQuery.erase(it);
547 void register_archetype_with_queries(
const Archetype* pArchetype) {
548 if (m_entityToCreateQuery.empty()) {
553 auto& handles = prepare_create_query_handles();
554 const bool needsExactPairSelectors = has_create_selector_kind(CreateSelectorKind::ExactPair);
555 const bool needsRelWildcardSelectors = has_create_selector_kind(CreateSelectorKind::RelWildcardPair);
556 const bool needsTgtWildcardSelectors = has_create_selector_kind(CreateSelectorKind::TgtWildcardPair);
557 const bool needsAnyPairWildcardSelectors = has_create_selector_kind(CreateSelectorKind::AnyPairWildcard);
558 bool hasAnyPair =
false;
559 cnt::darray_ext<Entity, 16> pairWildcardRelations;
560 for (
const auto entity: pArchetype->ids_view()) {
561 if (!entity.pair()) {
562 add_create_query_handles(entity, handles);
567 if (needsExactPairSelectors)
568 add_create_query_handles(entity, handles);
572 const auto rel = Entity((EntityId)entity.id(), 0,
false,
false);
573 const auto tgt = Entity((EntityId)entity.gen(), 0,
false,
false);
574 if (needsTgtWildcardSelectors)
575 add_create_query_handles(Pair(All, tgt), handles);
576 if (needsRelWildcardSelectors && !core::has(pairWildcardRelations, rel)) {
577 pairWildcardRelations.push_back(rel);
578 add_create_query_handles(Pair(rel, All), handles);
582 if (hasAnyPair && needsAnyPairWildcardSelectors)
583 add_create_query_handles(Pair(All, All), handles);
585 for (
const auto& candidate: handles) {
586 auto* pInfo = try_get(candidate.handle);
587 if (pInfo ==
nullptr || pInfo->refs() == 0)
590 if (!pInfo->register_archetype(*pArchetype, candidate.matchedSelector,
true))
593 register_query_archetype(candidate.handle, pArchetype, pInfo->result_cache_rev());
598#if GAIA_ECS_TEST_HOOKS
603 GAIA_NODISCARD
static bool
604 archetype_span_contains(std::span<const Archetype*> archetypes,
const Archetype* pArchetype) {
605 for (
const auto* pCachedArchetype: archetypes) {
606 if (pCachedArchetype == pArchetype)
616 GAIA_NODISCARD
static bool tracked_archetypes_contain(
617 const cnt::darray<const Archetype*>& archetypes,
const ArchetypeIdLookupKey& archetypeKey) {
618 for (
const auto* pArchetype: archetypes) {
619 if (pArchetype ==
nullptr)
622 if (ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash()) == archetypeKey)
630 static CreateSelectorKind classify_create_selector(Entity entity) {
632 return CreateSelectorKind::Other;
633 if (is_wildcard(entity.id()))
634 return is_wildcard(entity.gen()) ? CreateSelectorKind::AnyPairWildcard : CreateSelectorKind::TgtWildcardPair;
635 if (is_wildcard(entity.gen()))
636 return CreateSelectorKind::RelWildcardPair;
637 return CreateSelectorKind::ExactPair;
643 GAIA_NODISCARD
static constexpr uint32_t selector_kind_idx(CreateSelectorKind kind) {
644 return (uint32_t)kind;
650 GAIA_NODISCARD
bool has_create_selector_kind(CreateSelectorKind kind)
const {
651 return m_createQuerySelectorCnt[selector_kind_idx(kind)] != 0;
655 void track_create_selector(Entity entity) {
656 const auto kind = classify_create_selector(entity);
657 ++m_createQuerySelectorCnt[selector_kind_idx(kind)];
661 void untrack_create_selector(Entity entity) {
662 const auto kind = classify_create_selector(entity);
663 auto& cnt = m_createQuerySelectorCnt[selector_kind_idx(kind)];
664 GAIA_ASSERT(cnt != 0);
672 static QueryInfo::InvalidationKind select_invalidation_kind(
const QueryInfo& info, ChangeKind changeKind) {
673 switch (changeKind) {
674 case ChangeKind::DynamicResult:
675 return QueryInfo::InvalidationKind::Result;
676 case ChangeKind::All:
677 return QueryInfo::InvalidationKind::All;
678 case ChangeKind::Structural:
682 return (info.ctx().data.deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms) ||
683 info.ctx().data.deps.has_dep_flag(QueryCtx::DependencyHasVariableTerms))
684 ? QueryInfo::InvalidationKind::Result
685 : QueryInfo::InvalidationKind::Seed;
689 return QueryInfo::InvalidationKind::All;
695 void add_entity_query_pair(Entity entity, QueryHandle handle) {
696 EntityLookupKey entityKey(entity);
697 const auto it = m_entityToQuery.find(entityKey);
698 if (it == m_entityToQuery.end()) {
699 m_entityToQuery.try_emplace(entityKey, cnt::darray<QueryHandle>{handle});
703 auto& handles = it->second;
704 if (!core::has(handles, handle))
705 handles.push_back(handle);
711 void del_entity_query_pair(Entity entity, QueryHandle handle) {
712 auto it = m_entityToQuery.find(EntityLookupKey(entity));
713 if (it == m_entityToQuery.end())
716 auto& handles = it->second;
717 const auto idx = core::get_index_unsafe(handles, handle);
718 core::swap_erase_unsafe(handles, idx);
722 m_entityToQuery.erase(it);
728 void add_entity_to_query_pairs(EntitySpan entities, QueryHandle handle) {
729 for (
auto entity: entities) {
730 add_entity_query_pair(entity, handle);
737 void del_entity_to_query_pairs(EntitySpan entities, QueryHandle handle) {
738 for (
auto entity: entities) {
739 del_entity_query_pair(entity, handle);
746 void add_create_to_query_pair(Entity entity, QueryHandle handle) {
747 EntityLookupKey entityKey(entity);
748 const auto it = m_entityToCreateQuery.find(entityKey);
749 if (it == m_entityToCreateQuery.end()) {
750 m_entityToCreateQuery.try_emplace(entityKey, cnt::darray<QueryHandle>{handle});
751 track_create_selector(entity);
755 auto& handles = it->second;
756 if (!core::has(handles, handle)) {
757 handles.push_back(handle);
758 track_create_selector(entity);
765 void add_sort_to_query_pair(Entity entity, QueryHandle handle) {
766 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
767 if (it == m_sortEntityToQuery.end()) {
768 m_sortEntityToQuery.try_emplace(EntityLookupKey(entity), cnt::darray<QueryHandle>{handle});
772 auto& handles = it->second;
773 if (!core::has(handles, handle))
774 handles.push_back(handle);
780 void del_sort_to_query_pair(Entity entity, QueryHandle handle) {
781 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
782 if (it == m_sortEntityToQuery.end())
785 auto& handles = it->second;
786 core::swap_erase(handles, core::get_index(handles, handle));
788 m_sortEntityToQuery.erase(it);
794 void add_sort_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
795 if (ctx.data.sortByFunc ==
nullptr || ctx.data.sortBy == EntityBad)
798 add_sort_to_query_pair(ctx.data.sortBy, handle);
804 void del_sort_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
805 if (ctx.data.sortByFunc ==
nullptr || ctx.data.sortBy == EntityBad)
808 del_sort_to_query_pair(ctx.data.sortBy, handle);
814 void add_sorted_query(
const QueryCtx& ctx, QueryHandle handle) {
815 if (ctx.data.sortByFunc ==
nullptr)
818 m_sortedQueries.push_back(handle);
824 void del_sorted_query(
const QueryCtx& ctx, QueryHandle handle) {
825 if (ctx.data.sortByFunc ==
nullptr)
828 const auto idx = core::get_index(m_sortedQueries, handle);
829 GAIA_ASSERT(idx != BadIndex);
831 core::swap_erase(m_sortedQueries, idx);
837 void del_create_to_query_pair(Entity entity, QueryHandle handle) {
838 auto it = m_entityToCreateQuery.find(EntityLookupKey(entity));
839 if (it == m_entityToCreateQuery.end())
842 auto& handles = it->second;
843 core::swap_erase(handles, core::get_index(handles, handle));
844 untrack_create_selector(entity);
846 m_entityToCreateQuery.erase(it);
852 void add_create_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
853 if (ctx.data.cachePolicy != QueryCtx::CachePolicy::Immediate)
859 for (
const auto entity: ctx.data.deps.create_selectors_view())
860 add_create_to_query_pair(entity, handle);
866 void del_create_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
867 if (ctx.data.cachePolicy != QueryCtx::CachePolicy::Immediate)
870 for (
const auto entity: ctx.data.deps.create_selectors_view())
871 del_create_to_query_pair(entity, handle);
877 void add_create_query_handles(Entity selector, cnt::darray<CreateQueryCandidate>& handles) {
878 const auto it = m_entityToCreateQuery.find(EntityLookupKey(selector));
879 if (it == m_entityToCreateQuery.end())
882 for (
const auto handle: it->second) {
883 if (mark_create_query_handle(handle))
884 handles.push_back(CreateQueryCandidate{handle, selector});
890 GAIA_NODISCARD cnt::darray<CreateQueryCandidate>& prepare_create_query_handles() {
891 m_createQueryHandleScratch.clear();
895 ++m_createQueryHandleStamp;
896 if (m_createQueryHandleStamp == 0) {
897 m_createQueryHandleStampById = {};
898 m_createQueryHandleStamp = 1;
901 return m_createQueryHandleScratch;
907 GAIA_NODISCARD
bool mark_create_query_handle(QueryHandle handle) {
908 const auto handleId = (uint32_t)handle.id();
911 if (handleId >= m_createQueryHandleStampById.size())
912 m_createQueryHandleStampById.resize(handleId + 1, 0U, cnt::ResizePolicy::Scale);
914 auto& stamp = m_createQueryHandleStampById[handleId];
915 if (stamp == m_createQueryHandleStamp)
918 stamp = m_createQueryHandleStamp;
925 void add_archetype_query_pair(
const Archetype* pArchetype, QueryHandle handle) {
926 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
927 const auto it = m_archetypeToQuery.find(archetypeKey);
928 if (it == m_archetypeToQuery.end()) {
929 m_archetypeToQuery.try_emplace(archetypeKey, cnt::darray<QueryHandle>{handle});
933 auto& handles = it->second;
935 GAIA_ASSERT(!core::has(handles, handle));
936 handles.push_back(handle);
942 void del_archetype_query_pair(
const Archetype* pArchetype, QueryHandle handle) {
943 auto it = m_archetypeToQuery.find(ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash()));
944 if (it == m_archetypeToQuery.end())
947 auto& handles = it->second;
948 const auto idx = core::get_index(handles, handle);
949 GAIA_ASSERT(idx != BadIndex);
950 core::swap_erase(handles, idx);
952 m_archetypeToQuery.erase(it);
957 void unregister_query_archetypes(QueryHandle handle) {
958 auto it = m_queryToArchetype.find(QueryHandleLookupKey(handle));
959 if (it == m_queryToArchetype.end())
962 const auto& tracked = it->second.archetypes;
963 for (
const auto* pArchetype: tracked)
964 del_archetype_query_pair(pArchetype, handle);
966 m_queryToArchetype.erase(it);
973 void register_query_archetype(QueryHandle handle,
const Archetype* pArchetype, uint32_t syncedRevision) {
974 auto [trackedIt, inserted] = m_queryToArchetype.try_emplace(QueryHandleLookupKey(handle));
975 auto& tracked = trackedIt->second.archetypes;
979 GAIA_ASSERT(inserted || !core::has(tracked, pArchetype));
980 tracked.push_back(pArchetype);
981 trackedIt->second.syncedRevision = syncedRevision;
982 add_archetype_query_pair(pArchetype, handle);
988 void add_rel_query_pair(Entity relation, QueryHandle handle) {
989 const auto key = EntityLookupKey(relation);
990 const auto it = m_relationToQuery.find(key);
991 if (it == m_relationToQuery.end()) {
992 m_relationToQuery.try_emplace(key, cnt::darray<QueryHandle>{handle});
996 auto& handles = it->second;
997 if (!core::has(handles, handle))
998 handles.push_back(handle);
1004 void del_rel_query_pair(Entity relation, QueryHandle handle) {
1005 auto it = m_relationToQuery.find(EntityLookupKey(relation));
1006 if (it == m_relationToQuery.end())
1009 auto& handles = it->second;
1010 core::swap_erase(handles, core::get_index(handles, handle));
1011 if (handles.empty())
1012 m_relationToQuery.erase(it);
1018 void add_rel_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
1019 for (
const auto relation: ctx.data.deps.relations_view())
1020 add_rel_query_pair(relation, handle);
1026 void del_rel_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
1027 for (
const auto relation: ctx.data.deps.relations_view())
1028 del_rel_query_pair(relation, handle);
static page_storage_id get(const T &item) noexcept
Applies the default conversion for an item.
Definition paged_storage.h:47