28 static constexpr uint32_t FastComponentCacheSize = 512;
46 detail::ComponentDescId m_nextRuntimeCompDescId = 0x80000000u;
55 for (
const auto* pItem: m_itemArr)
57 for (
auto [componentId, pItem]: m_itemByDescId)
61 m_itemByDescId.clear();
62 m_compBySymbol.clear();
64 m_compByShortSymbol.clear();
65 m_compByEntity.clear();
68 template <
typename Func>
69 void for_each_item(Func&& func) {
70 for (
auto* pItem: m_itemArr) {
75 for (
auto& [componentId, pItem]: m_itemByDescId) {
81 template <
typename Func>
82 void for_each_item(Func&& func)
const {
83 for (
const auto* pItem: m_itemArr) {
88 for (
const auto& [componentId, pItem]: m_itemByDescId) {
94 GAIA_NODISCARD
static bool is_internal_symbol(
util::str_view symbol)
noexcept {
95 constexpr char InternalPrefix[] =
"gaia::ecs::";
96 constexpr uint32_t InternalPrefixLen = (uint32_t)(
sizeof(InternalPrefix) - 1);
97 return symbol.
size() >= InternalPrefixLen && memcmp(symbol.
data(), InternalPrefix, InternalPrefixLen) == 0;
101 const auto* pName = item.
name.str();
102 const auto len = item.
name.len();
103 for (uint32_t i = len; i > 1; --i) {
104 const auto idx = i - 1;
105 if (pName[idx] !=
':' || pName[idx - 1] !=
':')
120 bool changed =
false;
122 for (uint32_t i = 0; i < symbol.
size(); ++i) {
123 if (i + 1 < symbol.
size() && symbol.
data()[i] ==
':' && symbol.
data()[i + 1] ==
':') {
162 if (is_internal_symbol(symbol))
165 const auto shortName = short_name_key(item);
166 const bool hasShortName =
167 shortName.str() !=
nullptr && shortName.len() != 0 && shortName.len() != item.
name.len();
168 const auto leaf = hasShortName ?
util::str_view{shortName.str(), shortName.len()} : symbol;
170 if (!build_scoped_path(item.
path, scopePath, leaf))
171 (void)build_default_path(item.
path, symbol);
174 template <
typename ViewFunc>
175 void rebuild_lookup_map(
179 const auto view = getView(item);
183 const auto key = lookup_key(view);
184 const auto it = map.find(key);
185 if (it == map.end()) {
186 map.emplace(key, &item);
190 if (it->second != &item)
191 it->second =
nullptr;
195 void rebuild_resolved_name_maps() {
200 if (is_internal_symbol(symbol_name(item)))
203 const auto shortName = short_name_key(item);
204 return shortName.str() !=
nullptr && shortName.len() != 0 ?
util::str_view(shortName.str(), shortName.len())
213 m_compBySymbol.emplace(item.
name, &item);
214 initialize_names(item, scopePath);
215 rebuild_resolved_name_maps();
221 m_itemArr.reserve(FastComponentCacheSize);
235 template <
typename T>
238 GAIA_ASSERT(!entity.pair());
243 if (compDescId < FastComponentCacheSize) {
245 const auto* pItem = ComponentCacheItem::create<T>(entity);
246 GAIA_ASSERT(compDescId == pItem->comp.id());
247 m_itemArr[compDescId] = pItem;
249 m_compByEntity.emplace(pItem->entity, pItem);
253 if GAIA_UNLIKELY (compDescId >= m_itemArr.size()) {
254 const auto newSize = compDescId + 1U;
257 constexpr uint32_t CapacityIncreaseSize = 128;
258 const auto newCapacity = ((newSize / CapacityIncreaseSize) * CapacityIncreaseSize) + CapacityIncreaseSize;
259 m_itemArr.reserve(newCapacity);
262 m_itemArr.resize(newSize,
nullptr);
267 if GAIA_UNLIKELY (m_itemArr[compDescId] ==
nullptr) {
271 return *m_itemArr[compDescId];
276 auto createDesc = [&]() ->
const ComponentCacheItem& {
277 const auto* pItem = ComponentCacheItem::create<T>(entity);
278 GAIA_ASSERT(compDescId == pItem->comp.id());
279 m_itemByDescId.emplace(compDescId, pItem);
280 add_name_mappings(*
const_cast<ComponentCacheItem*
>(pItem), scopePath);
281 m_compByEntity.emplace(pItem->entity, pItem);
285 const auto it = m_itemByDescId.find(compDescId);
286 if (it == m_itemByDescId.end())
305 GAIA_NODISCARD
const ComponentCacheItem&
306 add(
Entity entity,
const char* name, uint32_t len, uint32_t size, DataStorageType storageType, uint32_t alig = 1,
309 GAIA_ASSERT(!entity.pair());
310 GAIA_ASSERT(name !=
nullptr);
312 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, ComponentCacheItem::MaxNameLength) : len;
313 GAIA_ASSERT(l > 0 && l < ComponentCacheItem::MaxNameLength);
316 const auto* pExisting = symbol(name, l);
317 if (pExisting !=
nullptr)
321 detail::ComponentDescId compDescId = m_nextRuntimeCompDescId;
322 while (find(compDescId) !=
nullptr) {
325 m_nextRuntimeCompDescId = compDescId + 1;
327 ComponentCacheItem::ComponentCacheItemCtx ctx{};
328 ctx.compDescId = compDescId;
333 ctx.storageType = storageType;
335 ctx.pSoaSizes = pSoaSizes;
336 ctx.hashLookup = hashLookup;
338 const auto* pItem = ComponentCacheItem::create(entity, ctx);
339 if (compDescId < FastComponentCacheSize) {
340 if (compDescId >= m_itemArr.size())
341 m_itemArr.resize(compDescId + 1U);
342 m_itemArr[compDescId] = pItem;
344 m_itemByDescId.emplace(compDescId, pItem);
347 add_name_mappings(*
const_cast<ComponentCacheItem*
>(pItem), scopePath);
348 m_compByEntity.emplace(pItem->entity, pItem);
357 if (compDescId < FastComponentCacheSize) {
358 if (compDescId >= m_itemArr.size())
361 return m_itemArr[compDescId];
365 const auto it = m_itemByDescId.find(compDescId);
366 return it != m_itemByDescId.end() ? it->second :
nullptr;
375 if (compDescId < FastComponentCacheSize) {
376 GAIA_ASSERT(compDescId < m_itemArr.size());
377 return *m_itemArr[compDescId];
381 GAIA_ASSERT(m_itemByDescId.contains(compDescId));
382 return *m_itemByDescId.find(compDescId)->second;
393 if (it != m_compByEntity.end())
411 GAIA_ASSERT(!entity.pair());
412 const auto* pItem = find(entity);
413 GAIA_ASSERT(pItem !=
nullptr);
422 auto* pItem = find(entity);
423 GAIA_ASSERT(pItem !=
nullptr);
432 return {item.
name.str(), item.
name.len()};
438 GAIA_NODISCARD util::str_view path_name(
const ComponentCacheItem& item)
const noexcept {
448 GAIA_NODISCARD util::str_view display_name(
const ComponentCacheItem& item)
const noexcept {
449 const auto symbol = symbol_name(item);
450 if (is_internal_symbol(symbol))
453 const auto path = path_name(item);
455 const auto pathIt = m_compByPath.find(lookup_key(path));
456 const auto symbolIt = m_compBySymbol.find(lookup_key(path));
457 const bool pathIsUnique = pathIt != m_compByPath.end() && pathIt->second == &item;
458 const bool pathShadowed = symbolIt != m_compBySymbol.end() && symbolIt->second != &item;
459 if (pathIsUnique && !pathShadowed)
472 bool path(ComponentCacheItem& item,
const char* name, uint32_t len = 0) noexcept {
473 if (name ==
nullptr || name[0] == 0) {
475 rebuild_resolved_name_maps();
479 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, ComponentCacheItem::MaxNameLength) : len;
480 if (l == 0 || l >= ComponentCacheItem::MaxNameLength)
483 item.path.assign(name, l);
484 rebuild_resolved_name_maps();
492 GAIA_NODISCARD
const ComponentCacheItem* symbol(
const char* name, uint32_t len = 0) const noexcept {
493 GAIA_ASSERT(name !=
nullptr);
495 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, ComponentCacheItem::MaxNameLength) : len;
496 GAIA_ASSERT(l < ComponentCacheItem::MaxNameLength);
498 const auto it = m_compBySymbol.find(ComponentCacheItem::SymbolLookupKey(name, l, 0));
499 return it != m_compBySymbol.end() ? it->second :
nullptr;
506 GAIA_NODISCARD
const ComponentCacheItem* path(
const char* name, uint32_t len = 0) const noexcept {
507 GAIA_ASSERT(name !=
nullptr);
509 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, ComponentCacheItem::MaxNameLength) : len;
510 GAIA_ASSERT(l < ComponentCacheItem::MaxNameLength);
512 const auto it = m_compByPath.find(ComponentCacheItem::SymbolLookupKey(name, l, 0));
513 return it != m_compByPath.end() ? it->second :
nullptr;
521 GAIA_NODISCARD
const ComponentCacheItem* short_symbol(
const char* name, uint32_t len = 0) const noexcept {
522 GAIA_ASSERT(name !=
nullptr);
524 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, ComponentCacheItem::MaxNameLength) : len;
525 GAIA_ASSERT(l < ComponentCacheItem::MaxNameLength);
527 const auto it = m_compByShortSymbol.find(ComponentCacheItem::SymbolLookupKey(name, l, 0));
528 return it != m_compByShortSymbol.end() ? it->second :
nullptr;
531 GAIA_NODISCARD ComponentCacheItem* symbol(
const char* name, uint32_t len = 0) noexcept {
532 return const_cast<ComponentCacheItem*
>(
const_cast<const ComponentCache*
>(
this)->symbol(name, len));
535 GAIA_NODISCARD ComponentCacheItem* path(
const char* name, uint32_t len = 0) noexcept {
536 return const_cast<ComponentCacheItem*
>(
const_cast<const ComponentCache*
>(
this)->path(name, len));
539 GAIA_NODISCARD ComponentCacheItem* short_symbol(
const char* name, uint32_t len = 0) noexcept {
540 return const_cast<ComponentCacheItem*
>(
const_cast<const ComponentCache*
>(
this)->short_symbol(name, len));
550 GAIA_NODISCARD
const ComponentCacheItem* resolve(
const char* name, uint32_t len = 0) const noexcept {
551 if (
const auto* pItem = symbol(name, len); pItem !=
nullptr)
553 if (
const auto* pItem = path(name, len); pItem !=
nullptr)
555 if (
const auto* pItem = short_symbol(name, len); pItem !=
nullptr)
560 GAIA_NODISCARD ComponentCacheItem* resolve(
const char* name, uint32_t len = 0) noexcept {
561 return const_cast<ComponentCacheItem*
>(
const_cast<const ComponentCache*
>(
this)->resolve(name, len));
570 void resolve(cnt::darray<const ComponentCacheItem*>& out,
const char* name, uint32_t len = 0)
const {
571 GAIA_ASSERT(name !=
nullptr);
574 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, ComponentCacheItem::MaxNameLength) : len;
575 GAIA_ASSERT(l < ComponentCacheItem::MaxNameLength);
576 const auto needle = util::str_view(name, l);
578 auto push_unique = [&](
const ComponentCacheItem* pItem) {
579 if (pItem ==
nullptr)
581 for (
const auto* pExisting: out) {
582 if (pExisting == pItem)
585 out.push_back(pItem);
588 push_unique(symbol(name, l));
589 push_unique(short_symbol(name, l));
591 if (
const auto* pItem = path(name, l); pItem !=
nullptr) {
594 for_each_item([&](
const ComponentCacheItem& item) {
595 if (item.path.view() == needle)
607 GAIA_NODISCARD
const ComponentCacheItem& get(
const char* name, uint32_t len = 0) const noexcept {
608 const auto* pItem = resolve(name, len);
609 GAIA_ASSERT(pItem !=
nullptr);
619 GAIA_NODISCARD ComponentCacheItem& get(
const char* name, uint32_t len = 0) noexcept {
620 auto* pItem = resolve(name, len);
621 GAIA_ASSERT(pItem !=
nullptr);
629 template <
typename T>
633 return find(compDescId);
639 template <
typename T>
643 return get(compDescId);
651 static ComponentCacheItem::Hooks& hooks(
const ComponentCacheItem& cacheItem)
noexcept {
658 const auto registeredTypes = m_itemArr.size();
659 GAIA_LOG_N(
"Registered components: %u", registeredTypes);
661 auto logDesc = [](
const ComponentCacheItem& item) {
663 " hash:%016" PRIx64
", size:%3u B, align:%3u B, [%u:%u] %s [%s]", item.hashLookup.hash,
664 item.comp.size(), item.comp.alig(), item.entity.id(), item.entity.gen(), item.name.str(),
665 EntityKindString[item.entity.kind()]);
667 for (
const auto* pItem: m_itemArr) {
668 if (pItem ==
nullptr)
672 for (
auto [componentId, pItem]: m_itemByDescId)