diff --git a/CMakeLists.txt b/CMakeLists.txt index 79c237d..379aa31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(UECS VERSION 0.10.3) +project(UECS VERSION 0.10.4) message(STATUS "[Project] ${PROJECT_NAME}") include(cmake/InitUCMake.cmake) diff --git a/README.md b/README.md index 6397f35..c7f5aba 100644 --- a/README.md +++ b/README.md @@ -71,11 +71,11 @@ int main() { - [chunk layout optimization with alignment](src/test/05_alignment/main.cpp) - [parrallel with `None` filter](src/test/06_none_parallel/main.cpp) - [system **overload**](src/test/07_overload/main.cpp) -- [runtime dynamic component and system](src/test/11_runtime_cmpt/main.cpp) +- [runtime dynamic component](src/test/11_runtime_cmpt/main.cpp) - [generate **frame graph** in **Graphviz**](src/test/12_framegraph/main.cpp) - [performance test](src/test/13_performance/main.cpp) - [serialize](src/test/14_serialize/main.cpp) -- [chunk job](src/test/15_chunk_job/main.cpp) +- [chunk job](src/test/15_chunk_job/main.cpp) ## Licensing diff --git a/doc/todo.md b/doc/todo.md index 943f432..2082d19 100644 --- a/doc/todo.md +++ b/doc/todo.md @@ -34,7 +34,7 @@ - [ ] batch create/instantiate (need benchmark) - [x] lock `FilterChange` - [ ] `EntityMngr` `Query`-driven API -- [x] `RTDCmptsView` = `const EntityLocator* locator + void** cmpts` +- [x] `CmptsView` = `const EntityLocator* locator + void** cmpts` - [ ] Filter Builder ### maybe deprecate diff --git a/include/UECS/CmptPtr.h b/include/UECS/CmptPtr.h index 13598ea..91ca7d9 100644 --- a/include/UECS/CmptPtr.h +++ b/include/UECS/CmptPtr.h @@ -13,37 +13,33 @@ namespace Ubpa::UECS { CmptPtr(Cmpt* p) : type{ CmptType::Of }, p{ p }{} CmptType Type() const noexcept { return type; } + + // unchecked void* Ptr() const noexcept { return p; } - // for static Component + // unchecked template - Cmpt* As() const noexcept { - assert(type.Is()); - return reinterpret_cast(p); - } - private: - CmptType type; - void* p; - }; + Cmpt* As() const noexcept { return reinterpret_cast(p); } - // CmptType + const void* - class CmptCPtr { - public: - CmptCPtr(CmptType type, const void* p) :type{ type }, p{ p }{} template - CmptCPtr(const Cmpt* p) : type{ CmptType::Of }, p{ p }{} + LastFrame AsLastFrame() const noexcept { + assert(type.GetAccessMode() == AccessMode::LAST_FRAME); + return p; + } - CmptType Type() const noexcept { return type; } - const void* Ptr() const noexcept { return p; } + template + Write AsWrite() const noexcept { + assert(type.GetAccessMode() == AccessMode::WRITE); + return p; + } - // for static Component template - const Cmpt* As() const noexcept { - assert(type.Is()); - return reinterpret_cast(p); + Latest AsLatest() const noexcept { + assert(type.GetAccessMode() == AccessMode::LATEST); + return p; } private: CmptType type; - const void* p; + void* p; }; } diff --git a/include/UECS/CmptsView.h b/include/UECS/CmptsView.h new file mode 100644 index 0000000..0b92213 --- /dev/null +++ b/include/UECS/CmptsView.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CmptPtr.h" +#include "CmptType.h" +#include "CmptTag.h" + +#include + +namespace Ubpa::UECS { + class EntityLocator; + + // use CmptsView::Iterator to read CmptPtr + class CmptsView { + public: + CmptsView(EntityLocator* locator, void** cmpts) + : locator{ locator }, cmpts{ cmpts }{} + + // check AccessMode + CmptPtr GetCmpt(CmptType) const; + + template + LastFrame GetCmptAsLastFrame() const { + return GetCmpt(CmptType::Of>).AsLastFrame(); + } + + template + Write GetCmptAsWrite() const { + return GetCmpt(CmptType::Of>).AsWrite(); + } + + template + Latest GetCmptAsLatest() const { + return GetCmpt(CmptType::Of>).AsLatest(); + } + + void* const* Components() const noexcept { return cmpts; } + private: + EntityLocator* locator; + void* const* cmpts; + }; +} diff --git a/include/UECS/EntityLocator.h b/include/UECS/EntityLocator.h index ab26e1a..f4a7cc2 100644 --- a/include/UECS/EntityLocator.h +++ b/include/UECS/EntityLocator.h @@ -17,11 +17,7 @@ namespace Ubpa::UECS { template EntityLocator(TypeList, TypeList, TypeList); - EntityLocator( - std::set lastFrameCmpts = {}, - std::set writeFrameCmpts = {}, - std::set latestCmpts = {} - ); + EntityLocator(const CmptType* types, size_t num); size_t HashCode() const noexcept { return hashCode; } diff --git a/include/UECS/RTDCmptsView.h b/include/UECS/RTDCmptsView.h deleted file mode 100644 index 8cb9258..0000000 --- a/include/UECS/RTDCmptsView.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include "CmptPtr.h" -#include "CmptType.h" -#include "CmptTag.h" - -#include - -namespace Ubpa::UECS { - class EntityLocator; - - // use RTDCmptsView::Iterator to read CmptPtr - // use CmptHandle for read/write control - // use begin() and end() to iterate - class RTDCmptsView { - public: - // for read/write control - class CmptHandle { - public: - CmptHandle(CmptType type, void* cmpt, AccessMode mode) - : type{ type }, cmpt{ cmpt }, mode{ mode }{} - - CmptType GetCmptType() const noexcept { return type; } - AccessMode GetMode() const noexcept { return mode; } - - CmptCPtr AsLastFrame() const noexcept { - assert(mode == AccessMode::LAST_FRAME); - return { type, cmpt }; - } - CmptPtr AsWrite() const noexcept { - assert(mode == AccessMode::WRITE); - return { type, cmpt }; - } - CmptCPtr AsLatest() const noexcept { - assert(mode == AccessMode::LATEST); - return { type, cmpt }; - } - private: - CmptType type; - void* cmpt; - AccessMode mode; - }; - - // forward - class Iterator /*: public std::iterator*/ { - public: - using iterator_category = std::forward_iterator_tag; - using value_type = CmptPtr; - using difference_type = std::ptrdiff_t; - using pointer = CmptPtr*; - using reference = CmptPtr&; - - Iterator(EntityLocator* locator, std::set::iterator typeIter = std::set::iterator{}, void* const* ptr_cmpt = nullptr) - : locator{ locator }, typeIter(typeIter), ptr_cmpt{ ptr_cmpt } {} - bool operator==(const Iterator& rhs) const noexcept { - return ptr_cmpt == rhs.ptr_cmpt; - } - bool operator!=(const Iterator& rhs) const noexcept { - return ptr_cmpt != rhs.ptr_cmpt; - } - CmptHandle operator*() const; - const CmptHandle* operator->() const noexcept; - Iterator& operator++() { - typeIter++; - ptr_cmpt++; - return *this; - } - private: - EntityLocator* locator; - std::set::iterator typeIter; - void* const* ptr_cmpt; - mutable CmptHandle handle{ CmptType::Invalid(), nullptr, AccessMode{} }; - }; - - RTDCmptsView(EntityLocator* locator, void** cmpts) - : locator{ locator }, cmpts{ cmpts }{} - - Iterator begin() const noexcept; - Iterator end() const noexcept; - - const std::set& CmptTypes() const noexcept; - void* const* Components() const noexcept { return cmpts; } - - private: - EntityLocator* locator; - void* const* cmpts; - }; -} diff --git a/include/UECS/SystemFunc.h b/include/UECS/SystemFunc.h index 3968d9b..21ab1da 100644 --- a/include/UECS/SystemFunc.h +++ b/include/UECS/SystemFunc.h @@ -2,7 +2,7 @@ #include "EntityQuery.h" #include "Entity.h" -#include "RTDCmptsView.h" +#include "CmptsView.h" #include "ChunkView.h" #include @@ -14,7 +14,7 @@ namespace Ubpa::UECS { // name must be unique in global // query.filter can be change dynamically by other with Schedule // [system function kind] (distinguish by argument list) - // 1. per entity function: [[const] Entity e] [size_t indexInQuery] [RTDCmptsView] ... + // 1. per entity function: [[const] Entity e] [size_t indexInQuery] [CmptsView] ... // * : {LastFrame|Write|Latest} // 2. chunk: ChunkView // 3. job: empty argument list @@ -41,7 +41,7 @@ namespace Ubpa::UECS { size_t HashCode() const noexcept { return hashCode; } - void operator()(Entity e, size_t entityIndexInQuery, RTDCmptsView rtdcmpts); + void operator()(Entity e, size_t entityIndexInQuery, CmptsView rtdcmpts); void operator()(ChunkView chunkView); void operator()(); @@ -52,7 +52,7 @@ namespace Ubpa::UECS { template SystemFunc(Func&& func, std::string name, EntityFilter filter, ArgList); - std::function func; + std::function func; std::string name; Mode mode; diff --git a/include/UECS/detail/SystemFunc.inl b/include/UECS/detail/SystemFunc.inl index 61f5fec..beb0edd 100644 --- a/include/UECS/detail/SystemFunc.inl +++ b/include/UECS/detail/SystemFunc.inl @@ -18,8 +18,8 @@ namespace Ubpa::UECS { { using ArgList = FuncTraits_ArgList; - static_assert(Contain_v, - "(Mode::Entity) 's argument list must contain RTDCmptsView"); + static_assert(Contain_v, + "(Mode::Entity) 's argument list must contain CmptsView"); static_assert(!Contain_v, "(Mode::Entity) 's argument list must not contain ChunkView"); @@ -40,8 +40,8 @@ namespace Ubpa::UECS { hashCode{ HashCode(this->name) }, query{ std::move(filter), EntityLocator{Filter_t{}} } { - static_assert(!Contain_v, - "'s argument list contains RTDCmptsView, so you should use the constructor of the run-time dynamic version"); + static_assert(!Contain_v, + "'s argument list contains CmptsView, so you should use the constructor of the run-time dynamic version"); if constexpr (IsEmpty_v) mode = Mode::Job; else if constexpr (std::is_same_v>) @@ -63,13 +63,14 @@ namespace Ubpa::UECS::detail::System_ { using CmptList = TypeList; // sorted template static auto run(Func&& func) noexcept { - return [func = std::forward(func)](Entity e, size_t entityIndexInQuery, RTDCmptsView rtdcmpts, ChunkView chunkView) { + return [func = std::forward(func)](Entity e, size_t entityIndexInQuery, CmptsView rtdcmpts, ChunkView chunkView) { auto unsorted_arg_tuple = std::make_tuple( e, entityIndexInQuery, rtdcmpts, chunkView, - reinterpret_cast(rtdcmpts.Components()[Find_v])...); + reinterpret_cast(rtdcmpts.Components()[Find_v])... + ); func(std::get(unsorted_arg_tuple)...); }; } diff --git a/src/core/CmptsView.cpp b/src/core/CmptsView.cpp new file mode 100644 index 0000000..c8a46f3 --- /dev/null +++ b/src/core/CmptsView.cpp @@ -0,0 +1,18 @@ +#include + +#include + +using namespace Ubpa::UECS; +using namespace std; + +CmptPtr CmptsView::GetCmpt(CmptType t) const { + size_t i = 0; + for (auto iter = locator->CmptTypes().begin(); iter != locator->CmptTypes().end(); ++iter, ++i) { + if (*iter == t) { + assert(iter->GetAccessMode() == t.GetAccessMode()); + return CmptPtr(*iter, *(cmpts + i)); + } + } + assert(false); + return CmptPtr(t, nullptr); +} diff --git a/src/core/EntityLocator.cpp b/src/core/EntityLocator.cpp index 955dfc9..f2cbe05 100644 --- a/src/core/EntityLocator.cpp +++ b/src/core/EntityLocator.cpp @@ -5,13 +5,25 @@ using namespace Ubpa::UECS; using namespace std; -EntityLocator::EntityLocator(set lastFrameCmpts, - set writeFrameCmpts, - set latestCmpts) - : lastFrameCmptTypes{ move(lastFrameCmpts) }, - writeCmptTypes{ move(writeFrameCmpts) }, - latestCmptTypes{ move(latestCmpts) } -{ +EntityLocator::EntityLocator(const CmptType* types, size_t num) { + assert(types != nullptr); + for (size_t i = 0; i < num; i++) { + switch (types[i].GetAccessMode()) + { + case Ubpa::UECS::AccessMode::LAST_FRAME: + lastFrameCmptTypes.insert(types[i]); + break; + case Ubpa::UECS::AccessMode::WRITE: + writeCmptTypes.insert(types[i]); + break; + case Ubpa::UECS::AccessMode::LATEST: + latestCmptTypes.insert(types[i]); + break; + default: + assert(false); + break; + } + } cmptTypes = SetUnion(lastFrameCmptTypes, writeCmptTypes); cmptTypes = SetUnion(cmptTypes, latestCmptTypes); hashCode = GenHashCode(); diff --git a/src/core/RTDCmptsView.cpp b/src/core/RTDCmptsView.cpp deleted file mode 100644 index e294ea2..0000000 --- a/src/core/RTDCmptsView.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -using namespace Ubpa::UECS; -using namespace std; - -RTDCmptsView::Iterator RTDCmptsView::begin() const noexcept { - return { locator, locator->CmptTypes().begin(), cmpts }; -} - -RTDCmptsView::Iterator RTDCmptsView::end() const noexcept { - return { locator, locator->CmptTypes().end(), cmpts + locator->CmptTypes().size() }; -} - -const set& RTDCmptsView::CmptTypes() const noexcept { - return locator->CmptTypes(); -} - -RTDCmptsView::CmptHandle RTDCmptsView::Iterator::operator*() const { - return { *typeIter, *ptr_cmpt, locator->GetCmptTagMode(*typeIter) }; -} - -const RTDCmptsView::CmptHandle* RTDCmptsView::Iterator::operator->() const noexcept { - handle = { *typeIter, *ptr_cmpt, locator->GetCmptTagMode(*typeIter) }; - return &handle; -} diff --git a/src/core/SystemFunc.cpp b/src/core/SystemFunc.cpp index 78973b8..2bbca13 100644 --- a/src/core/SystemFunc.cpp +++ b/src/core/SystemFunc.cpp @@ -2,7 +2,7 @@ using namespace Ubpa::UECS; -void SystemFunc::operator()(Entity e, size_t entityIndexInQuery, RTDCmptsView rtdcmpts) { +void SystemFunc::operator()(Entity e, size_t entityIndexInQuery, CmptsView rtdcmpts) { assert(mode == Mode::Entity); return func( e, @@ -17,7 +17,7 @@ void SystemFunc::operator()(ChunkView chunkView) { return func( Entity::Invalid(), size_t_invalid, - RTDCmptsView{ nullptr, nullptr }, + CmptsView{ nullptr, nullptr }, chunkView ); } @@ -27,7 +27,7 @@ void SystemFunc::operator()() { return func( Entity::Invalid(), size_t_invalid, - RTDCmptsView{ nullptr, nullptr }, + CmptsView{ nullptr, nullptr }, ChunkView{ nullptr, size_t_invalid, nullptr } ); } diff --git a/src/test/11_runtime_cmpt/main.cpp b/src/test/11_runtime_cmpt/main.cpp index e8a56b1..62a860e 100644 --- a/src/test/11_runtime_cmpt/main.cpp +++ b/src/test/11_runtime_cmpt/main.cpp @@ -10,34 +10,32 @@ class RTDSystem: public System{ using System::System; virtual void OnUpdate(Schedule& schedule) override { + std::array cmpts_write = { + CmptType{ "LuaCmpt", AccessMode::WRITE } + }; + std::array cmpts_read = { + CmptType{ "LuaCmpt", AccessMode::LATEST } + }; + EntityLocator locator_write( - {}, // read: last frame - { CmptType{ "LuaCmpt" } }, // write - {} // read: lastest + cmpts_write.data(), cmpts_write.size() ); EntityLocator locator_read( - {}, // read: last frame - {}, // write - { CmptType{ "LuaCmpt" } } // read: lastest + cmpts_read.data(), cmpts_read.size() ); + schedule .Register( - [](RTDCmptsView cmpts) { - for (auto handle : cmpts) { - if (handle.GetCmptType() == CmptType{ "LuaCmpt" }) { - double& val = *reinterpret_cast(handle.AsWrite().Ptr()); - val = 520.; - } - } + [](CmptsView cmpts) { + auto luaCmpt = cmpts.GetCmpt(CmptType{ "LuaCmpt", AccessMode::WRITE }); + double& val = *reinterpret_cast(luaCmpt.Ptr()); + val = 520.; }, "write", locator_write) .Register( - [](RTDCmptsView cmpts) { - for (auto handle : cmpts) { - if (handle.GetCmptType() == CmptType{ "LuaCmpt" }) { - const double& val = *reinterpret_cast(handle.AsLatest().Ptr()); - cout << "value : " << val << endl; - } - } + [](CmptsView cmpts) { + auto luaCmpt = cmpts.GetCmpt(CmptType{ "LuaCmpt", AccessMode::LATEST }); + const double& val = *reinterpret_cast(luaCmpt.Ptr()); + cout << "value : " << val << endl; }, "read", locator_read); } };