2#include "gaia/config/config.h"
6#include "gaia/cnt/darray.h"
7#include "gaia/cnt/map.h"
8#include "gaia/cnt/sarray.h"
9#include "gaia/cnt/sarray_ext.h"
10#include "gaia/core/bit_utils.h"
11#include "gaia/core/hashing_policy.h"
12#include "gaia/core/utility.h"
13#include "gaia/ecs/api.h"
14#include "gaia/ecs/component.h"
15#include "gaia/ecs/id.h"
16#include "gaia/ecs/query_fwd.h"
17#include "gaia/ecs/query_mask.h"
18#include "gaia/ecs/ser_binary.h"
26 static constexpr uint32_t MAX_ITEMS_IN_QUERY = 8U;
28 GAIA_GCC_WARNING_PUSH()
31 GAIA_GCC_WARNING_DISABLE("-Wshadow")
34 enum class QueryOpKind : uint8_t { All, Any, Not, Count };
36 enum class QueryAccess : uint8_t { None, Read, Write };
38 enum class QueryInputFlags : uint8_t { None, Variable };
40 GAIA_GCC_WARNING_POP()
42 using QueryLookupHash = core::direct_hash_key<uint64_t>;
43 using QueryEntityArray = cnt::sarray<Entity, MAX_ITEMS_IN_QUERY>;
44 using QueryArchetypeCacheIndexMap = cnt::map<EntityLookupKey, uint32_t>;
45 using QuerySerMap = cnt::map<QueryId, QuerySerBuffer>;
47 static constexpr QueryId QueryIdBad = (QueryId)-1;
48 static constexpr GroupId GroupIdMax = ((GroupId)-1) - 1;
51 static constexpr uint32_t IdMask = QueryIdBad;
65 constexpr QueryHandle()
noexcept: val((uint64_t)-1) {};
78 GAIA_NODISCARD
constexpr bool operator==(
const QueryHandle& other)
const noexcept {
79 return val == other.val;
81 GAIA_NODISCARD
constexpr bool operator!=(
const QueryHandle& other)
const noexcept {
82 return val != other.val;
85 GAIA_NODISCARD
auto id()
const {
88 GAIA_NODISCARD
auto gen()
const {
91 GAIA_NODISCARD
auto value()
const {
109 return {core::calculate_hash64(handle.value())};
113 static constexpr bool IsDirectHashKey =
true;
128 size_t hash()
const {
129 return (
size_t)m_hash.hash;
133 if GAIA_LIKELY (m_hash != other.m_hash)
136 return m_handle == other.m_handle;
140 return !operator==(other);
149 QueryOpKind
op = QueryOpKind::All;
171 bool operator==(
const QueryTerm& other)
const {
172 return id == other.
id &&
src == other.
src &&
op == other.
op;
174 bool operator!=(
const QueryTerm& other)
const {
175 return !operator==(other);
179 using QueryTermArray = cnt::sarray_ext<QueryTerm, MAX_ITEMS_IN_QUERY>;
181 using QueryRemappingArray = cnt::sarray_ext<uint8_t, MAX_ITEMS_IN_QUERY>;
190 return query_buffer(*world,
serId);
192 void ser_buffer_reset(
World* world) {
193 query_buffer_reset(*world,
serId);
207 enum QueryFlags : uint8_t {
231 uint8_t changedCnt = 0;
263 return {
_ids.data(), idsCnt};
267 return {
_changed.data(), changedCnt};
271 return {
_terms.data(), idsCnt};
274 return {
_terms.data(), idsCnt};
278 static_assert(MAX_ITEMS_IN_QUERY == 8);
280 void init(World* pWorld) {
282 cc = &comp_cache_mut(*pWorld);
288 const auto isComplex_old = data.
flags & QueryFlags::Complex;
292 uint32_t as_mask_0 = 0;
293 uint32_t as_mask_1 = 0;
294 bool isComplex =
false;
296 auto ids = data.ids_view();
297 const auto cnt = (uint32_t)ids.size();
299 const auto id = ids[i];
304 const auto j = (uint32_t)i;
305 const auto has_as = (uint32_t)is_base(*w,
id);
306 as_mask_0 |= (has_as << j);
308 const bool idIsWildcard = is_wildcard(
id.
id());
309 const bool isGenWildcard = is_wildcard(
id.gen());
310 isComplex |= (idIsWildcard || isGenWildcard);
313 const auto j = (uint32_t)i;
314 const auto e = entity_from_id(*w,
id.
id());
315 const auto has_as = (uint32_t)is_base(*w, e);
316 as_mask_0 |= (has_as << j);
319 if (!isGenWildcard) {
320 const auto j = (uint32_t)i;
321 const auto e = entity_from_id(*w,
id.gen());
322 const auto has_as = (uint32_t)is_base(*w, e);
323 as_mask_1 |= (has_as << j);
336 data.
flags |= QueryCtx::QueryFlags::Complex;
339 data.
flags &= ~QueryCtx::QueryFlags::Complex;
345 isComplex_old != (data.
flags & QueryFlags::Complex))
346 data.
flags |= QueryCtx::QueryFlags::Recompile;
349 GAIA_NODISCARD
bool operator==(
const QueryCtx& other)
const noexcept {
351 GAIA_ASSERT(
q.
handle.id() == QueryIdBad);
360 const auto& left = data;
361 const auto& right = other.data;
364 if (left.idsCnt != right.idsCnt)
366 if (left.changedCnt != right.changedCnt)
368 if (left.readWriteMask != right.readWriteMask)
373 const auto cnt = left.idsCnt;
375 if (left._terms[i] != right._terms[i])
382 const auto cnt = left.changedCnt;
384 if (left._changed[i] != right._changed[i])
390 if (left.sortBy != right.sortBy)
392 if (left.sortByFunc != right.sortByFunc)
396 if (left.groupBy != right.groupBy)
398 if (left.groupByFunc != right.groupByFunc)
404 GAIA_NODISCARD
bool operator!=(
const QueryCtx& other)
const noexcept {
405 return !operator==(other);
413 if (lhs.
op != rhs.
op)
414 return lhs.
op < rhs.
op;
417 if (lhs.
id != rhs.
id)
434 const uint32_t idsCnt = ctx.data.idsCnt;
436 auto& ctxData = ctx.data;
443 ctxData._terms.data(), ctxData._terms.data() + ctxData.idsCnt,
query_sort_cond{},
444 [&](uint32_t left, uint32_t right) {
445 core::swap(ctxData._ids[left], ctxData._ids[right]);
446 core::swap(ctxData._terms[left], ctxData._terms[right]);
447 core::swap(remappingCopy[left], remappingCopy[right]);
450 core::swap_bits(ctxData.readWriteMask, left, right);
451 core::swap_bits(ctxData.as_mask_0, left, right);
452 core::swap_bits(ctxData.as_mask_1, left, right);
463 const auto idxBeforeRemapping = (uint8_t)core::get_index_unsafe(remappingCopy, (uint8_t)i);
464 ctxData._remapping[i] = idxBeforeRemapping;
469 while (i < idsCnt && ctxData._terms[i].op == QueryOpKind::All)
471 ctxData.firstAny = (uint8_t)i;
472 while (i < idsCnt && ctxData._terms[i].op == QueryOpKind::Any)
474 ctxData.firstNot = (uint8_t)i;
478 inline void calc_lookup_hash(QueryCtx& ctx) {
479 GAIA_ASSERT(ctx.cc !=
nullptr);
481 GAIA_ASSERT(ctx.hashLookup.hash == 0);
483 QueryLookupHash::Type hashLookup = 0;
485 const auto& ctxData = ctx.data;
489 QueryLookupHash::Type hash = 0;
491 auto terms = ctxData.terms_view();
492 for (
const auto& pair: terms) {
493 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.op);
494 hash = core::hash_combine(hash, (QueryLookupHash::Type)pair.id.value());
496 hash = core::hash_combine(hash, (QueryLookupHash::Type)terms.size());
497 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.readWriteMask);
504 QueryLookupHash::Type hash = 0;
506 auto changed = ctxData.changed_view();
507 for (
auto id: changed)
508 hash = core::hash_combine(hash, (QueryLookupHash::Type)id.value());
509 hash = core::hash_combine(hash, (QueryLookupHash::Type)changed.size());
511 hashLookup = core::hash_combine(hashLookup, hash);
516 QueryLookupHash::Type hash = 0;
518 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.groupBy.value());
519 hash = core::hash_combine(hash, (QueryLookupHash::Type)ctxData.groupByFunc);
521 hashLookup = core::hash_combine(hashLookup, hash);
524 ctx.hashLookup = {core::calculate_hash64(hashLookup)};
533 template <u
int32_t MAX_COMPONENTS>
534 GAIA_NODISCARD
inline uint32_t comp_idx(
const QueryTerm* pTerms, Entity entity, Entity src) {
537 GAIA_FOR(MAX_COMPONENTS) {
538 if (pTerms[i].
id == entity && pTerms[i].src == src)
Array of elements of type.
Definition sarray_impl.h:26
Definition span_impl.h:99
Definition archetype.h:82
Cache for compile-time defined components.
Definition component_cache.h:23
Definition ser_buffer_binary.h:154
Definition robin_hood.h:720
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition query_common.h:219
Entity sortBy
Entity to sort the archetypes by. EntityBad for no sorting.
Definition query_common.h:237
TGroupByFunc groupByFunc
Function to use to perform the grouping.
Definition query_common.h:243
uint32_t as_mask_0
Mask for items with Is relationship pair. If the id is a pair, the first part (id) is written here.
Definition query_common.h:248
Entity groupBy
Entity to group the archetypes by. EntityBad for no grouping.
Definition query_common.h:241
uint8_t readWriteMask
Read-write mask. Bit 0 stands for component 0 in component arrays. A set bit means write access is re...
Definition query_common.h:258
uint32_t as_mask_1
Mask for items with Is relationship pair. If the id is a pair, the second part (gen) is written here.
Definition query_common.h:251
cnt::sarray< uint8_t, MAX_ITEMS_IN_QUERY > _remapping
Mapping of the original indices to the new ones after sorting.
Definition query_common.h:225
QueryMask queryMask
Component mask used for faster matching of simple queries.
Definition query_common.h:245
uint8_t firstAny
First ANY record in pairs/ids/ops.
Definition query_common.h:255
QueryArchetypeCacheIndexMap lastMatchedArchetypeIdx_All
Index of the last checked archetype in the component-to-archetype map.
Definition query_common.h:227
QueryEntityArray _ids
Array of queried ids.
Definition query_common.h:221
GroupId groupIdSet
Iteration will be restricted only to target Group.
Definition query_common.h:233
QueryEntityArray _changed
Array of filtered components.
Definition query_common.h:235
TSortByFunc sortByFunc
Function to use to perform sorting.
Definition query_common.h:239
uint8_t flags
Query flags.
Definition query_common.h:260
uint8_t firstNot
First NOT record in pairs/ids/ops.
Definition query_common.h:253
cnt::sarray< QueryTerm, MAX_ITEMS_IN_QUERY > _terms
Array of terms.
Definition query_common.h:223
Definition query_common.h:197
ComponentCache * cc
Component cache.
Definition query_common.h:201
QueryIdentity q
Query identity.
Definition query_common.h:205
QueryLookupHash hashLookup
Lookup hash for this query.
Definition query_common.h:203
Hashmap lookup structure used for Entity.
Definition query_common.h:99
Definition query_common.h:50
Definition query_common.h:183
QueryHandle handle
Query id.
Definition query_common.h:185
QueryId serId
Serialization id.
Definition query_common.h:187
Internal representation of QueryInput.
Definition query_common.h:161
Entity id
Queried id.
Definition query_common.h:163
Archetype * srcArchetype
Archetype of the src entity.
Definition query_common.h:167
QueryOpKind op
Operation to perform with the term.
Definition query_common.h:169
Entity src
Source of where the queried id is looked up at.
Definition query_common.h:165
Functor for sorting terms in a query before compilation.
Definition query_common.h:410