From ea14b334ef095490066e708f372a772310bdb6a8 Mon Sep 17 00:00:00 2001 From: Ubpa Date: Wed, 16 Sep 2020 14:00:01 +0800 Subject: [PATCH] let Archetype only store chunk pool (not EntityMngr) --- include/UECS/EntityMngr.h | 9 +++---- include/UECS/RTDCmptTraits.h | 2 +- include/UECS/detail/Archetype.h | 22 ++++++++-------- include/UECS/detail/Archetype.inl | 7 +++--- include/UECS/detail/EntityMngr.inl | 2 +- src/core/Archetype.cpp | 40 ++++++++++++++---------------- src/core/EntityMngr.cpp | 18 +++++++++----- 7 files changed, 51 insertions(+), 49 deletions(-) diff --git a/include/UECS/EntityMngr.h b/include/UECS/EntityMngr.h index b7ef721..78a0f97 100644 --- a/include/UECS/EntityMngr.h +++ b/include/UECS/EntityMngr.h @@ -5,10 +5,6 @@ #include "detail/Job.h" #include "EntityQuery.h" -#include - -#include - namespace Ubpa::UECS { class World; @@ -28,8 +24,9 @@ namespace Ubpa::UECS { // - when free entries is empty, use new entity entry (version is 0) class EntityMngr { public: - EntityMngr(World* world) : world{ world } {} + EntityMngr(World* world) : world{ world }, sharedChunkPool{ std::make_unique>() } {} EntityMngr(const EntityMngr& em); + ~EntityMngr(); // same world void Swap(EntityMngr& rhs) noexcept; @@ -94,7 +91,6 @@ namespace Ubpa::UECS { void Accept(IListener* listener) const; private: - Pool sharedChunkPool; // destruct finally World* world; friend class World; @@ -134,6 +130,7 @@ namespace Ubpa::UECS { size_t RequestEntityFreeEntry(); void RecycleEntityEntry(Entity); + std::unique_ptr> sharedChunkPool; std::unordered_map> ts2a; // archetype's CmptTypeSet to archetype }; } diff --git a/include/UECS/RTDCmptTraits.h b/include/UECS/RTDCmptTraits.h index 09288b3..1b1985a 100644 --- a/include/UECS/RTDCmptTraits.h +++ b/include/UECS/RTDCmptTraits.h @@ -6,7 +6,7 @@ #include namespace Ubpa::UECS { - // run-time dynamic component traits, singleton + // run-time dynamic component traits // size (> 0) is neccessary // optional // - alignment: alignof(std::max_align_t) as default, 8 / 16 in most cases diff --git a/include/UECS/detail/Archetype.h b/include/UECS/detail/Archetype.h index 607a18c..14bf596 100644 --- a/include/UECS/detail/Archetype.h +++ b/include/UECS/detail/Archetype.h @@ -8,6 +8,8 @@ #include "CmptTypeSet.h" #include "Chunk.h" +#include + #include #include @@ -20,23 +22,26 @@ namespace Ubpa::UECS { // type of Entity + Components is Archetype's type class Archetype { public: + Archetype(Pool* chunkPool) : chunkPool{ chunkPool } {} + // argument TypeList is for type deduction // auto add Entity template - Archetype(EntityMngr*, TypeList); + Archetype(Pool* chunkPool, TypeList); // copy - Archetype(EntityMngr*, const Archetype&); + Archetype(Pool* chunkPool, const Archetype&); + Archetype(const Archetype&) = delete; ~Archetype(); - // auto add Entity, use RTDCmptTraits - static Archetype* New(EntityMngr*, const CmptType* types, size_t num); + // auto add Entity + static Archetype* New(RTDCmptTraits&, Pool* chunkPool, const CmptType* types, size_t num); // auto add Entity template static Archetype* Add(const Archetype* from); - static Archetype* Add(const Archetype* from, const CmptType* types, size_t num); + static Archetype* Add(RTDCmptTraits&, const Archetype* from, const CmptType* types, size_t num); // auto add Entity static Archetype* Remove(const Archetype* from, const CmptType* types, size_t num); @@ -68,8 +73,7 @@ namespace Ubpa::UECS { template std::tuple> Create(Entity); - // use RTDCmptTraits's default constructor - size_t Create(Entity); + size_t Create(RTDCmptTraits&, Entity); // return index in archetype size_t Instantiate(Entity, size_t srcIdx); @@ -95,8 +99,6 @@ namespace Ubpa::UECS { static CmptTypeSet GenCmptTypeSet(); private: - Archetype(EntityMngr* entityMngr) : entityMngr{ entityMngr } {} - // set type2alignment // call after setting type2size and type2offset void SetLayout(); @@ -105,13 +107,13 @@ namespace Ubpa::UECS { static bool NotContainEntity(const CmptType* types, size_t num) noexcept; friend class EntityMngr; - EntityMngr* entityMngr; CmptTypeSet types; // Entity + Components RTSCmptTraits cmptTraits; std::unordered_map type2offset; // CmptType to offset in chunk (include Entity) size_t chunkCapacity{ size_t_invalid }; + Pool* chunkPool; std::vector chunks; size_t entityNum{ 0 }; // number of entities diff --git a/include/UECS/detail/Archetype.inl b/include/UECS/detail/Archetype.inl index c231a2d..59df937 100644 --- a/include/UECS/detail/Archetype.inl +++ b/include/UECS/detail/Archetype.inl @@ -4,9 +4,8 @@ namespace Ubpa::UECS { template - Archetype::Archetype(EntityMngr* entityMngr, TypeList) - : - entityMngr{ entityMngr }, + Archetype::Archetype(Pool* chunkPool, TypeList) + : chunkPool{ chunkPool }, types(GenCmptTypeSet()) { static_assert(IsSet_v>, @@ -23,7 +22,7 @@ namespace Ubpa::UECS { "... must be different"); assert(!(from->types.Contains(CmptType::Of) &&...)); - Archetype* rst = new Archetype{ from->entityMngr }; + Archetype* rst = new Archetype{ from->chunkPool }; rst->types = from->types; (rst->types.data.insert(CmptType::Of), ...); diff --git a/include/UECS/detail/EntityMngr.inl b/include/UECS/detail/EntityMngr.inl index 4b9a3ec..e8a08ee 100644 --- a/include/UECS/detail/EntityMngr.inl +++ b/include/UECS/detail/EntityMngr.inl @@ -13,7 +13,7 @@ namespace Ubpa::UECS { if(target != ts2a.end()) return target->second.get(); - auto archetype = new Archetype(this, TypeList{}); + auto archetype = new Archetype(sharedChunkPool.get(), TypeList{}); ts2a.emplace(std::move(typeset), std::unique_ptr{ archetype }); for (auto& [query, archetypes] : queryCache) { if (archetype->GetCmptTypeSet().IsMatch(query)) diff --git a/src/core/Archetype.cpp b/src/core/Archetype.cpp index f885950..e225a38 100644 --- a/src/core/Archetype.cpp +++ b/src/core/Archetype.cpp @@ -25,12 +25,13 @@ Archetype::~Archetype() { } } } - for (Chunk* chunk : chunks) - entityMngr->sharedChunkPool.Recycle(chunk); + // FastClear by EntityMngr + //for (Chunk* chunk : chunks) + // entityMngr->sharedChunkPool.Recycle(chunk); } -Archetype::Archetype(EntityMngr* em, const Archetype& src) - : entityMngr{ em } +Archetype::Archetype(Pool* pool, const Archetype& src) + : chunkPool{ pool } { types = src.types; cmptTraits = src.cmptTraits; @@ -41,7 +42,7 @@ Archetype::Archetype(EntityMngr* em, const Archetype& src) chunks.resize(src.chunks.size(), nullptr); for (size_t i = 0; i < src.chunks.size(); i++) { auto srcChunk = src.chunks[i]; - auto dstChunk = chunks[i] = entityMngr->sharedChunkPool.Request(); + auto dstChunk = chunks[i] = chunkPool->Request(); size_t num = src.EntityNumOfChunk(i); for (auto type : types.data) { auto offset = Offsetof(type); @@ -85,30 +86,30 @@ void Archetype::SetLayout() { type2offset.emplace(type, layout.offsets[i++]); } -Archetype* Archetype::New(EntityMngr* entityMngr, const CmptType* types, size_t num) { +Archetype* Archetype::New(RTDCmptTraits& rtdCmptTraits, Pool* chunkPool, const CmptType* types, size_t num) { assert(NotContainEntity(types, num)); - auto rst = new Archetype{ entityMngr }; + auto rst = new Archetype{ chunkPool }; rst->types.Insert(types, num); rst->types.data.insert(CmptType::Of); rst->cmptTraits.Register(); for (size_t i = 0; i < num; i++) - rst->cmptTraits.Register(entityMngr->world->cmptTraits, types[i]); + rst->cmptTraits.Register(rtdCmptTraits, types[i]); rst->SetLayout(); return rst; } -Archetype* Archetype::Add(const Archetype* from, const CmptType* types, size_t num) { +Archetype* Archetype::Add(RTDCmptTraits& rtdCmptTraits, const Archetype* from, const CmptType* types, size_t num) { assert(NotContainEntity(types, num)); assert(!from->types.ContainsAll(types, num)); - Archetype* rst = new Archetype{ from->entityMngr }; + Archetype* rst = new Archetype{ from->chunkPool }; rst->types = from->types; rst->cmptTraits = from->cmptTraits; rst->types.Insert(types, num); for (size_t i = 0; i < num; i++) - rst->cmptTraits.Register(rst->entityMngr->world->cmptTraits, types[i]); + rst->cmptTraits.Register(rtdCmptTraits, types[i]); rst->SetLayout(); @@ -119,7 +120,7 @@ Archetype* Archetype::Remove(const Archetype* from, const CmptType* types, size_ assert(NotContainEntity(types, num)); assert(from->types.ContainsAny(types, num)); - Archetype* rst = new Archetype{ from->entityMngr }; + Archetype* rst = new Archetype{ from->chunkPool }; rst->types = from->types; rst->cmptTraits = from->cmptTraits; @@ -132,12 +133,11 @@ Archetype* Archetype::Remove(const Archetype* from, const CmptType* types, size_ return rst; } -size_t Archetype::Create(Entity e) { +size_t Archetype::Create(RTDCmptTraits& rtdCmptTraits, Entity e) { size_t idx = RequestBuffer(); size_t idxInChunk = idx % chunkCapacity; byte* buffer = chunks[idx / chunkCapacity]->Data(); - const auto& rtdct = entityMngr->world->cmptTraits; for (const auto& type : types.data) { if (type.Is()) { constexpr size_t size = sizeof(Entity); @@ -145,8 +145,8 @@ size_t Archetype::Create(Entity e) { memcpy(buffer + offset + idxInChunk * size, &e, size); } else { - auto target = rtdct.GetDefaultConstructors().find(type); - if (target == rtdct.GetDefaultConstructors().end()) + auto target = rtdCmptTraits.GetDefaultConstructors().find(type); + if (target == rtdCmptTraits.GetDefaultConstructors().end()) continue; const auto& ctor = target->second; size_t size = cmptTraits.Sizeof(type); @@ -161,7 +161,7 @@ size_t Archetype::Create(Entity e) { size_t Archetype::RequestBuffer() { if (entityNum == chunks.size() * chunkCapacity) { - auto chunk = entityMngr->sharedChunkPool.Request(); + auto chunk = chunkPool->Request(); chunks.push_back(chunk); } return entityNum++; @@ -251,7 +251,7 @@ size_t Archetype::Erase(size_t idx) { size_t dstIdxInChunk = idx % chunkCapacity; byte* dstBuffer = chunks[idx / chunkCapacity]->Data(); - size_t movedIdx; + size_t movedIdx = size_t_invalid; if (idx != entityNum - 1) { size_t movedIdxInArchetype = entityNum - 1; @@ -273,8 +273,6 @@ size_t Archetype::Erase(size_t idx) { } } else { - movedIdx = size_t_invalid; - for (const auto& type : types.data) { size_t size = cmptTraits.Sizeof(type); size_t offset = Offsetof(type); @@ -287,7 +285,7 @@ size_t Archetype::Erase(size_t idx) { if (chunks.size() * chunkCapacity - entityNum >= chunkCapacity) { Chunk* chunk = chunks.back(); - entityMngr->sharedChunkPool.Recycle(chunk); + chunkPool->Recycle(chunk); chunks.pop_back(); } diff --git a/src/core/EntityMngr.cpp b/src/core/EntityMngr.cpp index 0e5bc7b..82badd0 100644 --- a/src/core/EntityMngr.cpp +++ b/src/core/EntityMngr.cpp @@ -19,11 +19,12 @@ size_t EntityMngr::RequestEntityFreeEntry() { } EntityMngr::EntityMngr(const EntityMngr& em) - : world{ em.world } + : world{ em.world }, + sharedChunkPool{ std::make_unique>() } { ts2a.reserve(em.ts2a.size()); for (const auto& [ts, a] : em.ts2a) { - auto [iter, success] = ts2a.try_emplace(ts, std::make_unique(this, *a)); + auto [iter, success] = ts2a.try_emplace(ts, std::make_unique(sharedChunkPool.get(), *a)); assert(success); } entityTableFreeEntry = em.entityTableFreeEntry; @@ -44,11 +45,16 @@ EntityMngr::EntityMngr(const EntityMngr& em) } } +EntityMngr::~EntityMngr() { + ts2a.clear(); + sharedChunkPool->FastClear(); +} + void EntityMngr::Swap(EntityMngr& rhs) noexcept { assert(world == rhs.world); using std::swap; - + swap(ts2a, rhs.ts2a); swap(entityTableFreeEntry, rhs.entityTableFreeEntry); swap(entityTable, rhs.entityTable); @@ -73,7 +79,7 @@ Archetype* EntityMngr::GetOrCreateArchetypeOf(const CmptType* types, size_t num) if (target != ts2a.end()) return target->second.get(); - auto archetype = Archetype::New(this, types, num); + auto archetype = Archetype::New(world->cmptTraits, sharedChunkPool.get(), types, num); ts2a.emplace(std::move(typeset), std::unique_ptr{ archetype }); for (auto& [query, archetypes] : queryCache) { @@ -90,7 +96,7 @@ Entity EntityMngr::Create(const CmptType* types, size_t num) { EntityInfo& info = entityTable[entityIndex]; Entity e{ entityIndex, info.version }; info.archetype = archetype; - info.idxInArchetype = archetype->Create(e); + info.idxInArchetype = archetype->Create(world->cmptTraits, e); return e; } @@ -111,7 +117,7 @@ Archetype* EntityMngr::AttachWithoutInit(Entity e, const CmptType* types, size_t Archetype* dstArchetype; auto target = ts2a.find(dstCmptTypeSet); if (target == ts2a.end()) { - dstArchetype = Archetype::Add(srcArchetype, types, num); + dstArchetype = Archetype::Add(world->cmptTraits, srcArchetype, types, num); assert(dstCmptTypeSet == dstArchetype->GetCmptTypeSet()); for (auto& [query, archetypes] : queryCache) { if (dstCmptTypeSet.IsMatch(query))