2#include "gaia/config/config.h"
3#include "gaia/config/profiler.h"
11#include "gaia/cnt/sarray_ext.h"
12#include "gaia/core/utility.h"
13#include "gaia/ecs/archetype_common.h"
14#include "gaia/ecs/chunk_allocator.h"
15#include "gaia/ecs/chunk_header.h"
16#include "gaia/ecs/common.h"
17#include "gaia/ecs/component.h"
18#include "gaia/ecs/component_cache.h"
19#include "gaia/ecs/component_desc.h"
20#include "gaia/ecs/entity_container.h"
21#include "gaia/ecs/id.h"
22#include "gaia/ecs/ser_binary.h"
23#include "gaia/mem/data_layout_policy.h"
24#include "gaia/mem/mem_alloc.h"
25#include "gaia/ser/ser_rt.h"
53 GAIA_MSVC_WARNING_PUSH()
54 GAIA_MSVC_WARNING_DISABLE(26495)
61 uint32_t chunkIndex, uint16_t capacity, uint8_t genEntities,
62 uint32_t& worldVersion):
63 m_header(wld, cc, chunkIndex, capacity, genEntities, worldVersion) {
70 GAIA_MSVC_WARNING_POP()
72 GAIA_CLANG_WARNING_PUSH()
74 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
78 const ChunkDataOffset* compOffs) {
85 if (cntEntities > 0) {
91 for (; j < cntEntities; ++j)
93 for (; j < ChunkHeader::MAX_COMPONENTS; ++j)
98 if (cntEntities > 0) {
100 GAIA_FOR_(cntEntities, j) {
101 dst[j].comp = comps[j];
102 dst[j].pData = &data(compOffs[j]);
103 dst[j].pItem = m_header.
cc->
find(comps[j].
id());
111 auto recs = comp_rec_view();
112 const auto recs_cnt = recs.size();
114 const auto& rec = recs[i];
115 if (rec.comp.size() == 0)
119 if (e.kind() == EntityKind::EK_Gen) {
127 call_ctor(0, *rec.pItem);
133 update_world_version_init();
136 GAIA_CLANG_WARNING_POP()
158 template <
typename T>
159 GAIA_NODISCARD GAIA_FORCEINLINE
auto view_inter(uint32_t from, uint32_t to)
const
162 if constexpr (std::is_same_v<core::raw_t<T>,
Entity>) {
163 GAIA_ASSERT(to <= m_header.
count);
164 return {(
const uint8_t*)&m_records.
pEntities[from], to - from};
166 using TT =
typename T::type;
167 using U =
typename component_type_t<TT>::Type;
168 static_assert(!std::is_empty_v<U>,
"Attempting to get value of an empty component");
170 constexpr auto kind = entity_kind_v<TT>;
171 const auto rel = m_header.
cc->
get<
typename T::rel>().entity;
172 const auto tgt = m_header.
cc->
get<
typename T::tgt>().entity;
173 const auto compIdx = comp_idx((
Entity)
Pair(rel, tgt));
175 if constexpr (mem::is_soa_layout_v<U>) {
176 GAIA_ASSERT(from == 0);
177 GAIA_ASSERT(to == capacity());
178 return {comp_ptr(compIdx), to};
179 }
else if constexpr (kind == EntityKind::EK_Gen) {
180 GAIA_ASSERT(to <= m_header.
count);
181 return {comp_ptr(compIdx, from), to - from};
183 GAIA_ASSERT(to <= m_header.
count);
185 return {comp_ptr(compIdx), 1};
188 using U =
typename component_type_t<T>::Type;
189 static_assert(!std::is_empty_v<U>,
"Attempting to get value of an empty component");
191 constexpr auto kind = entity_kind_v<T>;
192 const auto comp = m_header.
cc->
get<T>().entity;
193 GAIA_ASSERT(comp.kind() == kind);
194 const auto compIdx = comp_idx(comp);
196 if constexpr (mem::is_soa_layout_v<U>) {
197 GAIA_ASSERT(from == 0);
198 GAIA_ASSERT(to == capacity());
199 return {comp_ptr(compIdx), to};
200 }
else if constexpr (kind == EntityKind::EK_Gen) {
201 GAIA_ASSERT(to <= m_header.
count);
202 return {comp_ptr(compIdx, from), to - from};
204 GAIA_ASSERT(to <= m_header.
count);
206 return {comp_ptr(compIdx), 1};
216 template <
typename T,
bool WorldVersionUpdateWanted>
217 GAIA_NODISCARD GAIA_FORCEINLINE
auto view_mut_inter(uint32_t from, uint32_t to)
219 static_assert(!std::is_same_v<core::raw_t<T>,
Entity>,
"view_mut can't be used to modify Entity");
222 using TT =
typename T::type;
223 using U =
typename component_type_t<TT>::Type;
224 static_assert(!std::is_empty_v<U>,
"view_mut can't be used to modify tag components");
226 constexpr auto kind = entity_kind_v<TT>;
227 const auto rel = m_header.
cc->
get<
typename T::rel>().entity;
228 const auto tgt = m_header.
cc->
get<
typename T::tgt>().entity;
229 const auto compIdx = comp_idx((
Entity)
Pair(rel, tgt));
232 if constexpr (WorldVersionUpdateWanted) {
233 update_world_version(compIdx);
235#if GAIA_ENABLE_SET_HOOKS
236 const auto& rec = m_records.
pRecords[compIdx];
237 if GAIA_UNLIKELY (rec.pItem->comp_hooks.func_set !=
nullptr)
238 rec.pItem->comp_hooks.func_set(*m_header.
world, rec, *
this);
242 if constexpr (mem::is_soa_layout_v<U>) {
243 GAIA_ASSERT(from == 0);
244 GAIA_ASSERT(to == capacity());
245 return {comp_ptr_mut(compIdx), to};
246 }
else if constexpr (kind == EntityKind::EK_Gen) {
247 GAIA_ASSERT(to <= m_header.
count);
248 return {comp_ptr_mut(compIdx, from), to - from};
250 GAIA_ASSERT(to <= m_header.
count);
252 return {comp_ptr_mut(compIdx), 1};
255 using U =
typename component_type_t<T>::Type;
256 static_assert(!std::is_empty_v<U>,
"view_mut can't be used to modify tag components");
258 constexpr auto kind = entity_kind_v<T>;
259 const auto comp = m_header.
cc->
get<T>().entity;
260 GAIA_ASSERT(comp.kind() == kind);
261 const auto compIdx = comp_idx(comp);
264 if constexpr (WorldVersionUpdateWanted) {
265 update_world_version(compIdx);
267#if GAIA_ENABLE_SET_HOOKS
268 const auto& rec = m_records.
pRecords[compIdx];
269 if GAIA_UNLIKELY (rec.pItem->comp_hooks.func_set !=
nullptr)
270 rec.pItem->comp_hooks.func_set(*m_header.
world, rec, *
this);
274 if constexpr (mem::is_soa_layout_v<U>) {
275 GAIA_ASSERT(from == 0);
276 GAIA_ASSERT(to == capacity());
277 return {comp_ptr_mut(compIdx), to};
278 }
else if constexpr (kind == EntityKind::EK_Gen) {
279 GAIA_ASSERT(to <= m_header.
count);
280 return {comp_ptr_mut(compIdx, from), to - from};
282 GAIA_ASSERT(to <= m_header.
count);
284 return {comp_ptr_mut(compIdx), 1};
296 template <
bool WorldVersionUpdateWanted>
299 if constexpr (WorldVersionUpdateWanted) {
300 update_world_version(compIdx);
302#if GAIA_ENABLE_SET_HOOKS
303 const auto& rec = m_records.
pRecords[compIdx];
304 if GAIA_UNLIKELY (rec.pItem->comp_hooks.func_set !=
nullptr)
305 rec.pItem->comp_hooks.func_set(*m_header.
world, rec, *
this);
309 return comp_ptr_mut(compIdx, row);
319 template <
typename T>
320 GAIA_NODISCARD
decltype(
auto) comp_inter(uint16_t row)
const {
321 using U =
typename actual_type_t<T>::Type;
322 using RetValueType =
decltype(view<T>()[0]);
324 GAIA_ASSERT(row < m_header.
count);
325 if constexpr (mem::is_soa_layout_v<U>)
326 return view<T>(0, capacity())[row];
327 else if constexpr (
sizeof(RetValueType) <= 8)
328 return view<T>()[row];
330 return (
const U&)view<T>()[row];
334 Chunk(
const Chunk& chunk) =
delete;
335 Chunk(Chunk&& chunk) =
delete;
336 Chunk& operator=(
const Chunk& chunk) =
delete;
337 Chunk& operator=(Chunk&& chunk) =
delete;
340 static constexpr uint16_t chunk_header_size() {
341 const auto dataAreaOffset =
343 MemoryBlockUsableOffset +
345 sizeof(ChunkHeader) +
sizeof(ChunkRecords);
346 static_assert(dataAreaOffset < UINT16_MAX);
347 return dataAreaOffset;
350 static constexpr uint16_t chunk_total_bytes(uint16_t dataSize) {
351 return chunk_header_size() + dataSize;
354 static constexpr uint16_t chunk_data_bytes(uint16_t totalSize) {
355 return totalSize - chunk_header_size();
363 const auto chunk_offset = (uintptr_t)&chunk;
364 const auto data_offset = (uintptr_t)&chunk.m_data[0];
365 return data_offset - chunk_offset;
372 uint32_t chunkIndex, uint16_t capacity, uint8_t cntEntities, uint8_t genEntities,
373 uint16_t dataBytes, uint32_t& worldVersion,
381 const ChunkDataOffset* compOffs) {
382 const auto totalBytes = chunk_total_bytes(dataBytes);
383#if GAIA_ECS_CHUNK_ALLOCATOR
384 auto* pChunk = (
Chunk*)ChunkAllocator::get().alloc(totalBytes);
385 (void)
new (pChunk)
Chunk(wld, cc, chunkIndex, capacity, genEntities, worldVersion);
387 GAIA_ASSERT(totalBytes <= MaxMemoryBlockSize);
388 const auto sizeType = mem_block_size_type(totalBytes);
389 const auto allocSize = mem_block_size(sizeType);
390 auto* pChunkMem = mem::AllocHelper::alloc<uint8_t>(allocSize);
391 std::memset(pChunkMem, 0, allocSize);
392 auto* pChunk =
new (pChunkMem)
Chunk(wld, cc, chunkIndex, capacity, genEntities, worldVersion);
395 pChunk->init((uint32_t)cntEntities, ids, comps, offsets, compOffs);
402 GAIA_ASSERT(pChunk !=
nullptr);
403 GAIA_ASSERT(!pChunk->
dead());
409 pChunk->call_all_dtors();
412#if GAIA_ECS_CHUNK_ALLOCATOR
413 ChunkAllocator::get().free(pChunk);
415 mem::AllocHelper::free((uint8_t*)pChunk);
420 s.save(m_header.
count);
421 if (m_header.
count == 0)
426 const uint16_t dead = m_header.
dead;
429 s.save(lifespanCountdown);
431 const auto cnt = (uint32_t)m_header.
count;
432 const auto cap = (uint32_t)m_header.
capacity;
437 GAIA_FOR(cnt) s.save(pData[i]);
442 for (
const auto& rec: comp_rec_view()) {
444 if (rec.comp.size() == 0)
447 rec.pItem->save(&s, rec.pData, 0, cnt, cap);
452 void load(ser::ISerializer& s) {
453 uint16_t prevCount = m_header.
count;
454 s.load(m_header.
count);
455 if (m_header.
count == 0)
461 uint16_t lifespanCountdown = 0;
463 s.load(lifespanCountdown);
464 m_header.
dead = dead != 0;
467 const auto cnt = (uint32_t)m_header.
count;
468 const auto cap = (uint32_t)m_header.
capacity;
475 entity_view_mut()[i] = e;
480 call_gen_ctors(prevCount, cnt);
482 for (
const auto& rec: comp_rec_view()) {
484 if (rec.comp.size() == 0)
487 rec.pItem->load(&s, rec.pData, 0, cnt, cap);
496 GAIA_ASSERT(!empty());
498#if GAIA_ASSERT_ENABLED
500 entity_view_mut()[m_header.
count - 1] = EntityBad;
509 update_world_version();
518 template <
typename T>
519 GAIA_NODISCARD
decltype(
auto)
view(uint16_t from, uint16_t to)
const {
520 using U =
typename actual_type_t<T>::Type;
523 if constexpr (mem::is_soa_layout_v<U>)
529 template <
typename T>
530 GAIA_NODISCARD
decltype(
auto) view()
const {
531 return view<T>(0, m_header.
count);
534 template <
typename T>
535 GAIA_NODISCARD
decltype(
auto) view_raw(
const void* ptr, uint32_t size)
const {
536 using U =
typename actual_type_t<T>::Type;
546 template <
typename T>
547 GAIA_NODISCARD
decltype(
auto)
view_mut(uint16_t from, uint16_t to) {
548 using U =
typename actual_type_t<T>::Type;
549 static_assert(!std::is_same_v<U, Entity>,
"Modifying chunk entities via view_mut is forbidden");
552 if constexpr (mem::is_soa_layout_v<U>)
558 template <
typename T>
559 GAIA_NODISCARD
decltype(
auto) view_mut() {
560 return view_mut<T>(0, m_header.
count);
563 template <
typename T>
564 GAIA_NODISCARD
decltype(
auto) view_mut_raw(
void* ptr, uint32_t size)
const {
565 using U =
typename actual_type_t<T>::Type;
566 static_assert(!std::is_same_v<U, Entity>,
"Modifying chunk entities via view_mut is forbidden");
578 template <
typename T>
579 GAIA_NODISCARD
decltype(
auto)
sview_mut(uint16_t from, uint16_t to) {
580 using U =
typename actual_type_t<T>::Type;
581 static_assert(!std::is_same_v<U, Entity>,
"Modifying chunk entities via sview_mut is forbidden");
584 if constexpr (mem::is_soa_layout_v<U>)
590 template <
typename T>
591 GAIA_NODISCARD
decltype(
auto) sview_mut_raw(
void* ptr, uint32_t size)
const {
592 using U =
typename actual_type_t<T>::Type;
593 static_assert(!std::is_same_v<U, Entity>,
"Modifying chunk entities via sview_mut is forbidden");
598 template <
typename T>
599 GAIA_NODISCARD
decltype(
auto) sview_mut() {
600 return sview_mut<T>(0, m_header.
count);
614 static_assert(!std::is_same_v<core::raw_t<T>,
Entity>,
"mod can't be used to modify Entity");
617 using TT =
typename T::type;
618 using U =
typename component_type_t<TT>::Type;
619 static_assert(!std::is_empty_v<U>,
"mut can't be used to modify tag components");
621#if GAIA_ASSERT_ENABLED
624 const auto rel = m_header.
cc->
get<
typename T::rel>().entity;
625 const auto tgt = m_header.
cc->
get<
typename T::tgt>().entity;
626 const auto compIdx = comp_idx((
Entity)
Pair(rel, tgt));
629 update_world_version(compIdx);
631#if GAIA_ENABLE_SET_HOOKS
632 if constexpr (TriggerHooks) {
633 const auto& rec = m_records.
pRecords[compIdx];
634 if GAIA_UNLIKELY (rec.pItem->comp_hooks.func_set !=
nullptr)
635 rec.pItem->comp_hooks.func_set(*m_header.
world, rec, *
this);
639 using U =
typename component_type_t<T>::Type;
640 static_assert(!std::is_empty_v<U>,
"mut can't be used to modify tag components");
642#if GAIA_ASSERT_ENABLED
643 constexpr auto kind = entity_kind_v<T>;
645 const auto comp = m_header.
cc->
get<T>().entity;
646 GAIA_ASSERT(comp.kind() == kind);
647 const auto compIdx = comp_idx(comp);
650 update_world_version(compIdx);
652#if GAIA_ENABLE_SET_HOOKS
653 if constexpr (TriggerHooks) {
654 const auto& rec = m_records.
pRecords[compIdx];
655 if GAIA_UNLIKELY (rec.pItem->comp_hooks.func_set !=
nullptr)
656 rec.pItem->comp_hooks.func_set(*m_header.
world, rec, *
this);
669 template <
typename T>
670 GAIA_NODISCARD
decltype(
auto)
view_auto(uint16_t from, uint16_t to) {
671 using UOriginal =
typename actual_type_t<T>::TypeOriginal;
672 if constexpr (core::is_mut_v<UOriginal>)
673 return view_mut<T>(from, to);
675 return view<T>(from, to);
678 template <
typename T>
679 GAIA_NODISCARD
decltype(
auto) view_auto() {
680 return view_auto<T>(0, m_header.
count);
691 template <
typename T>
692 GAIA_NODISCARD
decltype(
auto)
sview_auto(uint16_t from, uint16_t to) {
693 using UOriginal =
typename actual_type_t<T>::TypeOriginal;
694 if constexpr (core::is_mut_v<UOriginal>)
695 return sview_mut<T>(from, to);
697 return view<T>(from, to);
700 template <
typename T>
701 GAIA_NODISCARD
decltype(
auto) sview_auto() {
702 return sview_auto<T>(0, m_header.
count);
705 GAIA_NODISCARD EntitySpan entity_view()
const {
709 GAIA_NODISCARD EntitySpan ids_view()
const {
717 GAIA_NODISCARD uint8_t* comp_ptr_mut(uint32_t compIdx) {
718 const auto& rec = m_records.
pRecords[compIdx];
722 GAIA_NODISCARD uint8_t* comp_ptr_mut(uint32_t compIdx, uint32_t offset) {
723 const auto& rec = m_records.
pRecords[compIdx];
724 return rec.
pData + ((uintptr_t)rec.comp.size() * offset);
727 GAIA_NODISCARD
const uint8_t* comp_ptr(uint32_t compIdx)
const {
728 const auto& rec = m_records.
pRecords[compIdx];
732 GAIA_NODISCARD
const uint8_t* comp_ptr(uint32_t compIdx, uint32_t offset)
const {
733 const auto& rec = m_records.
pRecords[compIdx];
734 return rec.
pData + ((uintptr_t)rec.comp.size() * offset);
740 const auto row = m_header.
count++;
743 GAIA_ASSERT(m_header.
count != 0);
746 entity_view_mut()[row] = entity;
756 GAIA_PROF_SCOPE(Chunk::copy_entity_data);
758 auto& srcEntityContainer = recs[srcEntity];
759 auto* pSrcChunk = srcEntityContainer.pChunk;
761 auto& dstEntityContainer = recs[dstEntity];
762 auto* pDstChunk = dstEntityContainer.pChunk;
764 GAIA_ASSERT(srcEntityContainer.pArchetype == dstEntityContainer.pArchetype);
766 auto srcRecs = pSrcChunk->comp_rec_view();
770 GAIA_FOR(pSrcChunk->m_header.genEntities) {
771 const auto& rec = srcRecs[i];
772 if (rec.comp.size() == 0U)
775 const auto* pSrc = (
const void*)pSrcChunk->comp_ptr_mut(i);
776 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(i);
778 pDst, pSrc, dstEntityContainer.row, srcEntityContainer.row, pDstChunk->capacity(), pSrcChunk->capacity());
787 GAIA_PROF_SCOPE(Chunk::move_entity_data);
789 auto& ec = recs[entity];
790 auto* pSrcChunk = ec.pChunk;
791 auto srcRecs = pSrcChunk->comp_rec_view();
795 GAIA_FOR(pSrcChunk->m_header.genEntities) {
796 const auto& rec = srcRecs[i];
797 if (rec.comp.size() == 0U)
800 auto* pSrc = (
void*)pSrcChunk->comp_ptr_mut(i);
801 auto* pDst = (
void*)comp_ptr_mut(i);
802 rec.pItem->ctor_move(pDst, pSrc, row, ec.row, capacity(), pSrcChunk->capacity());
812 GAIA_PROF_SCOPE(Chunk::copy_foreign_entity_data);
814 GAIA_ASSERT(pSrcChunk !=
nullptr);
815 GAIA_ASSERT(pDstChunk !=
nullptr);
816 GAIA_ASSERT(srcRow < pSrcChunk->size());
817 GAIA_ASSERT(dstRow < pDstChunk->size());
819 auto srcIds = pSrcChunk->ids_view();
820 auto dstIds = pDstChunk->ids_view();
821 auto dstRecs = pDstChunk->comp_rec_view();
831 const auto oldId = srcIds[i];
832 const auto newId = dstIds[j];
834 if (oldId == newId) {
835 const auto& rec = dstRecs[j];
836 if (rec.comp.size() != 0U) {
837 auto* pSrc = (
void*)pSrcChunk->comp_ptr_mut(i);
838 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(j);
839 rec.pItem->ctor_copy(pDst, pSrc, dstRow, srcRow, pDstChunk->
capacity(), pSrcChunk->
capacity());
848 const auto& rec = dstRecs[j];
849 if (rec.pItem !=
nullptr && rec.pItem->func_ctor !=
nullptr) {
850 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(j, dstRow);
851 rec.pItem->func_ctor(pDst, 1);
860 const auto& rec = dstRecs[j];
861 if (rec.pItem !=
nullptr && rec.pItem->func_ctor !=
nullptr) {
862 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(j, dstRow);
863 rec.pItem->func_ctor(pDst, 1);
875 GAIA_PROF_SCOPE(Chunk::move_foreign_entity_data);
877 GAIA_ASSERT(pSrcChunk !=
nullptr);
878 GAIA_ASSERT(pDstChunk !=
nullptr);
879 GAIA_ASSERT(srcRow < pSrcChunk->size());
880 GAIA_ASSERT(dstRow < pDstChunk->size());
882 auto srcIds = pSrcChunk->ids_view();
883 auto dstIds = pDstChunk->ids_view();
884 auto dstRecs = pDstChunk->comp_rec_view();
894 const auto oldId = srcIds[i];
895 const auto newId = dstIds[j];
897 if (oldId == newId) {
898 const auto& rec = dstRecs[j];
899 if (rec.comp.size() != 0U) {
900 auto* pSrc = (
void*)pSrcChunk->comp_ptr_mut(i);
901 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(j);
902 rec.pItem->ctor_move(pDst, pSrc, dstRow, srcRow, pDstChunk->
capacity(), pSrcChunk->
capacity());
911 const auto& rec = dstRecs[j];
912 if (rec.pItem !=
nullptr && rec.pItem->func_ctor !=
nullptr) {
913 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(j, dstRow);
914 rec.pItem->func_ctor(pDst, 1);
923 const auto& rec = dstRecs[j];
924 if (rec.pItem !=
nullptr && rec.pItem->func_ctor !=
nullptr) {
925 auto* pDst = (
void*)pDstChunk->comp_ptr_mut(j, dstRow);
926 rec.pItem->func_ctor(pDst, 1);
939 GAIA_PROF_SCOPE(Chunk::remove_entity_inter);
941 const uint16_t rowA = row;
942 const uint16_t rowB = m_header.
count - 1;
944 GAIA_ASSERT(rowA <= rowB);
947 if GAIA_LIKELY (rowA < rowB) {
948 GAIA_ASSERT(m_header.
count > 1);
950 auto ev = entity_view_mut();
953 const auto entityB = ev[rowB];
954 auto& ecB = recs[entityB];
955#if GAIA_ASSERT_ENABLED
956 const auto entityA = ev[rowA];
957 auto& ecA = recs[entityA];
959 GAIA_ASSERT(ecA.pArchetype == ecB.pArchetype);
960 GAIA_ASSERT(ecA.pChunk == ecB.pChunk);
966 auto recView = comp_rec_view();
968 const auto& rec = recView[i];
969 if (rec.comp.size() == 0U)
972 auto* pSrc = (
void*)comp_ptr_mut(i);
973 rec.pItem->move(pSrc, pSrc, rowA, rowB, capacity(), capacity());
975 pSrc = (
void*)comp_ptr_mut(i, rowB);
976 rec.pItem->dtor(pSrc);
983 auto recView = comp_rec_view();
985 const auto& rec = recView[i];
986 if (rec.comp.size() == 0U)
989 auto* pSrc = (
void*)comp_ptr_mut(i, rowA);
990 rec.pItem->dtor(pSrc);
1002 if GAIA_UNLIKELY (m_header.
count == 0)
1005 GAIA_PROF_SCOPE(Chunk::remove_entity);
1009 remove_entity_inter(row, recs);
1014 remove_last_entity();
1018 const uint16_t pivot = size_disabled() - 1;
1019 swap_chunk_entities(row, pivot, recs);
1021 remove_entity_inter(pivot, recs);
1024 remove_last_entity();
1037 if GAIA_UNLIKELY (m_header.
count <= 1 || rowA == rowB)
1040 GAIA_PROF_SCOPE(Chunk::swap_chunk_entities);
1043 auto ev = entity_view_mut();
1044 const auto entityA = ev[rowA];
1045 const auto entityB = ev[rowB];
1047 auto& ecA = recs[entityA];
1048 auto& ecB = recs[entityB];
1049 GAIA_ASSERT(ecA.pArchetype == ecB.pArchetype);
1050 GAIA_ASSERT(ecA.pChunk == ecB.pChunk);
1056 auto recView = comp_rec_view();
1058 const auto& rec = recView[i];
1059 if (rec.comp.size() == 0U)
1062 GAIA_ASSERT(rec.pData == comp_ptr_mut(i));
1063 rec.pItem->swap(rec.pData, rec.pData, rowA, rowB, capacity(), capacity());
1079 if GAIA_UNLIKELY (entityA == entityB)
1082 GAIA_PROF_SCOPE(Chunk::swap_chunk_entities);
1084 auto& ecA = fetch_mut(world, entityA);
1085 auto& ecB = fetch_mut(world, entityB);
1088 GAIA_ASSERT(ecA.pArchetype == ecB.pArchetype);
1089 GAIA_ASSERT(ecA.pArchetype == ecB.pArchetype);
1091 auto* pChunkA = ecA.pChunk;
1092 auto* pChunkB = ecB.pChunk;
1095 pChunkA->entity_view_mut()[ecA.row] = entityB;
1096 pChunkB->entity_view_mut()[ecB.row] = entityA;
1099 auto recViewA = pChunkA->comp_rec_view();
1100 GAIA_FOR(pChunkA->m_header.genEntities) {
1101 const auto& recA = recViewA[i];
1102 if (recA.comp.size() == 0U)
1105 auto* pDataA = pChunkA->comp_rec_view()[i].pData;
1106 auto* pDataB = pChunkB->comp_rec_view()[i].pData;
1113 pChunkA->capacity(), pChunkA->capacity()
1118 core::swap(ecA.row, ecB.row);
1119 core::swap(ecA.pChunk, ecB.pChunk);
1127 GAIA_ASSERT(row < m_header.
count &&
"Entity chunk row out of bounds!");
1131 if (!m_header.has_disabled_entities())
1137 const auto entity = entity_view()[row];
1139 recs[entity].data.dis = 0;
1143 if (!m_header.has_enabled_entities())
1149 const auto entity = entity_view()[row];
1151 recs[entity].data.dis = 1;
1160 GAIA_ASSERT(m_header.
count > 0);
1169 return m_data[offset];
1175 const uint8_t&
data(uint32_t offset)
const {
1176 return m_data[offset];
1187 GAIA_PROF_SCOPE(Chunk::call_ctor);
1189 const auto compIdx = comp_idx(item.
entity);
1190 auto* pSrc = (
void*)comp_ptr_mut(compIdx, entIdx);
1194 void call_gen_ctors(uint32_t entIdx, uint32_t entCnt) {
1198 GAIA_PROF_SCOPE(Chunk::call_gen_ctors);
1200 auto recs = comp_rec_view();
1202 const auto& rec = recs[i];
1204 const auto* pItem = rec.pItem;
1205 if (pItem ==
nullptr || pItem->func_ctor ==
nullptr)
1208 auto* pSrc = (
void*)comp_ptr_mut(i, entIdx);
1209 pItem->func_ctor(pSrc, entCnt);
1213 void call_all_dtors() {
1217 GAIA_PROF_SCOPE(Chunk::call_all_dtors);
1219 auto ids = ids_view();
1220 auto recs = comp_rec_view();
1221 const auto recs_cnt = recs.size();
1222 GAIA_FOR(recs_cnt) {
1223 const auto& rec = recs[i];
1225 const auto* pItem = rec.pItem;
1226 if (pItem ==
nullptr || pItem->func_dtor ==
nullptr)
1229 auto* pSrc = (
void*)comp_ptr_mut(i, 0);
1230 const auto e = ids[i];
1231 const auto cnt = (e.kind() == EntityKind::EK_Gen) ? m_header.
count : (uint16_t)1;
1232 pItem->func_dtor(pSrc, cnt);
1244 auto ids = ids_view();
1245 return core::has(ids, entity);
1251 template <
typename T>
1252 GAIA_NODISCARD
bool has()
const {
1254 const auto rel = m_header.
cc->
get<
typename T::rel>().entity;
1255 const auto tgt = m_header.
cc->
get<
typename T::tgt>().entity;
1258 const auto* pComp = m_header.
cc->
find<T>();
1259 return pComp !=
nullptr && has(pComp->entity);
1271 template <
typename T>
1272 decltype(
auto)
set(uint16_t row) {
1276 actual_type_t<T>::Kind == EntityKind::EK_Gen || row == 0,
1277 "Set providing a row can only be used with generic components");
1282 GAIA_ASSERT(row < m_header.
capacity);
1283 return view_mut<T>()[row];
1290 template <
typename T>
1295 type.kind() == EntityKind::EK_Gen || row == 0,
1296 "Set providing a row can only be used with generic components");
1297 GAIA_ASSERT(type.kind() == entity_kind_v<T>);
1302 GAIA_ASSERT(row < m_header.
capacity);
1311 return view_mut<T>()[row];
1319 template <
typename T>
1320 decltype(
auto)
sset(uint16_t row) {
1322 actual_type_t<T>::Kind == EntityKind::EK_Gen || row == 0,
1323 "Set providing a row can only be used with generic components");
1325 GAIA_ASSERT(row < m_header.
capacity);
1326 return sview_mut<T>()[row];
1335 template <
typename T>
1337 static_assert(core::is_raw_v<T>);
1340 type.kind() == EntityKind::EK_Gen || row == 0,
1341 "Set providing a row can only be used with generic components");
1343 GAIA_ASSERT(row < m_header.
capacity);
1352 return sview_mut<T>()[row];
1365 template <
typename T>
1366 GAIA_NODISCARD
decltype(
auto)
get(uint16_t row)
const {
1368 entity_kind_v<T> == EntityKind::EK_Gen,
"Get providing a row can only be used with generic components");
1370 return comp_inter<T>(row);
1377 template <
typename T>
1378 GAIA_NODISCARD
decltype(
auto)
get()
const {
1380 entity_kind_v<T> != EntityKind::EK_Gen,
1381 "Get not providing a row can only be used with non-generic components");
1383 return comp_inter<T>(0);
1390 return ecs::comp_idx<ChunkHeader::MAX_COMPONENTS>(m_records.
pCompEntities, entity);
1398 return ecs::comp_idx({m_records.
pCompEntities + offset, m_header.
count - offset}, entity);
1405 m_header.
index = value;
1409 GAIA_NODISCARD uint32_t
idx()
const {
1410 return m_header.
index;
1415 return m_header.has_enabled_entities();
1420 return m_header.has_disabled_entities();
1435 return m_header.
dead == 1;
1440 GAIA_ASSERT(!dead());
1446 GAIA_ASSERT(!dead());
1453 GAIA_ASSERT(dying());
1466 constexpr float Threshold = 0.75f;
1467 return ((
float)m_header.
count / (
float)m_header.
capacity) < Threshold;
1471 GAIA_NODISCARD uint16_t
size()
const {
1472 return m_header.
count;
1477 return m_header.
count == 0;
1503 GAIA_NODISCARD
bool changed(uint32_t requiredVersion)
const {
1504 const auto* versions = m_records.
pVersions;
1505 const auto changeVersion = versions[0];
1506 return ::gaia::ecs::version_changed(changeVersion, requiredVersion);
1510 GAIA_NODISCARD
bool changed(uint32_t requiredVersion, uint32_t compIdx)
const {
1511 const auto* versions = m_records.
pVersions;
1513 const auto changeVersion = versions[compIdx + 1];
1514 return ::gaia::ecs::version_changed(changeVersion, requiredVersion);
1519 auto versions = comp_version_view_mut();
1546 " Chunk #%04u, entities:%u/%u, lifespanCountdown:%u", m_header.
index, m_header.
count, m_header.
capacity,
Array of elements of type.
Definition sarray_ext_impl.h:27
Definition span_impl.h:99
GAIA_NODISCARD decltype(auto) sview_auto(uint16_t from, uint16_t to)
Returns either a mutable or immutable entity/component view based on the requested type....
Definition chunk.h:692
GAIA_NODISCARD uint16_t capacity() const
Returns the number of entities in the chunk.
Definition chunk.h:1491
static void free(Chunk *pChunk)
Releases all memory allocated by pChunk.
Definition chunk.h:401
const uint8_t & data(uint32_t offset) const
Returns an immutable pointer to chunk data.
Definition chunk.h:1175
decltype(auto) sset(uint16_t row, Entity type)
Sets the value of a generic entity type at the position row in the chunk.
Definition chunk.h:1336
void remove_entity(uint16_t row, EntityContainers &recs)
Tries to remove the entity at row row. Removal is done via swapping with last entity in chunk....
Definition chunk.h:1001
GAIA_FORCEINLINE void update_world_version()
Update the version of all components.
Definition chunk.h:1527
GAIA_NODISCARD uint32_t comp_idx(Entity entity, uint32_t offset) const
Returns the internal index of a component based on the provided entity.
Definition chunk.h:1397
bool progress_death()
Updates internal lifespan.
Definition chunk.h:1452
decltype(auto) set(uint16_t row)
Sets the value of the unique component T on row in the chunk.
Definition chunk.h:1272
GAIA_NODISCARD GAIA_FORCEINLINE auto comp_ptr_mut_gen(uint32_t compIdx, uint32_t row)
Returns a read-write span of the component data. Also updates the world version for the component.
Definition chunk.h:297
void die()
Marks the chunk as dead (ready to delete)
Definition chunk.h:1429
GAIA_NODISCARD uint32_t idx() const
Returns the index of this chunk in its archetype's storage.
Definition chunk.h:1409
uint8_t & data(uint32_t offset)
Returns a mutable pointer to chunk data.
Definition chunk.h:1168
void update_versions()
Updates the version numbers for this chunk.
Definition chunk.h:507
GAIA_FORCEINLINE void update_world_version(uint32_t compIdx)
Update the version of a component at the index.
Definition chunk.h:1518
GAIA_NODISCARD bool has_disabled_entities() const
Checks is this chunk has any disabled entities.
Definition chunk.h:1419
GAIA_NODISCARD bool full() const
Checks is the full capacity of the has has been reached.
Definition chunk.h:1459
GAIA_NODISCARD bool is_semi() const
Checks is the chunk is semi-full.
Definition chunk.h:1464
GAIA_NODISCARD decltype(auto) view(uint16_t from, uint16_t to) const
Returns a read-only entity or component view.
Definition chunk.h:519
GAIA_NODISCARD uint16_t add_entity(Entity entity)
Make.
Definition chunk.h:739
GAIA_NODISCARD uint16_t size_enabled() const
Return the number of entities in the chunk which are enabled.
Definition chunk.h:1481
GAIA_NODISCARD decltype(auto) view_auto(uint16_t from, uint16_t to)
Returns either a mutable or immutable entity/component view based on the requested type....
Definition chunk.h:670
void start_dying()
Starts the process of dying (not yet ready to delete, can be revived)
Definition chunk.h:1439
GAIA_NODISCARD bool has() const
Checks if component T is present in the chunk.
Definition chunk.h:1252
GAIA_NODISCARD uint16_t size() const
Returns the total number of entities in the chunk (both enabled and disabled)
Definition chunk.h:1471
GAIA_NODISCARD decltype(auto) get(uint16_t row) const
Returns the value stored in the generic component T on row in the chunk.
Definition chunk.h:1366
static uintptr_t chunk_data_area_offset()
Returns the relative offset of m_data in Chunk.
Definition chunk.h:359
void move_entity_data(Entity entity, uint16_t row, EntityContainers &recs)
Moves all data associated with entity into the chunk so that it is stored at the row row.
Definition chunk.h:786
void set_idx(uint32_t value)
Sets the index of this chunk in its archetype's storage.
Definition chunk.h:1404
GAIA_NODISCARD decltype(auto) get() const
Returns the value stored in the unique component T.
Definition chunk.h:1378
GAIA_NODISCARD bool changed(uint32_t requiredVersion, uint32_t compIdx) const
Returns true if the provided version is newer than the one stored internally.
Definition chunk.h:1510
static void copy_entity_data(Entity srcEntity, Entity dstEntity, EntityContainers &recs)
Copies all data associated with srcEntity into dstEntity.
Definition chunk.h:755
bool enabled(uint16_t row) const
Checks if the entity is enabled.
Definition chunk.h:1159
GAIA_NODISCARD bool dying() const
Checks is this chunk is dying.
Definition chunk.h:1424
GAIA_NODISCARD bool changed(uint32_t requiredVersion) const
Returns true if the provided version is newer than the one stored internally. Use when checking if th...
Definition chunk.h:1503
void remove_last_entity()
Remove the last entity from a chunk. If as a result the chunk becomes empty it is scheduled for delet...
Definition chunk.h:494
GAIA_NODISCARD uint16_t size_disabled() const
Return the number of entities in the chunk which are enabled.
Definition chunk.h:1486
void swap_chunk_entities(uint16_t rowA, uint16_t rowB, EntityContainers &recs)
Tries to swap the entity at row rowA with the one at the row rowB. When swapping, all data associated...
Definition chunk.h:1035
static void move_foreign_entity_data(Chunk *pSrcChunk, uint32_t srcRow, Chunk *pDstChunk, uint32_t dstRow)
Moves all data associated with entity into the chunk so that it is stored at the row row.
Definition chunk.h:874
void enable_entity(uint16_t row, bool enableEntity, EntityContainers &recs)
Enables or disables the entity on a given row in the chunk.
Definition chunk.h:1126
GAIA_NODISCARD uint32_t comp_idx(Entity entity) const
Returns the internal index of a component based on the provided entity.
Definition chunk.h:1389
static void swap_chunk_entities(World &world, Entity entityA, Entity entityB)
Tries to swap entityA with entityB. When swapping, all data associated with the two entities is swapp...
Definition chunk.h:1077
GAIA_FORCEINLINE void update_world_version_init()
Update the version of all components on chunk init.
Definition chunk.h:1537
GAIA_NODISCARD bool dead() const
Checks is this chunk is dead (ready to delete)
Definition chunk.h:1434
decltype(auto) set(uint16_t row, Entity type)
Sets the value of a generic entity type at the position row in the chunk.
Definition chunk.h:1291
GAIA_NODISCARD bool has_enabled_entities() const
Checks is this chunk has any enabled entities.
Definition chunk.h:1414
void revive()
Makes a dying chunk alive again.
Definition chunk.h:1445
GAIA_NODISCARD bool has(Entity entity) const
Checks if a component/entity entity is present in the chunk.
Definition chunk.h:1243
GAIA_NODISCARD bool empty() const
Checks is there are any entities in the chunk.
Definition chunk.h:1476
static void copy_foreign_entity_data(Chunk *pSrcChunk, uint32_t srcRow, Chunk *pDstChunk, uint32_t dstRow)
Copies all data associated with entity into the chunk so that it is stored at the row row.
Definition chunk.h:811
void remove_entity_inter(uint16_t row, EntityContainers &recs)
Tries to remove the entity at row. Removal is done via swapping with last entity in chunk....
Definition chunk.h:938
static Chunk * create(const World &wld, const ComponentCache &cc, uint32_t chunkIndex, uint16_t capacity, uint8_t cntEntities, uint8_t genEntities, uint16_t dataBytes, uint32_t &worldVersion, const ChunkDataOffsets &offsets, const Entity *ids, const Component *comps, const ChunkDataOffset *compOffs)
Allocates memory for a new chunk.
Definition chunk.h:370
GAIA_NODISCARD decltype(auto) view_mut(uint16_t from, uint16_t to)
Returns a mutable entity or component view.
Definition chunk.h:547
GAIA_NODISCARD decltype(auto) sview_mut(uint16_t from, uint16_t to)
Returns a mutable component view. Doesn't update the world version when the access is acquired.
Definition chunk.h:579
GAIA_NODISCARD uint8_t size_generic() const
Returns the total number of generic entities/components in the chunk.
Definition chunk.h:1496
decltype(auto) sset(uint16_t row)
Sets the value of the unique component T on row in the chunk.
Definition chunk.h:1320
GAIA_FORCEINLINE void modify()
Marks the component.
Definition chunk.h:613
Cache for compile-time defined components.
Definition component_cache.h:23
GAIA_NODISCARD const ComponentCacheItem * find(detail::ComponentDescId compDescId) const noexcept
Searches for the component cache item given the compDescId.
Definition component_cache.h:138
GAIA_NODISCARD const ComponentCacheItem & get(detail::ComponentDescId compDescId) const noexcept
Returns the component cache item given the compDescId.
Definition component_cache.h:156
Wrapper for two Entities forming a relationship pair.
Definition id.h:395
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition chunk_header.h:19
ChunkDataVersionOffset firstByte_Versions
Byte at which the first version number is located.
Definition chunk_header.h:21
ChunkDataOffset firstByte_EntityData
Byte at which the first entity is located.
Definition chunk_header.h:27
ChunkDataOffset firstByte_Records
Byte at which the first component id is located.
Definition chunk_header.h:25
ChunkDataOffset firstByte_CompEntities
Byte at which the first entity id is located.
Definition chunk_header.h:23
Definition chunk_header.h:39
ComponentRecord * pRecords
Pointer to the array of component records.
Definition chunk_header.h:45
Entity * pCompEntities
Pointer to where (component) entities are stored.
Definition chunk_header.h:43
Entity * pEntities
Pointer to the array of entities.
Definition chunk_header.h:47
ComponentVersion * pVersions
Pointer to where component versions are stored.
Definition chunk_header.h:41
Definition component_cache_item.h:24
Entity entity
Component entity.
Definition component_cache_item.h:45
FuncCtor * func_ctor
Function to call when the component needs to be constructed.
Definition component_cache_item.h:56
Definition chunk_header.h:30
uint8_t * pData
Pointer to where the first instance of the component is stored.
Definition chunk_header.h:34
Definition entity_container.h:151
Definition data_layout_policy.h:90
Definition data_layout_policy.h:92