26 static constexpr uint32_t MaxNameLength = 256;
30 using FuncCtor = void(
void*, uint32_t);
31 using FuncDtor = void(
void*, uint32_t);
32 using FuncFrom = void(
void*,
void*, uint32_t, uint32_t, uint32_t, uint32_t);
33 using FuncCopy = void(
void*,
const void*, uint32_t, uint32_t, uint32_t, uint32_t);
34 using FuncMove = void(
void*,
void*, uint32_t, uint32_t, uint32_t, uint32_t);
35 using FuncSwap = void(
void*,
void*, uint32_t, uint32_t, uint32_t, uint32_t);
36 using FuncCmp = bool(
const void*,
const void*);
38 using FuncSave = void(
ser::serializer&,
const void*, uint32_t, uint32_t, uint32_t);
39 using FuncLoad = void(
ser::serializer&,
void*, uint32_t, uint32_t, uint32_t);
46 char name[MaxNameLength]{};
47 ser::serialization_type_id type = ser::serialization_type_id::u8;
53 uint32_t compDescId = 0;
54 const char* nameStr =
nullptr;
58 DataStorageType storageType = DataStorageType::Table;
60 const uint8_t* pSoaSizes =
nullptr;
62 FuncCtor* funcCtor =
nullptr;
63 FuncMove* funcMoveCtor =
nullptr;
64 FuncCopy* funcCopyCtor =
nullptr;
65 FuncDtor* funcDtor =
nullptr;
66 FuncCopy* funcCopy =
nullptr;
67 FuncMove* funcMove =
nullptr;
68 FuncSwap* funcSwap =
nullptr;
69 FuncCmp* funcCmp =
nullptr;
70 FuncSave* funcSave =
nullptr;
71 FuncLoad* funcLoad =
nullptr;
81 uint8_t soaSizes[meta::StructToTupleMaxTypes];
88 FuncCtor* func_ctor{};
90 FuncMove* func_move_ctor{};
92 FuncCopy* func_copy_ctor{};
94 FuncDtor* func_dtor{};
96 FuncCopy* func_copy{};
98 FuncMove* func_move{};
100 FuncSwap* func_swap{};
104 FuncSave* func_save{};
106 FuncLoad* func_load{};
110 #if GAIA_ENABLE_ADD_DEL_HOOKS
112 FuncOnAdd* func_add{};
114 FuncOnDel* func_del{};
116 #if GAIA_ENABLE_SET_HOOKS
118 FuncOnSet* func_set{};
123 cnt::darray<SchemaField> schema;
126 ComponentCacheItem() =
default;
127 ~ComponentCacheItem() =
default;
130 ComponentCacheItem(
const ComponentCacheItem&) =
delete;
131 ComponentCacheItem(ComponentCacheItem&&) =
delete;
132 ComponentCacheItem& operator=(
const ComponentCacheItem&) =
delete;
133 ComponentCacheItem& operator=(ComponentCacheItem&&) =
delete;
136 ctor_move(
void* pDst,
void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc)
const {
137 GAIA_ASSERT(pSrc !=
nullptr && pDst !=
nullptr);
138 GAIA_ASSERT(pSrc != pDst || idxSrc != idxDst);
139 if (func_move_ctor !=
nullptr) {
140 func_move_ctor(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
144 if (comp.soa() != 0 || comp.size() == 0)
147 auto* pD = (uint8_t*)pDst + ((uintptr_t)comp.size() * idxDst);
148 auto* pS = (uint8_t*)pSrc + ((uintptr_t)comp.size() * idxSrc);
149 memmove((
void*)pD, (
const void*)pS, comp.size());
153 void* pDst,
const void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc)
const {
154 GAIA_ASSERT(pSrc !=
nullptr && pDst !=
nullptr);
155 GAIA_ASSERT(pSrc != pDst || idxSrc != idxDst);
156 if (func_copy_ctor !=
nullptr) {
157 func_copy_ctor(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
161 if (comp.soa() != 0 || comp.size() == 0)
164 auto* pD = (uint8_t*)pDst + ((uintptr_t)comp.size() * idxDst);
165 auto* pS = (
const uint8_t*)pSrc + ((uintptr_t)comp.size() * idxSrc);
166 memcpy((
void*)pD, (
const void*)pS, comp.size());
169 void dtor(
void* pSrc)
const {
170 if (func_dtor !=
nullptr)
175 copy(
void* pDst,
const void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc)
const {
176 GAIA_ASSERT(pSrc !=
nullptr && pDst !=
nullptr);
177 GAIA_ASSERT(pSrc != pDst || idxSrc != idxDst);
178 if (func_copy !=
nullptr) {
179 func_copy(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
183 if (comp.soa() != 0 || comp.size() == 0)
186 auto* pD = (uint8_t*)pDst + ((uintptr_t)comp.size() * idxDst);
187 auto* pS = (
const uint8_t*)pSrc + ((uintptr_t)comp.size() * idxSrc);
188 memcpy((
void*)pD, (
const void*)pS, comp.size());
191 void move(
void* pDst,
void* pSrc, uint32_t idxDst, uint32_t idxSrc, uint32_t sizeDst, uint32_t sizeSrc)
const {
192 GAIA_ASSERT(pSrc !=
nullptr && pDst !=
nullptr);
193 GAIA_ASSERT(pSrc != pDst || idxSrc != idxDst);
194 if (func_move !=
nullptr) {
195 func_move(pDst, pSrc, idxDst, idxSrc, sizeDst, sizeSrc);
199 if (comp.soa() != 0 || comp.size() == 0)
202 auto* pD = (uint8_t*)pDst + ((uintptr_t)comp.size() * idxDst);
203 auto* pS = (uint8_t*)pSrc + ((uintptr_t)comp.size() * idxSrc);
204 memmove((
void*)pD, (
const void*)pS, comp.size());
208 swap(
void* pLeft,
void* pRight, uint32_t idxLeft, uint32_t idxRight, uint32_t sizeDst, uint32_t sizeSrc)
const {
209 GAIA_ASSERT(pLeft !=
nullptr && pRight !=
nullptr);
210 if (func_swap !=
nullptr) {
211 func_swap(pLeft, pRight, idxLeft, idxRight, sizeDst, sizeSrc);
215 if (comp.soa() != 0 || comp.size() == 0)
218 auto* l = (uint8_t*)pLeft + ((uintptr_t)comp.size() * idxLeft);
219 auto* r = (uint8_t*)pRight + ((uintptr_t)comp.size() * idxRight);
220 GAIA_FOR(comp.size()) {
221 const auto tmp = l[i];
227 bool cmp(
const void* pLeft,
const void* pRight)
const {
228 GAIA_ASSERT(pLeft != pRight);
229 if (func_cmp !=
nullptr)
230 return func_cmp(pLeft, pRight);
232 if (comp.soa() != 0 || comp.size() == 0)
235 return memcmp(pLeft, pRight, comp.size()) == 0;
238 void save(ser::serializer& serializer,
const void* pSrc, uint32_t from, uint32_t to, uint32_t cap)
const {
239 GAIA_ASSERT(serializer.valid() && pSrc !=
nullptr && from < to && to <= cap);
240 if (func_save !=
nullptr) {
241 func_save(serializer, pSrc, from, to, cap);
245 if (comp.soa() != 0 || comp.size() == 0)
248 const auto* pBase = (
const uint8_t*)pSrc;
249 GAIA_FOR2(from, to) {
250 const auto* p = pBase + ((uintptr_t)comp.size() * i);
251 serializer.save_raw((
const void*)p, comp.size(), ser::serialization_type_id::trivial_wrapper);
255 void load(ser::serializer& serializer,
void* pDst, uint32_t from, uint32_t to, uint32_t cap)
const {
256 GAIA_ASSERT(serializer.valid() && pDst !=
nullptr && from < to && to <= cap);
257 if (func_load !=
nullptr) {
258 func_load(serializer, pDst, from, to, cap);
262 if (comp.soa() != 0 || comp.size() == 0)
265 auto* pBase = (uint8_t*)pDst;
266 GAIA_FOR2(from, to) {
267 auto* p = pBase + ((uintptr_t)comp.size() * i);
268 serializer.load_raw((
void*)p, comp.size(), ser::serialization_type_id::trivial_wrapper);
272 GAIA_NODISCARD
bool set_field(
273 const char* fieldName, uint32_t len, ser::serialization_type_id type, uint32_t fieldOffset,
274 uint32_t fieldSize) {
275 if (fieldName ==
nullptr || fieldName[0] == 0)
278 const auto fieldLen = len == 0 ? (uint32_t)GAIA_STRLEN(fieldName, MaxNameLength) : len;
279 if (fieldLen == 0 || fieldLen >= MaxNameLength)
282 for (
auto& f: schema) {
283 if (strncmp(f.name, fieldName, fieldLen) == 0 && f.name[fieldLen] == 0) {
285 f.offset = fieldOffset;
292 memcpy((
void*)f.name, (
const void*)fieldName, fieldLen);
293 f.name[fieldLen] = 0;
295 f.offset = fieldOffset;
301 void clear_fields() {
305 GAIA_NODISCARD
bool has_fields()
const {
306 return !schema.empty();
314 const Hooks& hooks()
const {
320 GAIA_NODISCARD uint32_t calc_new_mem_offset(uint32_t addr,
size_t cnt)
const noexcept {
321 if (comp.soa() == 0) {
322 addr = (uint32_t)mem::detail::get_aligned_byte_offset(addr, comp.alig(), comp.size(), cnt);
324 GAIA_FOR(comp.soa()) {
325 addr = (uint32_t)mem::detail::get_aligned_byte_offset(addr, comp.alig(), soaSizes[i], cnt);
330 addr += comp.soa() * 12;
336 template <
typename T>
337 GAIA_NODISCARD
static uint32_t init_type_name(
char (&nameTmp)[MaxNameLength]) {
338 auto ct_name = detail::ComponentDesc<T>::name();
347 auto nameTmpLen = (uint32_t)ct_name.size();
348 GAIA_ASSERT(nameTmpLen < MaxNameLength);
349 memcpy((
void*)nameTmp, (
const void*)ct_name.data(), nameTmpLen);
350 nameTmp[ct_name.size()] = 0;
352 auto strip_prefix = [&](
const char* prefix, uint32_t prefixLen) {
353 if (nameTmpLen <= prefixLen || strncmp(nameTmp, prefix, prefixLen) != 0)
356 memmove(nameTmp, nameTmp + prefixLen, nameTmpLen - prefixLen + 1);
357 nameTmpLen -= prefixLen;
360 strip_prefix(
"const ", 6);
362 const uint32_t NSubstrings = 3;
363 const char* to_remove[NSubstrings] = {
"class ",
"struct ",
"enum "};
364 const uint32_t to_remove_len[NSubstrings] = {6, 7, 5};
365 GAIA_FOR(NSubstrings) {
366 strip_prefix(to_remove[i], to_remove_len[i]);
369 while (nameTmpLen > 0) {
370 const auto ch = nameTmp[nameTmpLen - 1];
371 if (ch !=
' ' && ch !=
'&' && ch !=
'*')
374 nameTmp[--nameTmpLen] = 0;
377 if (nameTmpLen > 6 && strncmp(nameTmp + nameTmpLen - 6,
" const", 6) == 0) {
379 nameTmp[nameTmpLen] = 0;
384 GAIA_FOR(NSubstrings) {
385 const auto* str = to_remove[i];
386 const auto len = to_remove_len[i];
389 while ((pos = strstr(pos, str)) !=
nullptr) {
390 const bool isBoundary = pos == nameTmp || pos[-1] ==
'<' || pos[-1] ==
',' || pos[-1] ==
' ';
396 const auto tailMaxLen = (size_t)(MaxNameLength - (uint32_t)(pos + len - nameTmp));
397 memmove(pos, pos + len, GAIA_STRLEN(pos + len, tailMaxLen) + 1);
405 static void init_name(SymbolLookupKey& nameOut,
const char* nameStr, uint32_t nameLen) {
406 char* name = mem::AllocHelper::alloc<char>(nameLen + 1);
407 memcpy((
void*)name, (
const void*)nameStr, nameLen);
409 nameOut = SymbolLookupKey(name, nameLen, 1);
413 template <
typename T>
414 GAIA_NODISCARD
static ComponentCacheItem* create(Entity entity) {
415 static_assert(core::is_raw_v<T>);
417 constexpr auto componentSize = detail::ComponentDesc<T>::size();
419 componentSize < Component::MaxComponentSizeInBytes,
420 "Trying to register a component larger than the maximum allowed component size! In the future this "
421 "restriction won't apply to components not stored inside archetype chunks.");
423 char nameTmp[MaxNameLength];
424 const auto nameTmpLen = init_type_name<T>(nameTmp);
426 ComponentCacheItemCtx ctx{};
427 ctx.compDescId = detail::ComponentDesc<T>::id();
428 ctx.nameStr = nameTmp;
429 ctx.nameLen = nameTmpLen;
430 ctx.size = componentSize;
431 ctx.alig = detail::ComponentDesc<T>::alig();
432 ctx.storageType = DataStorageType::Table;
433 uint8_t soaSizes[meta::StructToTupleMaxTypes]{};
434 ctx.soa = detail::ComponentDesc<T>::soa(soaSizes);
435 ctx.pSoaSizes = soaSizes;
436 ctx.hashLookup = detail::ComponentDesc<T>::hash_lookup();
437 ctx.funcCtor = detail::ComponentDesc<T>::func_ctor();
438 ctx.funcMoveCtor = detail::ComponentDesc<T>::func_move_ctor();
439 ctx.funcCopyCtor = detail::ComponentDesc<T>::func_copy_ctor();
440 ctx.funcDtor = detail::ComponentDesc<T>::func_dtor();
441 ctx.funcCopy = detail::ComponentDesc<T>::func_copy();
442 ctx.funcMove = detail::ComponentDesc<T>::func_move();
443 ctx.funcSwap = detail::ComponentDesc<T>::func_swap();
444 ctx.funcCmp = detail::ComponentDesc<T>::func_cmp();
445 ctx.funcSave = detail::ComponentDesc<T>::func_save();
446 ctx.funcLoad = detail::ComponentDesc<T>::func_load();
447 return create(entity, ctx);
450 GAIA_NODISCARD
static ComponentCacheItem* create(Entity entity,
const ComponentCacheItemCtx& ctx) {
451 GAIA_ASSERT(ctx.nameStr !=
nullptr && ctx.nameLen > 0 && ctx.nameLen < MaxNameLength);
452 GAIA_ASSERT(ctx.size < Component::MaxComponentSizeInBytes);
453 GAIA_ASSERT((ctx.size == 0 && ctx.alig == 0) || (ctx.alig > 0 && ctx.alig < Component::MaxAlignment));
454 GAIA_ASSERT(ctx.soa <= meta::StructToTupleMaxTypes);
456 auto* cci = mem::AllocHelper::alloc<ComponentCacheItem>(
"ComponentCacheItem");
457 (void)
new (cci) ComponentCacheItem();
458 cci->entity = entity;
459 cci->comp = Component(ctx.compDescId, ctx.soa, ctx.size, ctx.alig, ctx.storageType);
460 cci->hashLookup = ctx.hashLookup.hash != 0
462 : ComponentLookupHash{core::calculate_hash64(ctx.nameStr, ctx.nameLen)};
464 if (ctx.soa > 0 && ctx.pSoaSizes !=
nullptr) {
465 GAIA_FOR(ctx.soa) cci->soaSizes[i] = ctx.pSoaSizes[i];
468 init_name(cci->name, ctx.nameStr, ctx.nameLen);
470 cci->func_ctor = ctx.funcCtor;
471 cci->func_move_ctor = ctx.funcMoveCtor;
472 cci->func_copy_ctor = ctx.funcCopyCtor;
473 cci->func_dtor = ctx.funcDtor;
474 cci->func_copy = ctx.funcCopy;
475 cci->func_move = ctx.funcMove;
476 cci->func_swap = ctx.funcSwap;
477 cci->func_cmp = ctx.funcCmp;
478 cci->func_save = ctx.funcSave;
479 cci->func_load = ctx.funcLoad;
484 static
void destroy(ComponentCacheItem* pItem) {
485 if (pItem ==
nullptr)
488 if (pItem->name.str() !=
nullptr && pItem->name.owned()) {
489 mem::AllocHelper::free((
void*)pItem->name.str());
493 pItem->~ComponentCacheItem();
494 mem::AllocHelper::free(
"ComponentCacheItem", pItem);