diff --git a/include/UECS/ChunkView.h b/include/UECS/ChunkView.h index cc662e8..2d9952e 100644 --- a/include/UECS/ChunkView.h +++ b/include/UECS/ChunkView.h @@ -13,7 +13,7 @@ namespace Ubpa::UECS { bool Contains(CmptType) const; - // if not contain, return nullptr + // nullptr if not contain void* GetCmptArray(CmptType) const; template Cmpt* GetCmptArray() const { return reinterpret_cast(GetCmptArray(CmptType::Of)); } diff --git a/include/UECS/EntityMngr.h b/include/UECS/EntityMngr.h index b73d1fe..4bb3f0d 100644 --- a/include/UECS/EntityMngr.h +++ b/include/UECS/EntityMngr.h @@ -19,9 +19,10 @@ namespace Ubpa::UECS { // [API] // - Entity: Create, Instantiate, Destroy, Exist // - Component: Attach, Emplace, Detach, Have, Get, Components + // - Singleton: IsSingleton, GetSingletonEntity, GetSingleton // - other: EntityNum, AddCommand // [important] - // - API with CmptType need RTDCmptTraits to get {size|alignment|lifecycle function} (throw std::logic_error) + // - some API with CmptType need RTDCmptTraits to get {size|alignment|lifecycle function} (throw std::logic_error) // - API with Entity require Entity exist (throw std::invalid_argument) class EntityMngr { public: @@ -50,8 +51,10 @@ namespace Ubpa::UECS { bool Have(Entity, CmptType) const; + // nullptr if not singleton template Cmpt* Get(Entity) const; + // nullptr if not singleton CmptPtr Get(Entity, CmptType) const; std::vector Components(Entity) const; @@ -66,13 +69,10 @@ namespace Ubpa::UECS { bool IsSingleton(CmptType) const; Entity GetSingletonEntity(CmptType) const; - CmptPtr GetSingleton(CmptType) const; // nullptr if not singleton - CmptPtr GetIfSingleton(CmptType) const; + CmptPtr GetSingleton(CmptType) const; template Cmpt* GetSingleton() const { return GetSingleton(CmptType::Of).As(); } - template - Cmpt* GetIfSingleton() const { return GetIfSingleton(CmptType::Of).As(); } void Accept(IListener* listener) const; @@ -89,9 +89,10 @@ namespace Ubpa::UECS { // types not contain Entity Archetype* GetOrCreateArchetypeOf(const CmptType* types, size_t num); + // return original archetype template - void AttachWithoutInit(Entity); - void AttachWithoutInit(Entity, const CmptType* types, size_t num); + Archetype* AttachWithoutInit(Entity); + Archetype* AttachWithoutInit(Entity, const CmptType* types, size_t num); const std::set& QueryArchetypes(const EntityQuery& query) const; mutable std::unordered_map> queryCache; diff --git a/include/UECS/RTDCmptTraits.h b/include/UECS/RTDCmptTraits.h index 6899af5..9d857a6 100644 --- a/include/UECS/RTDCmptTraits.h +++ b/include/UECS/RTDCmptTraits.h @@ -50,6 +50,7 @@ namespace Ubpa::UECS { size_t Sizeof(CmptType) const; size_t Alignof(CmptType) const; + void DefaultConstruct(CmptType, void* cmpt) const; void CopyConstruct(CmptType, void* dst, void* src) const; void MoveConstruct(CmptType, void* dst, void* src) const; void MoveAssign(CmptType, void* dst, void* src) const; diff --git a/include/UECS/detail/Archetype.h b/include/UECS/detail/Archetype.h index 15033f5..db1cd0d 100644 --- a/include/UECS/detail/Archetype.h +++ b/include/UECS/detail/Archetype.h @@ -42,12 +42,15 @@ namespace Ubpa::UECS { std::tuple, std::vector>, std::vector> Locate(const CmptLocator& locator) const; + // nullptr if not contains void* Locate(size_t chunkIdx, CmptType) const; Chunk* GetChunk(size_t chunkIdx) const { return chunks[chunkIdx]; } + // nullptr if not contains void* At(CmptType, size_t idx) const; + // nullptr if not contains template Cmpt* At(size_t idx) const{ return reinterpret_cast(At(CmptType::Of, idx)); } @@ -78,9 +81,6 @@ namespace Ubpa::UECS { const CmptTypeSet& GetCmptTypeSet() const noexcept { return types; } const RTSCmptTraits& GetRTSCmptTraits() const noexcept { return cmptTraits; } - // no Entity - size_t CmptNum() const noexcept { return types.data.size() - 1; } - size_t EntityNum() const noexcept { return entityNum; } size_t EntityNumOfChunk(size_t chunkIdx) const noexcept; size_t ChunkNum() const noexcept { return chunks.size(); } diff --git a/include/UECS/detail/Archetype.inl b/include/UECS/detail/Archetype.inl index ed721aa..b39deb5 100644 --- a/include/UECS/detail/Archetype.inl +++ b/include/UECS/detail/Archetype.inl @@ -10,7 +10,7 @@ namespace Ubpa::UECS { types(GenCmptTypeSet()) { static_assert(IsSet_v>, - "Archetype::Archetype: ... must be different"); + "... must be different"); cmptTraits.Register(); (cmptTraits.Register(), ...); SetLayout(); @@ -19,12 +19,14 @@ namespace Ubpa::UECS { template Archetype* Archetype::Add(const Archetype* from) { static_assert(sizeof...(Cmpts) > 0); - assert(((!from->types.Contains(CmptType::Of)) &&...)); + static_assert(IsSet_v>, + "... must be different"); + assert(!from->types.Contains(std::array{ CmptType::Of... })); Archetype* rst = new Archetype{ from->entityMngr }; rst->types = from->types; - rst->types.data.insert(CmptType::Of...); + (rst->types.data.insert(CmptType::Of), ...); rst->cmptTraits = from->cmptTraits; (rst->cmptTraits.Register(), ...); @@ -35,11 +37,12 @@ namespace Ubpa::UECS { template std::tuple> Archetype::Create(Entity e) { - assert((types.Contains(CmptType::Of) &&...) && types.data.size() == 1 + sizeof...(Cmpts)); static_assert((std::is_constructible_v &&...), - "Archetype::Create: isn't constructible"); + " isn't constructible"); static_assert(IsSet_v>, - "Archetype::Create: ... must be different"); + "... must be different"); + + assert((types.Contains(CmptType::Of) &&...) && types.data.size() == 1 + sizeof...(Cmpts)); size_t idx = RequestBuffer(); size_t idxInChunk = idx % chunkCapacity; @@ -47,18 +50,21 @@ namespace Ubpa::UECS { new(buffer + Offsetof(CmptType::Of) + idxInChunk * sizeof(Entity))Entity(e); - std::tuple cmpts = { new(buffer + Offsetof(CmptType::Of) + idxInChunk * sizeof(Cmpts))Cmpts... }; + std::tuple cmpts = { new(buffer + Offsetof(CmptType::Of) + idxInChunk * sizeof(Cmpts))Cmpts... }; return { idx,cmpts }; } template CmptTypeSet Archetype::GenCmptTypeSet() { - if constexpr(sizeof...(Cmpts) == 0) - return Archetype::GenCmptTypeSet(nullptr, 0); - else { + if constexpr (sizeof...(Cmpts) > 0) { + static_assert(IsSet_v>, + "... must be different"); + constexpr std::array types = { CmptType::Of... }; return Archetype::GenCmptTypeSet(types.data(), types.size()); } + else + return Archetype::GenCmptTypeSet(nullptr, 0); } } diff --git a/include/UECS/detail/CmptsLocator.inl b/include/UECS/detail/CmptsLocator.inl index 5ab749f..1e42178 100644 --- a/include/UECS/detail/CmptsLocator.inl +++ b/include/UECS/detail/CmptsLocator.inl @@ -7,7 +7,7 @@ namespace Ubpa::UECS::detail { template CmptLocator GenerateCmptLocator(TypeList) { if constexpr (sizeof...(Cmpts) > 0) { - constexpr std::array types{ CmptType::Of... }; + constexpr std::array types{ CmptType::Of... }; return CmptLocator{ types.data(), types.size() }; } else diff --git a/include/UECS/detail/EntityMngr.inl b/include/UECS/detail/EntityMngr.inl index f447727..4f7d5e4 100644 --- a/include/UECS/detail/EntityMngr.inl +++ b/include/UECS/detail/EntityMngr.inl @@ -8,9 +8,6 @@ namespace Ubpa::UECS { template Archetype* EntityMngr::GetOrCreateArchetypeOf() { - static_assert(IsSet_v>, - "EntityMngr::GetOrCreateArchetypeOf: ... must be different"); - const auto typeset = Archetype::GenCmptTypeSet(); auto target = ts2a.find(typeset); if(target != ts2a.end()) @@ -28,8 +25,6 @@ namespace Ubpa::UECS { template std::tuple EntityMngr::Create() { - static_assert(IsSet_v>, - "EntityMngr::Create: ... must be different"); Archetype* archetype = GetOrCreateArchetypeOf(); size_t entityIndex = RequestEntityFreeEntry(); EntityInfo& info = entityTable[entityIndex]; @@ -41,18 +36,15 @@ namespace Ubpa::UECS { } template - void EntityMngr::AttachWithoutInit(Entity e) { - static_assert(IsSet_v>, - "EntityMngr::AttachWithoutInit: ... must be different"); + Archetype* EntityMngr::AttachWithoutInit(Entity e) { if (!Exist(e)) throw std::invalid_argument("Entity is invalid"); auto& info = entityTable[e.Idx()]; Archetype* srcArchetype = info.archetype; - size_t srcIdxInArchetype = info.idxInArchetype; const auto& srcCmptTypeSet = srcArchetype->GetCmptTypeSet(); auto dstCmptTypeSet = srcCmptTypeSet; - dstCmptTypeSet.data.insert(CmptType::Of...); + (dstCmptTypeSet.data.insert(CmptType::Of), ...); // get dstArchetype Archetype* dstArchetype; @@ -66,13 +58,14 @@ namespace Ubpa::UECS { } ts2a.emplace(std::move(dstCmptTypeSet), std::unique_ptr{ dstArchetype }); } - else + else { dstArchetype = target->second.get(); - - if (dstArchetype == srcArchetype) - return; + if (dstArchetype == srcArchetype) + return srcArchetype; + } // move src to dst + size_t srcIdxInArchetype = info.idxInArchetype; size_t dstIdxInArchetype = dstArchetype->RequestBuffer(); auto srcCmptTraits = srcArchetype->GetRTSCmptTraits(); @@ -89,17 +82,16 @@ namespace Ubpa::UECS { info.archetype = dstArchetype; info.idxInArchetype = dstIdxInArchetype; + + return srcArchetype; } template std::tuple EntityMngr::Attach(Entity e) { - static_assert((std::is_default_constructible_v &&...), - "EntityMngr::Attach: isn't default constructible"); - using CmptList = TypeList; - const auto& cmptTypes = entityTable[e.Idx()].archetype->GetCmptTypeSet(); + auto origArchetype = AttachWithoutInit(e); + const auto& cmptTypes = origArchetype->GetCmptTypeSet(); std::array needAttach = { !cmptTypes.Contains(CmptType::Of)... }; - AttachWithoutInit(e); const auto& new_info = entityTable[e.Idx()]; std::tuple cmpts{ new_info.archetype->At(new_info.idxInArchetype)... }; ((std::get>(needAttach) ? new(std::get(cmpts))Cmpts : nullptr), ...); @@ -111,7 +103,7 @@ namespace Ubpa::UECS { Cmpt* EntityMngr::Emplace(Entity e, Args&&... args) { static_assert(std::is_constructible_v || is_list_initializable_v, - "EntityMngr::Emplace: isn't constructible/list_initializable with Args..."); + " isn't constructible/list_initializable with Args..."); if (!Have(e, CmptType::Of)) { AttachWithoutInit(e); diff --git a/include/UECS/detail/RTDCmptTraits.inl b/include/UECS/detail/RTDCmptTraits.inl index 7297611..806e862 100644 --- a/include/UECS/detail/RTDCmptTraits.inl +++ b/include/UECS/detail/RTDCmptTraits.inl @@ -58,6 +58,13 @@ namespace Ubpa::UECS { return alignments.find(type)->second; } + inline void RTDCmptTraits::DefaultConstruct(CmptType type, void* cmpt) const { + auto target = default_constructors.find(type); + + if (target != default_constructors.end()) + target->second(cmpt); + } + inline void RTDCmptTraits::CopyConstruct(CmptType type, void* dst, void* src) const { auto target = copy_constructors.find(type); diff --git a/include/UECS/detail/SingletonLocator.inl b/include/UECS/detail/SingletonLocator.inl index df6f9e7..129426d 100644 --- a/include/UECS/detail/SingletonLocator.inl +++ b/include/UECS/detail/SingletonLocator.inl @@ -7,7 +7,7 @@ namespace Ubpa::UECS::detail { template SingletonLocator GenerateSingletonLocator(TypeList) { if constexpr (sizeof...(Singletons) > 0) { - constexpr std::array types{ CmptType::Of... }; + constexpr std::array types{ CmptType::Of... }; return SingletonLocator{ types.data(), types.size() }; } else diff --git a/src/core/Archetype.cpp b/src/core/Archetype.cpp index a6a5d42..b1997d2 100644 --- a/src/core/Archetype.cpp +++ b/src/core/Archetype.cpp @@ -58,7 +58,7 @@ Archetype* Archetype::New(EntityMngr* entityMngr, const CmptType* types, size_t Archetype* Archetype::Add(const Archetype* from, const CmptType* types, size_t num) { assert(NotContainEntity(types, num)); - assert(!from->types.ContainsAny(types, num)); + assert(!from->types.Contains(types, num)); Archetype* rst = new Archetype{ from->entityMngr }; @@ -126,7 +126,9 @@ size_t Archetype::RequestBuffer() { void* Archetype::At(CmptType type, size_t idx) const { assert(idx < entityNum); - assert(types.Contains(type)); + + if (!types.Contains(type)) + return nullptr; size_t size = cmptTraits.Sizeof(type); size_t offset = Offsetof(type); @@ -192,8 +194,10 @@ tuple, vector>, vector> Archetype::Locat } void* Archetype::Locate(size_t chunkIdx, CmptType t) const { - assert(types.Contains(t)); assert(chunkIdx < chunks.size()); + if (!types.Contains(t)) + return nullptr; + auto buffer = chunks[chunkIdx]->Data(); return buffer + Offsetof(t); } diff --git a/src/core/ChunkView.cpp b/src/core/ChunkView.cpp index d73f919..4d2e757 100644 --- a/src/core/ChunkView.cpp +++ b/src/core/ChunkView.cpp @@ -5,7 +5,7 @@ using namespace Ubpa::UECS; void* ChunkView::GetCmptArray(CmptType t) const { - return Contains(t) ? archetype->Locate(chunkIdx, t) : nullptr; + return archetype->Locate(chunkIdx, t); } size_t ChunkView::EntityNum() const noexcept { diff --git a/src/core/EntityMngr.cpp b/src/core/EntityMngr.cpp index 30a9831..ce29dbd 100644 --- a/src/core/EntityMngr.cpp +++ b/src/core/EntityMngr.cpp @@ -55,7 +55,7 @@ Entity EntityMngr::Create(const CmptType* types, size_t num) { return e; } -void EntityMngr::AttachWithoutInit(Entity e, const CmptType* types, size_t num) { +Archetype* EntityMngr::AttachWithoutInit(Entity e, const CmptType* types, size_t num) { assert(types != nullptr && num > 0); assert(IsSet(types, num)); if (!Exist(e)) throw std::invalid_argument("Entity is invalid"); @@ -80,11 +80,11 @@ void EntityMngr::AttachWithoutInit(Entity e, const CmptType* types, size_t num) } ts2a.emplace(std::move(dstCmptTypeSet), std::unique_ptr{dstArchetype}); } - else + else { dstArchetype = target->second.get(); - - if (dstArchetype == srcArchetype) - return; + if (dstArchetype == srcArchetype) + return srcArchetype; + } // move src to dst size_t dstIdxInArchetype = dstArchetype->RequestBuffer(); @@ -103,22 +103,24 @@ void EntityMngr::AttachWithoutInit(Entity e, const CmptType* types, size_t num) info.archetype = dstArchetype; info.idxInArchetype = dstIdxInArchetype; + + return srcArchetype; } void EntityMngr::Attach(Entity e, const CmptType* types, size_t num) { - auto srcArchetype = entityTable[e.Idx()].archetype; - AttachWithoutInit(e, types, num); - const auto& new_info = entityTable[e.Idx()]; + auto origArchetype = AttachWithoutInit(e, types, num); + const auto& info = entityTable[e.Idx()]; const auto& rtdct = RTDCmptTraits::Instance(); for (size_t i = 0; i < num; i++) { const auto& type = types[i]; - if (srcArchetype->GetCmptTypeSet().Contains(type)) + if (origArchetype->GetCmptTypeSet().Contains(type)) continue; + auto target = rtdct.default_constructors.find(type); if (target == rtdct.default_constructors.end()) continue; - target->second(new_info.archetype->At(type, new_info.idxInArchetype)); + target->second(info.archetype->At(type, info.idxInArchetype)); } } @@ -129,7 +131,6 @@ void EntityMngr::Detach(Entity e, const CmptType* types, size_t num) { auto& info = entityTable[e.Idx()]; Archetype* srcArchetype = info.archetype; - size_t srcIdxInArchetype = info.idxInArchetype; const auto& srcCmptTypeSet = srcArchetype->GetCmptTypeSet(); auto dstCmptTypeSet = srcCmptTypeSet; @@ -147,14 +148,16 @@ void EntityMngr::Detach(Entity e, const CmptType* types, size_t num) { } ts2a.emplace(std::move(dstCmptTypeSet), std::unique_ptr{dstArchetype}); } - else + else { dstArchetype = target->second.get(); - - if (dstArchetype == srcArchetype) - return; + if (dstArchetype == srcArchetype) + return; + } // move src to dst + size_t srcIdxInArchetype = info.idxInArchetype; size_t dstIdxInArchetype = dstArchetype->RequestBuffer(); + const auto& srcCmptTraits = srcArchetype->GetRTSCmptTraits(); for (const auto& type : srcCmptTypeSet.data) { auto srcCmpt = srcArchetype->At(type, srcIdxInArchetype); @@ -197,6 +200,8 @@ Entity EntityMngr::Instantiate(Entity srcEntity) { } bool EntityMngr::IsSet(const CmptType* types, size_t num) noexcept { + assert(types || num == 0); + for (size_t i = 0; i < num; i++) { for (size_t j = 0; j < i; j++) if (types[i] == types[j]) @@ -248,7 +253,7 @@ tuple> EntityMngr::LocateSingletons(const SingletonLocator vector rst; rst.reserve(locator.SingletonTypes().size()); for (const auto& t : locator.SingletonTypes()) { - auto ptr = GetIfSingleton(t); + auto ptr = GetSingleton(t); if (ptr.Ptr() == nullptr) return { false, {} }; rst.push_back(ptr); @@ -371,15 +376,6 @@ Entity EntityMngr::GetSingletonEntity(CmptType t) const { } CmptPtr EntityMngr::GetSingleton(CmptType t) const { - assert(IsSingleton(t)); - ArchetypeFilter filter{ {t}, {}, {} }; - EntityQuery query(move(filter)); - const auto& archetypes = QueryArchetypes(query); - auto archetype = *archetypes.begin(); - return { t, archetype->At(t, 0) }; -} - -CmptPtr EntityMngr::GetIfSingleton(CmptType t) const { ArchetypeFilter filter{ {t}, {}, {} }; EntityQuery query(move(filter)); const auto& archetypes = QueryArchetypes(query);