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;
125 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_entityToQuery;
127 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_relationToQuery;
129 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_sortEntityToQuery;
131 cnt::darray<QueryHandle> m_sortedQueries;
133 cnt::map<EntityLookupKey, cnt::darray<QueryHandle>> m_entityToCreateQuery;
135 cnt::map<ArchetypeIdLookupKey, cnt::darray<QueryHandle>> m_archetypeToQuery;
137 cnt::map<QueryHandleLookupKey, TrackedArchetypes> m_queryToArchetype;
139 cnt::darray<CreateQueryCandidate> m_createQueryHandleScratch;
141 cnt::darray<uint32_t> m_createQueryHandleStampById;
142 uint32_t m_createQueryHandleStamp = 1;
144 uint32_t m_createQuerySelectorCnt[(size_t)CreateSelectorKind::Count] = {};
148 m_queryArr.reserve(256);
151 ~QueryCache() =
default;
153 QueryCache(QueryCache&&) =
delete;
154 QueryCache(
const QueryCache&) =
delete;
155 QueryCache& operator=(QueryCache&&) =
delete;
156 QueryCache& operator=(
const QueryCache&) =
delete;
161 GAIA_NODISCARD
bool valid(QueryHandle handle)
const {
162 if (handle.id() == QueryIdBad)
165 if (!m_queryArr.has(handle.id()))
168 const auto& h = m_queryArr[handle.id()];
169 return h.idx == handle.id() && h.gen == handle.gen();
176 m_entityToQuery.clear();
177 m_relationToQuery.clear();
178 m_sortEntityToQuery.clear();
179 m_sortedQueries.clear();
180 m_entityToCreateQuery.clear();
181 m_archetypeToQuery.clear();
182 m_queryToArchetype.clear();
183 m_createQueryHandleScratch.clear();
184 m_createQueryHandleStampById.clear();
185 m_createQueryHandleStamp = 1;
186 for (
auto& cnt: m_createQuerySelectorCnt)
192 void clear_archetype_tracking() {
193 m_archetypeToQuery.clear();
194 m_queryToArchetype.clear();
200 QueryInfo* try_get(QueryHandle handle) {
204 auto& info = m_queryArr[handle.id()];
205 GAIA_ASSERT(info.idx == handle.id());
206 GAIA_ASSERT(info.gen == handle.gen());
213 const QueryInfo* try_get(QueryHandle handle)
const {
217 const auto& info = m_queryArr[handle.id()];
218 GAIA_ASSERT(info.idx == handle.id());
219 GAIA_ASSERT(info.gen == handle.gen());
223#if GAIA_ECS_TEST_HOOKS
225 GAIA_NODISCARD
bool verify_archetype_tracking()
const {
226 for (
const auto& pair: m_queryToArchetype) {
227 const auto handle = pair.first.handle();
228 const auto* pInfo = try_get(handle);
229 if (pInfo ==
nullptr || pInfo->refs() == 0)
232 const auto& tracked = pair.second.archetypes;
233 for (uint32_t i = 0; i < tracked.size(); ++i) {
234 const auto* pArchetype = tracked[i];
235 if (pArchetype ==
nullptr)
238 for (uint32_t j = i + 1; j < tracked.size(); ++j) {
239 if (tracked[j] == pArchetype)
243 if (!archetype_span_contains(pInfo->cache_archetype_view(), pArchetype))
246 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
247 const auto reverseIt = m_archetypeToQuery.find(archetypeKey);
248 if (reverseIt == m_archetypeToQuery.end() || !core::has(reverseIt->second, handle))
253 for (
const auto& pair: m_archetypeToQuery) {
254 const auto& handles = pair.second;
255 for (uint32_t i = 0; i < handles.size(); ++i) {
256 const auto handle = handles[i];
257 const auto* pInfo = try_get(handle);
258 if (pInfo ==
nullptr || pInfo->refs() == 0)
261 for (uint32_t j = i + 1; j < handles.size(); ++j) {
262 if (handles[j] == handle)
266 const auto trackedIt = m_queryToArchetype.find(QueryHandleLookupKey(handle));
267 if (trackedIt == m_queryToArchetype.end())
270 if (!tracked_archetypes_contain(trackedIt->second.archetypes, pair.first))
280 GAIA_NODISCARD uint32_t test_query_count()
const {
281 return (uint32_t)m_queryArr.item_count();
288 QueryInfo& get(QueryHandle handle) {
289 GAIA_ASSERT(valid(handle));
291 auto& info = m_queryArr[handle.id()];
292 GAIA_ASSERT(info.idx == handle.id());
293 GAIA_ASSERT(info.gen == handle.gen());
304 const EntityToArchetypeMap& entityToArchetypeMap,
305 std::span<const Archetype*> allArchetypes) {
306 GAIA_ASSERT(ctx.hashLookup.hash != 0);
309 auto ret = m_pCache.try_emplace(QueryLookupKey(ctx.hashLookup, &ctx),
nullptr);
311 auto* pInfo = ret.first->second;
312 GAIA_ASSERT(pInfo !=
nullptr);
318 QueryInfoCreationCtx creationCtx{};
319 creationCtx.pQueryCtx = &ctx;
320 creationCtx.pEntityToArchetypeMap = &entityToArchetypeMap;
321 creationCtx.allArchetypes = allArchetypes;
322 auto handle = m_queryArr.alloc(&creationCtx);
326 auto& info = get(handle);
328 ret.first->second = &info;
329 auto new_p = robin_hood::pair(std::make_pair(QueryLookupKey(ctx.hashLookup, &info.ctx()), &info));
330 ret.first->swap(new_p);
332 return register_query_info(handle, info);
340 QueryInfo& add_local(
342 const EntityToArchetypeMap& entityToArchetypeMap,
343 std::span<const Archetype*> allArchetypes) {
344 QueryInfoCreationCtx creationCtx{};
345 creationCtx.pQueryCtx = &ctx;
346 creationCtx.pEntityToArchetypeMap = &entityToArchetypeMap;
347 creationCtx.allArchetypes = allArchetypes;
348 auto handle = m_queryArr.alloc(&creationCtx);
350 auto& info = get(handle);
352 return register_query_info(handle, info);
358 bool del(QueryHandle handle) {
359 auto* pInfo = try_get(handle);
360 if (pInfo ==
nullptr)
364 if (pInfo->refs() != 0)
367 unregister_query_archetypes(handle);
370 auto it = m_pCache.find(QueryLookupKey(pInfo->ctx().hashLookup, &pInfo->ctx()));
371 if (it != m_pCache.end())
375 del_entity_to_query_pairs(pInfo->ctx().data.ids_view(), handle);
376 del_rel_to_query_pairs(pInfo->ctx(), handle);
377 del_sort_to_query_pairs(pInfo->ctx(), handle);
378 del_sorted_query(pInfo->ctx(), handle);
379 del_create_to_query_pairs(pInfo->ctx(), handle);
380 m_queryArr.free(handle);
387 return m_queryArr.begin();
392 return m_queryArr.end();
397 GAIA_NODISCARD
bool has_relation_query_dependencies()
const {
398 return !m_relationToQuery.empty();
408 void invalidate_queries_for_entity(EntityLookupKey entityKey, ChangeKind changeKind) {
409 auto it = m_entityToQuery.find(entityKey);
410 if (it == m_entityToQuery.end())
413 const auto& handles = it->second;
414 for (
const auto& handle: handles) {
415 auto& info = get(handle);
418 info.invalidate(select_invalidation_kind(info, changeKind));
425 void invalidate_queries_for_rel(Entity relation, ChangeKind changeKind) {
426 auto it = m_relationToQuery.find(EntityLookupKey(relation));
427 if (it == m_relationToQuery.end())
430 for (
const auto handle: it->second) {
431 auto& info = get(handle);
433 info.invalidate(select_invalidation_kind(info, changeKind));
439 GAIA_NODISCARD
bool has_sorted_queries()
const {
440 return !m_sortedQueries.empty();
446 GAIA_NODISCARD
bool has_sorted_queries_for_entity(Entity entity)
const {
447 const auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
448 return it != m_sortEntityToQuery.end() && !it->second.empty();
453 void invalidate_sorted_queries_for_entity(Entity entity) {
454 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
455 if (it == m_sortEntityToQuery.end())
458 for (
const auto handle: it->second) {
459 auto* pInfo = try_get(handle);
460 if (pInfo ==
nullptr || pInfo->refs() == 0)
463 pInfo->invalidate_sort();
468 void invalidate_sorted_queries() {
469 for (
const auto handle: m_sortedQueries) {
470 auto* pInfo = try_get(handle);
471 if (pInfo ==
nullptr || pInfo->refs() == 0)
474 pInfo->invalidate_sort();
480 void sync_archetype_cache(QueryInfo& queryInfo) {
481 const auto handle = QueryInfo::handle(queryInfo);
485 const auto archetypes = queryInfo.cache_archetype_view();
486 const auto key = QueryHandleLookupKey(handle);
487 auto it = m_queryToArchetype.find(key);
488 if (it != m_queryToArchetype.end() && it->second.syncedRevision == queryInfo.result_cache_rev())
491 unregister_query_archetypes(handle);
493 if (archetypes.empty())
496 auto [trackedIt, inserted] = m_queryToArchetype.try_emplace(key);
497 auto& tracked = trackedIt->second.archetypes;
501 tracked.reserve((uint32_t)archetypes.size());
502 for (
const auto* pArchetype: archetypes) {
503 tracked.push_back(pArchetype);
504 add_archetype_query_pair(pArchetype, handle);
506 trackedIt->second.syncedRevision = queryInfo.result_cache_rev();
511 void remove_archetype_from_queries(Archetype* pArchetype) {
512 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
513 auto it = m_archetypeToQuery.find(archetypeKey);
514 if (it == m_archetypeToQuery.end())
517 const auto handles = it->second;
518 for (
const auto handle: handles) {
519 auto* pInfo = try_get(handle);
520 if (pInfo !=
nullptr && pInfo->refs() != 0)
521 pInfo->remove(pArchetype);
523 auto trackedIt = m_queryToArchetype.find(QueryHandleLookupKey(handle));
524 if (trackedIt == m_queryToArchetype.end())
527 auto& tracked = trackedIt->second.archetypes;
528 core::swap_erase(tracked, core::get_index(tracked, pArchetype));
530 m_queryToArchetype.erase(trackedIt);
533 m_archetypeToQuery.erase(it);
538 void register_archetype_with_queries(
const Archetype* pArchetype) {
539 if (m_entityToCreateQuery.empty()) {
544 auto& handles = prepare_create_query_handles();
545 const bool needsExactPairSelectors = has_create_selector_kind(CreateSelectorKind::ExactPair);
546 const bool needsRelWildcardSelectors = has_create_selector_kind(CreateSelectorKind::RelWildcardPair);
547 const bool needsTgtWildcardSelectors = has_create_selector_kind(CreateSelectorKind::TgtWildcardPair);
548 const bool needsAnyPairWildcardSelectors = has_create_selector_kind(CreateSelectorKind::AnyPairWildcard);
549 bool hasAnyPair =
false;
550 cnt::darray_ext<Entity, 16> pairWildcardRelations;
551 for (
const auto entity: pArchetype->ids_view()) {
552 if (!entity.pair()) {
553 add_create_query_handles(entity, handles);
558 if (needsExactPairSelectors)
559 add_create_query_handles(entity, handles);
563 const auto relKind = entity.entity() ? EntityKind::EK_Uni : EntityKind::EK_Gen;
564 const auto rel = Entity((EntityId)entity.id(), 0,
false,
false, relKind);
565 const auto tgt = Entity((EntityId)entity.gen(), 0,
false,
false, entity.kind());
566 if (needsTgtWildcardSelectors)
567 add_create_query_handles(Pair(All, tgt), handles);
568 if (needsRelWildcardSelectors && !core::has(pairWildcardRelations, rel)) {
569 pairWildcardRelations.push_back(rel);
570 add_create_query_handles(Pair(rel, All), handles);
574 if (hasAnyPair && needsAnyPairWildcardSelectors)
575 add_create_query_handles(Pair(All, All), handles);
577 for (
const auto& candidate: handles) {
578 auto* pInfo = try_get(candidate.handle);
579 if (pInfo ==
nullptr || pInfo->refs() == 0)
582 if (!pInfo->register_archetype(*pArchetype, candidate.matchedSelector,
true))
585 register_query_archetype(candidate.handle, pArchetype, pInfo->result_cache_rev());
590#if GAIA_ECS_TEST_HOOKS
595 GAIA_NODISCARD
static bool
596 archetype_span_contains(std::span<const Archetype*> archetypes,
const Archetype* pArchetype) {
597 for (
const auto* pCachedArchetype: archetypes) {
598 if (pCachedArchetype == pArchetype)
608 GAIA_NODISCARD
static bool tracked_archetypes_contain(
609 const cnt::darray<const Archetype*>& archetypes,
const ArchetypeIdLookupKey& archetypeKey) {
610 for (
const auto* pArchetype: archetypes) {
611 if (pArchetype ==
nullptr)
614 if (ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash()) == archetypeKey)
622 static CreateSelectorKind classify_create_selector(Entity entity) {
624 return CreateSelectorKind::Other;
625 if (is_wildcard(entity.id()))
626 return is_wildcard(entity.gen()) ? CreateSelectorKind::AnyPairWildcard : CreateSelectorKind::TgtWildcardPair;
627 if (is_wildcard(entity.gen()))
628 return CreateSelectorKind::RelWildcardPair;
629 return CreateSelectorKind::ExactPair;
635 GAIA_NODISCARD
static constexpr uint32_t selector_kind_idx(CreateSelectorKind kind) {
636 return (uint32_t)kind;
642 GAIA_NODISCARD
bool has_create_selector_kind(CreateSelectorKind kind)
const {
643 return m_createQuerySelectorCnt[selector_kind_idx(kind)] != 0;
647 void track_create_selector(Entity entity) {
648 const auto kind = classify_create_selector(entity);
649 ++m_createQuerySelectorCnt[selector_kind_idx(kind)];
653 void untrack_create_selector(Entity entity) {
654 const auto kind = classify_create_selector(entity);
655 auto& cnt = m_createQuerySelectorCnt[selector_kind_idx(kind)];
656 GAIA_ASSERT(cnt != 0);
664 static QueryInfo::InvalidationKind select_invalidation_kind(
const QueryInfo& info, ChangeKind changeKind) {
665 switch (changeKind) {
666 case ChangeKind::DynamicResult:
667 return QueryInfo::InvalidationKind::Result;
668 case ChangeKind::All:
669 return QueryInfo::InvalidationKind::All;
670 case ChangeKind::Structural:
674 return (info.ctx().data.deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms) ||
675 info.ctx().data.deps.has_dep_flag(QueryCtx::DependencyHasVariableTerms))
676 ? QueryInfo::InvalidationKind::Result
677 : QueryInfo::InvalidationKind::Seed;
681 return QueryInfo::InvalidationKind::All;
687 void add_entity_query_pair(Entity entity, QueryHandle handle) {
688 EntityLookupKey entityKey(entity);
689 const auto it = m_entityToQuery.find(entityKey);
690 if (it == m_entityToQuery.end()) {
691 m_entityToQuery.try_emplace(entityKey, cnt::darray<QueryHandle>{handle});
695 auto& handles = it->second;
696 if (!core::has(handles, handle))
697 handles.push_back(handle);
703 void del_entity_query_pair(Entity entity, QueryHandle handle) {
704 auto it = m_entityToQuery.find(EntityLookupKey(entity));
705 if (it == m_entityToQuery.end())
708 auto& handles = it->second;
709 const auto idx = core::get_index_unsafe(handles, handle);
710 core::swap_erase_unsafe(handles, idx);
714 m_entityToQuery.erase(it);
720 void add_entity_to_query_pairs(EntitySpan entities, QueryHandle handle) {
721 for (
auto entity: entities) {
722 add_entity_query_pair(entity, handle);
729 void del_entity_to_query_pairs(EntitySpan entities, QueryHandle handle) {
730 for (
auto entity: entities) {
731 del_entity_query_pair(entity, handle);
738 void add_create_to_query_pair(Entity entity, QueryHandle handle) {
739 EntityLookupKey entityKey(entity);
740 const auto it = m_entityToCreateQuery.find(entityKey);
741 if (it == m_entityToCreateQuery.end()) {
742 m_entityToCreateQuery.try_emplace(entityKey, cnt::darray<QueryHandle>{handle});
743 track_create_selector(entity);
747 auto& handles = it->second;
748 if (!core::has(handles, handle)) {
749 handles.push_back(handle);
750 track_create_selector(entity);
757 void add_sort_to_query_pair(Entity entity, QueryHandle handle) {
758 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
759 if (it == m_sortEntityToQuery.end()) {
760 m_sortEntityToQuery.try_emplace(EntityLookupKey(entity), cnt::darray<QueryHandle>{handle});
764 auto& handles = it->second;
765 if (!core::has(handles, handle))
766 handles.push_back(handle);
772 void del_sort_to_query_pair(Entity entity, QueryHandle handle) {
773 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
774 if (it == m_sortEntityToQuery.end())
777 auto& handles = it->second;
778 core::swap_erase(handles, core::get_index(handles, handle));
780 m_sortEntityToQuery.erase(it);
786 void add_sort_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
787 if (ctx.data.sortByFunc ==
nullptr || ctx.data.sortBy == EntityBad)
790 add_sort_to_query_pair(ctx.data.sortBy, handle);
796 void del_sort_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
797 if (ctx.data.sortByFunc ==
nullptr || ctx.data.sortBy == EntityBad)
800 del_sort_to_query_pair(ctx.data.sortBy, handle);
806 void add_sorted_query(
const QueryCtx& ctx, QueryHandle handle) {
807 if (ctx.data.sortByFunc ==
nullptr)
810 m_sortedQueries.push_back(handle);
816 void del_sorted_query(
const QueryCtx& ctx, QueryHandle handle) {
817 if (ctx.data.sortByFunc ==
nullptr)
820 const auto idx = core::get_index(m_sortedQueries, handle);
821 GAIA_ASSERT(idx != BadIndex);
823 core::swap_erase(m_sortedQueries, idx);
829 void del_create_to_query_pair(Entity entity, QueryHandle handle) {
830 auto it = m_entityToCreateQuery.find(EntityLookupKey(entity));
831 if (it == m_entityToCreateQuery.end())
834 auto& handles = it->second;
835 core::swap_erase(handles, core::get_index(handles, handle));
836 untrack_create_selector(entity);
838 m_entityToCreateQuery.erase(it);
844 void add_create_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
845 if (ctx.data.cachePolicy != QueryCtx::CachePolicy::Immediate)
851 for (
const auto entity: ctx.data.deps.create_selectors_view())
852 add_create_to_query_pair(entity, handle);
858 void del_create_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
859 if (ctx.data.cachePolicy != QueryCtx::CachePolicy::Immediate)
862 for (
const auto entity: ctx.data.deps.create_selectors_view())
863 del_create_to_query_pair(entity, handle);
869 void add_create_query_handles(Entity selector, cnt::darray<CreateQueryCandidate>& handles) {
870 const auto it = m_entityToCreateQuery.find(EntityLookupKey(selector));
871 if (it == m_entityToCreateQuery.end())
874 for (
const auto handle: it->second) {
875 if (mark_create_query_handle(handle))
876 handles.push_back(CreateQueryCandidate{handle, selector});
882 GAIA_NODISCARD cnt::darray<CreateQueryCandidate>& prepare_create_query_handles() {
883 m_createQueryHandleScratch.clear();
887 ++m_createQueryHandleStamp;
888 if (m_createQueryHandleStamp == 0) {
889 m_createQueryHandleStampById = {};
890 m_createQueryHandleStamp = 1;
893 return m_createQueryHandleScratch;
899 GAIA_NODISCARD
bool mark_create_query_handle(QueryHandle handle) {
900 const auto handleId = (uint32_t)handle.id();
901 if (handleId >= m_createQueryHandleStampById.size())
902 m_createQueryHandleStampById.resize(handleId + 1);
904 auto& stamp = m_createQueryHandleStampById[handleId];
905 if (stamp == m_createQueryHandleStamp)
908 stamp = m_createQueryHandleStamp;
915 void add_archetype_query_pair(
const Archetype* pArchetype, QueryHandle handle) {
916 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
917 const auto it = m_archetypeToQuery.find(archetypeKey);
918 if (it == m_archetypeToQuery.end()) {
919 m_archetypeToQuery.try_emplace(archetypeKey, cnt::darray<QueryHandle>{handle});
923 auto& handles = it->second;
925 GAIA_ASSERT(!core::has(handles, handle));
926 handles.push_back(handle);
932 void del_archetype_query_pair(
const Archetype* pArchetype, QueryHandle handle) {
933 auto it = m_archetypeToQuery.find(ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash()));
934 if (it == m_archetypeToQuery.end())
937 auto& handles = it->second;
938 const auto idx = core::get_index(handles, handle);
939 GAIA_ASSERT(idx != BadIndex);
940 core::swap_erase(handles, idx);
942 m_archetypeToQuery.erase(it);
947 void unregister_query_archetypes(QueryHandle handle) {
948 auto it = m_queryToArchetype.find(QueryHandleLookupKey(handle));
949 if (it == m_queryToArchetype.end())
952 const auto& tracked = it->second.archetypes;
953 for (
const auto* pArchetype: tracked)
954 del_archetype_query_pair(pArchetype, handle);
956 m_queryToArchetype.erase(it);
963 void register_query_archetype(QueryHandle handle,
const Archetype* pArchetype, uint32_t syncedRevision) {
964 auto [trackedIt, inserted] = m_queryToArchetype.try_emplace(QueryHandleLookupKey(handle));
965 auto& tracked = trackedIt->second.archetypes;
969 GAIA_ASSERT(inserted || !core::has(tracked, pArchetype));
970 tracked.push_back(pArchetype);
971 trackedIt->second.syncedRevision = syncedRevision;
972 add_archetype_query_pair(pArchetype, handle);
978 void add_rel_query_pair(Entity relation, QueryHandle handle) {
979 const auto key = EntityLookupKey(relation);
980 const auto it = m_relationToQuery.find(key);
981 if (it == m_relationToQuery.end()) {
982 m_relationToQuery.try_emplace(key, cnt::darray<QueryHandle>{handle});
986 auto& handles = it->second;
987 if (!core::has(handles, handle))
988 handles.push_back(handle);
994 void del_rel_query_pair(Entity relation, QueryHandle handle) {
995 auto it = m_relationToQuery.find(EntityLookupKey(relation));
996 if (it == m_relationToQuery.end())
999 auto& handles = it->second;
1000 core::swap_erase(handles, core::get_index(handles, handle));
1001 if (handles.empty())
1002 m_relationToQuery.erase(it);
1008 void add_rel_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
1009 for (
const auto relation: ctx.data.deps.relations_view())
1010 add_rel_query_pair(relation, handle);
1016 void del_rel_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
1017 for (
const auto relation: ctx.data.deps.relations_view())
1018 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