63 enum class ChangeKind : uint8_t {
75 add_entity_to_query_pairs(info.ctx().data.ids_view(), handle);
76 add_rel_to_query_pairs(info.ctx(), handle);
77 add_sort_to_query_pairs(info.ctx(), handle);
78 add_sorted_query(info.ctx(), handle);
79 add_create_to_query_pairs(info.ctx(), handle);
86 struct CreateQueryCandidate {
88 Entity matchedSelector = EntityBad;
93 enum class CreateSelectorKind : uint8_t {
102 struct TrackedArchetypes {
104 uint32_t syncedRevision = 0;
129 uint32_t m_createQueryHandleStamp = 1;
131 uint32_t m_createQuerySelectorCnt[(size_t)CreateSelectorKind::Count] = {};
135 m_queryArr.reserve(256);
145 GAIA_NODISCARD
bool valid(
QueryHandle handle)
const {
146 if (handle.id() == QueryIdBad)
149 if (!m_queryArr.has(handle.id()))
152 const auto& h = m_queryArr[handle.id()];
153 return h.idx == handle.id() && h.gen == handle.gen();
159 m_entityToQuery.clear();
160 m_relationToQuery.clear();
161 m_sortEntityToQuery.clear();
162 m_sortedQueries.clear();
163 m_entityToCreateQuery.clear();
164 m_archetypeToQuery.clear();
165 m_queryToArchetype.clear();
166 m_createQueryHandleScratch.clear();
167 m_createQueryHandleStampById.clear();
168 m_createQueryHandleStamp = 1;
169 for (
auto& cnt: m_createQuerySelectorCnt)
176 m_archetypeToQuery.clear();
177 m_queryToArchetype.clear();
187 auto& info = m_queryArr[handle.id()];
188 GAIA_ASSERT(info.
idx == handle.id());
189 GAIA_ASSERT(info.
gen == handle.gen());
197 GAIA_ASSERT(valid(handle));
199 auto& info = m_queryArr[handle.id()];
200 GAIA_ASSERT(info.
idx == handle.id());
201 GAIA_ASSERT(info.
gen == handle.gen());
214 GAIA_ASSERT(ctx.hashLookup.hash != 0);
217 auto ret = m_pCache.try_emplace(
QueryLookupKey(ctx.hashLookup, &ctx),
nullptr);
219 auto* pInfo = ret.first->second;
220 GAIA_ASSERT(pInfo !=
nullptr);
227 creationCtx.pQueryCtx = &ctx;
228 creationCtx.pEntityToArchetypeMap = &entityToArchetypeMap;
229 creationCtx.allArchetypes = allArchetypes;
230 auto handle = m_queryArr.
alloc(&creationCtx);
234 auto& info =
get(handle);
236 ret.first->second = &info;
238 ret.first->swap(new_p);
240 return register_query_info(handle, info);
249 creationCtx.pQueryCtx = &ctx;
250 creationCtx.pEntityToArchetypeMap = &entityToArchetypeMap;
251 creationCtx.allArchetypes = allArchetypes;
252 auto handle = m_queryArr.
alloc(&creationCtx);
254 auto& info =
get(handle);
256 return register_query_info(handle, info);
264 if (pInfo ==
nullptr)
268 if (pInfo->refs() != 0)
271 unregister_query_archetypes(handle);
274 auto it = m_pCache.find(
QueryLookupKey(pInfo->ctx().hashLookup, &pInfo->ctx()));
275 if (it != m_pCache.end())
279 del_entity_to_query_pairs(pInfo->ctx().data.ids_view(), handle);
280 del_rel_to_query_pairs(pInfo->ctx(), handle);
281 del_sort_to_query_pairs(pInfo->ctx(), handle);
282 del_sorted_query(pInfo->ctx(), handle);
283 del_create_to_query_pairs(pInfo->ctx(), handle);
284 m_queryArr.free(handle);
290 return m_queryArr.
begin();
294 return m_queryArr.end();
304 auto it = m_entityToQuery.find(entityKey);
305 if (it == m_entityToQuery.end())
308 const auto& handles = it->second;
309 for (
const auto& handle: handles) {
310 auto& info =
get(handle);
313 info.invalidate(select_invalidation_kind(info, changeKind));
317 void invalidate_queries_for_rel(
Entity relation, ChangeKind changeKind) {
319 if (it == m_relationToQuery.end())
322 for (
const auto handle: it->second) {
323 auto& info =
get(handle);
325 info.invalidate(select_invalidation_kind(info, changeKind));
329 void invalidate_sorted_queries_for_entity(Entity entity) {
330 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
331 if (it == m_sortEntityToQuery.end())
334 for (
const auto handle: it->second) {
336 if (pInfo ==
nullptr || pInfo->refs() == 0)
339 pInfo->invalidate_sort();
345 for (
const auto handle: m_sortedQueries) {
347 if (pInfo ==
nullptr || pInfo->refs() == 0)
350 pInfo->invalidate_sort();
354 void sync_archetype_cache(
QueryInfo& queryInfo) {
355 const auto handle = QueryInfo::handle(queryInfo);
359 const auto archetypes = queryInfo.cache_archetype_view();
361 auto it = m_queryToArchetype.find(key);
362 if (it != m_queryToArchetype.end() && it->second.syncedRevision == queryInfo.reverse_index_revision())
365 unregister_query_archetypes(handle);
367 if (archetypes.empty())
370 auto [trackedIt, inserted] = m_queryToArchetype.try_emplace(key);
371 auto& tracked = trackedIt->second.archetypes;
375 tracked.reserve((uint32_t)archetypes.size());
376 for (
const auto* pArchetype: archetypes) {
377 tracked.push_back(pArchetype);
378 add_archetype_query_pair(pArchetype, handle);
380 trackedIt->second.syncedRevision = queryInfo.reverse_index_revision();
383 void remove_archetype_from_queries(Archetype* pArchetype) {
384 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
385 auto it = m_archetypeToQuery.find(archetypeKey);
386 if (it == m_archetypeToQuery.end())
389 const auto handles = it->second;
390 for (
const auto handle: handles) {
392 if (pInfo !=
nullptr && pInfo->refs() != 0)
393 pInfo->remove(pArchetype);
395 auto trackedIt = m_queryToArchetype.find(QueryHandleLookupKey(handle));
396 if (trackedIt == m_queryToArchetype.end())
399 auto& tracked = trackedIt->second.archetypes;
400 core::swap_erase(tracked, core::get_index(tracked, pArchetype));
401 if (trackedIt->second.archetypes.empty())
402 m_queryToArchetype.erase(trackedIt);
405 m_archetypeToQuery.erase(it);
408 void register_archetype_with_queries(
const Archetype* pArchetype) {
409 auto& handles = prepare_create_query_handles();
410 const bool needsExactPairSelectors = has_create_selector_kind(CreateSelectorKind::ExactPair);
411 const bool needsRelWildcardSelectors = has_create_selector_kind(CreateSelectorKind::RelWildcardPair);
412 const bool needsTgtWildcardSelectors = has_create_selector_kind(CreateSelectorKind::TgtWildcardPair);
413 const bool needsAnyPairWildcardSelectors = has_create_selector_kind(CreateSelectorKind::AnyPairWildcard);
414 bool hasAnyPair =
false;
415 cnt::darray_ext<Entity, 16> pairWildcardRelations;
416 for (
const auto entity: pArchetype->ids_view()) {
417 if (!entity.pair()) {
418 add_create_query_handles(entity, handles);
423 if (needsExactPairSelectors)
424 add_create_query_handles(entity, handles);
428 const auto relKind = entity.entity() ? EntityKind::EK_Uni : EntityKind::EK_Gen;
429 const auto rel = Entity((EntityId)entity.id(), 0,
false,
false, relKind);
430 const auto tgt = Entity((EntityId)entity.gen(), 0,
false,
false, entity.kind());
431 if (needsTgtWildcardSelectors)
432 add_create_query_handles(Pair(All, tgt), handles);
433 if (needsRelWildcardSelectors && !core::has(pairWildcardRelations, rel)) {
434 pairWildcardRelations.push_back(rel);
435 add_create_query_handles(Pair(rel, All), handles);
439 if (hasAnyPair && needsAnyPairWildcardSelectors)
440 add_create_query_handles(Pair(All, All), handles);
442 for (
const auto& candidate: handles) {
443 auto* pInfo =
try_get(candidate.handle);
444 if (pInfo ==
nullptr || pInfo->refs() == 0)
447 if (!pInfo->register_archetype(*pArchetype, candidate.matchedSelector,
true))
450 register_query_archetype(candidate.handle, pArchetype, pInfo->reverse_index_revision());
456 static CreateSelectorKind classify_create_selector(Entity entity) {
458 return CreateSelectorKind::Other;
459 if (is_wildcard(entity.id()))
460 return is_wildcard(entity.gen()) ? CreateSelectorKind::AnyPairWildcard : CreateSelectorKind::TgtWildcardPair;
461 if (is_wildcard(entity.gen()))
462 return CreateSelectorKind::RelWildcardPair;
463 return CreateSelectorKind::ExactPair;
466 GAIA_NODISCARD
static constexpr uint32_t selector_kind_idx(CreateSelectorKind kind) {
467 return (uint32_t)kind;
470 GAIA_NODISCARD
bool has_create_selector_kind(CreateSelectorKind kind)
const {
471 return m_createQuerySelectorCnt[selector_kind_idx(kind)] != 0;
475 void track_create_selector(Entity entity) {
476 const auto kind = classify_create_selector(entity);
477 ++m_createQuerySelectorCnt[selector_kind_idx(kind)];
481 void untrack_create_selector(Entity entity) {
482 const auto kind = classify_create_selector(entity);
483 auto& cnt = m_createQuerySelectorCnt[selector_kind_idx(kind)];
484 GAIA_ASSERT(cnt != 0);
489 switch (changeKind) {
490 case ChangeKind::DynamicResult:
492 case ChangeKind::All:
494 case ChangeKind::Structural:
498 return (info.ctx().data.deps.has_dep_flag(QueryCtx::DependencyHasSourceTerms) ||
499 info.ctx().data.deps.has_dep_flag(QueryCtx::DependencyHasVariableTerms))
511 void add_entity_query_pair(Entity entity, QueryHandle handle) {
512 EntityLookupKey entityKey(entity);
513 const auto it = m_entityToQuery.find(entityKey);
514 if (it == m_entityToQuery.end()) {
515 m_entityToQuery.try_emplace(entityKey, cnt::darray<QueryHandle>{handle});
519 auto& handles = it->second;
520 if (!core::has(handles, handle))
521 handles.push_back(handle);
527 void del_entity_query_pair(Entity entity, QueryHandle handle) {
528 auto it = m_entityToQuery.find(EntityLookupKey(entity));
529 if (it == m_entityToQuery.end())
532 auto& handles = it->second;
533 const auto idx = core::get_index_unsafe(handles, handle);
534 core::swap_erase_unsafe(handles, idx);
538 m_entityToQuery.erase(it);
543 void add_entity_to_query_pairs(EntitySpan entities, QueryHandle handle) {
544 for (
auto entity: entities) {
545 add_entity_query_pair(entity, handle);
551 void del_entity_to_query_pairs(EntitySpan entities, QueryHandle handle) {
552 for (
auto entity: entities) {
553 del_entity_query_pair(entity, handle);
557 void add_create_to_query_pair(Entity entity, QueryHandle handle) {
558 EntityLookupKey entityKey(entity);
559 const auto it = m_entityToCreateQuery.find(entityKey);
560 if (it == m_entityToCreateQuery.end()) {
561 m_entityToCreateQuery.try_emplace(entityKey, cnt::darray<QueryHandle>{handle});
562 track_create_selector(entity);
566 auto& handles = it->second;
567 if (!core::has(handles, handle)) {
568 handles.push_back(handle);
569 track_create_selector(entity);
573 void add_sort_to_query_pair(Entity entity, QueryHandle handle) {
574 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
575 if (it == m_sortEntityToQuery.end()) {
576 m_sortEntityToQuery.try_emplace(EntityLookupKey(entity), cnt::darray<QueryHandle>{handle});
580 auto& handles = it->second;
581 if (!core::has(handles, handle))
582 handles.push_back(handle);
585 void del_sort_to_query_pair(Entity entity, QueryHandle handle) {
586 auto it = m_sortEntityToQuery.find(EntityLookupKey(entity));
587 if (it == m_sortEntityToQuery.end())
590 auto& handles = it->second;
591 core::swap_erase(handles, core::get_index(handles, handle));
593 m_sortEntityToQuery.erase(it);
596 void add_sort_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
597 if (ctx.data.sortByFunc ==
nullptr || ctx.data.sortBy == EntityBad)
600 add_sort_to_query_pair(ctx.data.sortBy, handle);
603 void del_sort_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
604 if (ctx.data.sortByFunc ==
nullptr || ctx.data.sortBy == EntityBad)
607 del_sort_to_query_pair(ctx.data.sortBy, handle);
610 void add_sorted_query(
const QueryCtx& ctx, QueryHandle handle) {
611 if (ctx.data.sortByFunc ==
nullptr)
614 m_sortedQueries.push_back(handle);
617 void del_sorted_query(
const QueryCtx& ctx, QueryHandle handle) {
618 if (ctx.data.sortByFunc ==
nullptr)
621 const auto idx = core::get_index(m_sortedQueries, handle);
622 GAIA_ASSERT(idx != BadIndex);
624 core::swap_erase(m_sortedQueries, idx);
627 void del_create_to_query_pair(Entity entity, QueryHandle handle) {
628 auto it = m_entityToCreateQuery.find(EntityLookupKey(entity));
629 if (it == m_entityToCreateQuery.end())
632 auto& handles = it->second;
633 core::swap_erase(handles, core::get_index(handles, handle));
634 untrack_create_selector(entity);
636 m_entityToCreateQuery.erase(it);
639 void add_create_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
640 if (ctx.data.cachePolicy != QueryCtx::CachePolicy::Immediate)
646 for (
const auto entity: ctx.data.deps.create_selectors_view())
647 add_create_to_query_pair(entity, handle);
650 void del_create_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
651 if (ctx.data.cachePolicy != QueryCtx::CachePolicy::Immediate)
654 for (
const auto entity: ctx.data.deps.create_selectors_view())
655 del_create_to_query_pair(entity, handle);
658 void add_create_query_handles(Entity selector, cnt::darray<CreateQueryCandidate>& handles) {
659 const auto it = m_entityToCreateQuery.find(EntityLookupKey(selector));
660 if (it == m_entityToCreateQuery.end())
663 for (
const auto handle: it->second) {
664 if (mark_create_query_handle(handle))
665 handles.push_back(CreateQueryCandidate{handle, selector});
669 cnt::darray<CreateQueryCandidate>& prepare_create_query_handles() {
670 m_createQueryHandleScratch.clear();
674 ++m_createQueryHandleStamp;
675 if (m_createQueryHandleStamp == 0) {
676 m_createQueryHandleStampById = {};
677 m_createQueryHandleStamp = 1;
680 return m_createQueryHandleScratch;
683 GAIA_NODISCARD
bool mark_create_query_handle(QueryHandle handle) {
684 const auto handleId = (uint32_t)handle.id();
685 if (handleId >= m_createQueryHandleStampById.size())
686 m_createQueryHandleStampById.resize(handleId + 1);
688 auto& stamp = m_createQueryHandleStampById[handleId];
689 if (stamp == m_createQueryHandleStamp)
692 stamp = m_createQueryHandleStamp;
696 void add_archetype_query_pair(
const Archetype* pArchetype, QueryHandle handle) {
697 const auto archetypeKey = ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash());
698 const auto it = m_archetypeToQuery.find(archetypeKey);
699 if (it == m_archetypeToQuery.end()) {
700 m_archetypeToQuery.try_emplace(archetypeKey, cnt::darray<QueryHandle>{handle});
704 auto& handles = it->second;
706 GAIA_ASSERT(!core::has(handles, handle));
707 handles.push_back(handle);
710 void del_archetype_query_pair(
const Archetype* pArchetype, QueryHandle handle) {
711 auto it = m_archetypeToQuery.find(ArchetypeIdLookupKey(pArchetype->id(), pArchetype->id_hash()));
712 if (it == m_archetypeToQuery.end())
715 auto& handles = it->second;
716 const auto idx = core::get_index(handles, handle);
717 GAIA_ASSERT(idx != BadIndex);
718 core::swap_erase(handles, idx);
720 m_archetypeToQuery.erase(it);
723 void unregister_query_archetypes(QueryHandle handle) {
724 auto it = m_queryToArchetype.find(QueryHandleLookupKey(handle));
725 if (it == m_queryToArchetype.end())
728 const auto& tracked = it->second.archetypes;
729 for (
const auto* pArchetype: tracked)
730 del_archetype_query_pair(pArchetype, handle);
732 m_queryToArchetype.erase(it);
735 void register_query_archetype(QueryHandle handle,
const Archetype* pArchetype, uint32_t syncedRevision) {
736 auto [trackedIt, inserted] = m_queryToArchetype.try_emplace(QueryHandleLookupKey(handle));
737 auto& tracked = trackedIt->second.archetypes;
741 GAIA_ASSERT(inserted || !core::has(tracked, pArchetype));
742 tracked.push_back(pArchetype);
743 trackedIt->second.syncedRevision = syncedRevision;
744 add_archetype_query_pair(pArchetype, handle);
747 void add_rel_query_pair(Entity relation, QueryHandle handle) {
748 const auto key = EntityLookupKey(relation);
749 const auto it = m_relationToQuery.find(key);
750 if (it == m_relationToQuery.end()) {
751 m_relationToQuery.try_emplace(key, cnt::darray<QueryHandle>{handle});
755 auto& handles = it->second;
756 if (!core::has(handles, handle))
757 handles.push_back(handle);
760 void del_rel_query_pair(Entity relation, QueryHandle handle) {
761 auto it = m_relationToQuery.find(EntityLookupKey(relation));
762 if (it == m_relationToQuery.end())
765 auto& handles = it->second;
766 core::swap_erase(handles, core::get_index(handles, handle));
768 m_relationToQuery.erase(it);
771 void add_rel_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
772 for (
const auto relation: ctx.data.deps.relations_view())
773 add_rel_query_pair(relation, handle);
776 void del_rel_to_query_pairs(
const QueryCtx& ctx, QueryHandle handle) {
777 for (
const auto relation: ctx.data.deps.relations_view())
778 del_rel_query_pair(relation, handle);