diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6d83207..90183363 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,14 @@ name: Build -on: [pull_request, workflow_dispatch] +on: + pull_request: + workflow_dispatch: + inputs: + debug: + type: boolean + description: 'Enable TMate Debug' + required: false + default: false env: BUILD_TYPE: Release @@ -16,6 +24,16 @@ jobs: runs-on: ${{ matrix.os }} steps: + - name: Setup TMate Session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug }} + with: + detached: true + + - name: Set XCode Version + run: sudo xcode-select -s /Library/Developer/CommandLineTools + if: runner.os == 'macOS' + - name: Checkout Repo uses: actions/checkout@v2 diff --git a/CMake/Target.cmake b/CMake/Target.cmake index f88869d5..4a9c33b5 100644 --- a/CMake/Target.cmake +++ b/CMake/Target.cmake @@ -245,9 +245,11 @@ function(AddMirrorInfoSourceGenerationTarget) foreach (SEARCH_DIR ${PARAMS_SEARCH_DIR}) file(GLOB_RECURSE INPUT_HEADER_FILES "${SEARCH_DIR}/*.h") foreach (INPUT_HEADER_FILE ${INPUT_HEADER_FILES}) - get_filename_component(FILENAME ${INPUT_HEADER_FILE} NAME_WE) + string(REPLACE "${CMAKE_SOURCE_DIR}/" "" TEMP ${INPUT_HEADER_FILE}) + get_filename_component(DIR ${TEMP} DIRECTORY) + get_filename_component(FILENAME ${TEMP} NAME_WE) - set(OUTPUT_SOURCE "${CMAKE_BINARY_DIR}/Generated/MirrorInfoSource/${PARAMS_NAME}/${FILENAME}.generated.cpp") + set(OUTPUT_SOURCE "${CMAKE_BINARY_DIR}/Generated/MirrorInfoSource/${DIR}/${FILENAME}.generated.cpp") list(APPEND OUTPUT_SOURCES ${OUTPUT_SOURCE}) add_custom_command( @@ -289,10 +291,10 @@ function(AddExecutable) ) endif() - add_executable( + add_executable(${PARAMS_NAME}) + target_sources( ${PARAMS_NAME} - ${PARAMS_SRC} - ${GENERATED_SRC} + PRIVATE ${PARAMS_SRC} ${GENERATED_SRC} ) target_include_directories( ${PARAMS_NAME} @@ -351,8 +353,10 @@ function(AddLibrary) add_library( ${PARAMS_NAME} ${PARAMS_TYPE} - ${PARAMS_SRC} - ${GENERATED_SRC} + ) + target_sources( + ${PARAMS_NAME} + PRIVATE ${PARAMS_SRC} ${GENERATED_SRC} ) target_include_directories( ${PARAMS_NAME} @@ -414,10 +418,10 @@ function(AddTest) ) endif() - add_executable( + add_executable(${PARAMS_NAME}) + target_sources( ${PARAMS_NAME} - ${PARAMS_SRC} - ${GENERATED_SRC} + PRIVATE ${PARAMS_SRC} ${GENERATED_SRC} ) target_include_directories( ${PARAMS_NAME} diff --git a/CMake/ThirdParty.cmake b/CMake/ThirdParty.cmake index 4bb15159..1e8a7cb8 100644 --- a/CMake/ThirdParty.cmake +++ b/CMake/ThirdParty.cmake @@ -66,7 +66,7 @@ function(Get3rdPlatformValue) cmake_parse_arguments(PARAMS "ARCH" "OUTPUT" "INPUT" ${ARGN}) if (${PARAMS_ARCH}) - set(PLATFORM_KEYWORDS "Windows-AMD64;Darwin-arm64;Darwin-x86_64") + set(PLATFORM_KEYWORDS "Windows-AMD64;Darwin-arm64") set(CURRENT_KEYWORDS "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") else() set(PLATFORM_KEYWORDS "Windows;Darwin;Linux") @@ -331,7 +331,7 @@ function(Add3rdCMakeProject) SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} CMAKE_ARGS ${CMAKE_BUILD_TYPE_ARGS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} ${PARAMS_CMAKE_ARG} - BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ -j 16 INSTALL_COMMAND ${CMAKE_COMMAND} --install --config $ ) set_target_properties( diff --git a/Editor/Source/CMakeLists.txt b/Editor/Source/CMakeLists.txt index 78c41d40..67bc6f3a 100644 --- a/Editor/Source/CMakeLists.txt +++ b/Editor/Source/CMakeLists.txt @@ -9,7 +9,7 @@ AddExecutable( NAME Editor SRC ${SOURCES} INC Include - LIB Qt Core RHI Rendering Runtime + LIB Qt Core RHI Runtime RES ${FINAL_RESOURCES} ) diff --git a/Editor/Source/Include/Editor/Core.h b/Editor/Source/Include/Editor/Core.h index a9372862..1149f9f5 100644 --- a/Editor/Source/Include/Editor/Core.h +++ b/Editor/Source/Include/Editor/Core.h @@ -5,7 +5,7 @@ #pragma once #include -#include +#include namespace Editor { class Core { @@ -17,7 +17,6 @@ namespace Editor { void Initialize(int argc, char** argv); void Cleanup(); bool ProjectHasSet() const; - Rendering::RenderingModule* GetRenderingModule() const; Runtime::Engine* GetEngine() const; private: @@ -25,9 +24,7 @@ namespace Editor { void ParseCommandLineArgs(int argc, char** argv) const; void InitializeRuntime(); - void InitializeRendering(); - Rendering::RenderingModule* renderingModule; Runtime::Engine* engine; }; } diff --git a/Editor/Source/Src/Core.cpp b/Editor/Source/Src/Core.cpp index ea60c5f7..d958b563 100644 --- a/Editor/Source/Src/Core.cpp +++ b/Editor/Source/Src/Core.cpp @@ -21,8 +21,7 @@ namespace Editor { } Core::Core() - : renderingModule(nullptr) - , engine(nullptr) + : engine(nullptr) { } @@ -32,13 +31,11 @@ namespace Editor { { ParseCommandLineArgs(argc, argv); InitializeRuntime(); - InitializeRendering(); } void Core::Cleanup() // NOLINT { ::Core::ModuleManager::Get().Unload("Runtime"); - ::Core::ModuleManager::Get().Unload("Rendering"); } Runtime::Engine* Core::GetEngine() const @@ -51,11 +48,6 @@ namespace Editor { return !caProjectFile.GetValue().empty(); } - Rendering::RenderingModule* Core::GetRenderingModule() const - { - return renderingModule; - } - void Core::ParseCommandLineArgs(int argc, char** argv) const // NOLINT { ::Core::Cli::Get().Parse(argc, argv); @@ -65,17 +57,9 @@ namespace Editor { { Runtime::EngineInitParams params {}; params.projectFile = caProjectFile.GetValue(); + params.rhiType = caRhiType.GetValue(); + Runtime::EngineHolder::Load("Editor", params); engine = &Runtime::EngineHolder::Get(); } - - void Core::InitializeRendering() - { - renderingModule = ::Core::ModuleManager::Get().FindOrLoadTyped("Rendering"); - Assert(renderingModule != nullptr); - - Rendering::RenderingModuleInitParams initParams; - initParams.rhiType = RHI::RHIAbbrStringToRHIType(caRhiType.GetValue()); - renderingModule->Initialize(initParams); - } } diff --git a/Engine/Source/CMakeLists.txt b/Engine/Source/CMakeLists.txt index 98b21b72..5cd23a69 100644 --- a/Engine/Source/CMakeLists.txt +++ b/Engine/Source/CMakeLists.txt @@ -8,7 +8,6 @@ add_subdirectory(Mirror) add_subdirectory(Core) add_subdirectory(Render) add_subdirectory(Runtime) -add_subdirectory(Rendering) add_subdirectory(RHI-Dummy) add_subdirectory(RHI-Vulkan) diff --git a/Engine/Source/Common/CMakeLists.txt b/Engine/Source/Common/CMakeLists.txt index 9d14ceb0..2f0855bf 100644 --- a/Engine/Source/Common/CMakeLists.txt +++ b/Engine/Source/Common/CMakeLists.txt @@ -4,7 +4,7 @@ AddLibrary( TYPE STATIC SRC ${SOURCES} PUBLIC_INC Include - LIB debugbreak cityhash taskflow fmt-lib rapidjson + LIB debugbreak cityhash taskflow rapidjson ) file(GLOB TEST_SOURCES Test/*.cpp) diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index f062cbc9..814dbdfa 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -4,13 +4,18 @@ #pragma once +#include #include #include #include #include +#include +#include +#include #include #include +#include namespace Common { class VectorUtils { @@ -18,20 +23,18 @@ namespace Common { template static typename std::vector::iterator SwapWithLastAndDelete(std::vector& vector, const typename std::vector::iterator& iterator); template static size_t SwapWithLastAndDelete(std::vector& vector, size_t index); template static std::vector GetIntersection(const std::vector& lhs, const std::vector& rhs); + template static std::vector GetDifferences(const std::vector& lhs, const std::vector& rhs); }; class SetUtils { public: template static std::unordered_set GetIntersection(const std::unordered_set& lhs, const std::unordered_set& rhs); template static std::unordered_set GetUnion(const std::unordered_set& lhs, const std::unordered_set& rhs); - template static void GetUnionInline(std::unordered_set& lhs, const std::unordered_set& rhs); + template static void GetUnionInplace(std::unordered_set& lhs, const std::unordered_set& rhs); }; - template - class InplaceVectorIter; - - template - concept ValidInplaceVectorIter = std::is_same_v> || std::is_same_v>; + template class InplaceVectorIter; + template concept ValidInplaceVectorIter = std::is_same_v> || std::is_same_v>; template class InplaceVectorIter { @@ -40,6 +43,11 @@ namespace Common { explicit InplaceVectorIter(T* inPtr); + InplaceVectorIter(const InplaceVectorIter& inOther); + InplaceVectorIter(InplaceVectorIter&& inOther) noexcept; + InplaceVectorIter& operator=(const InplaceVectorIter& inOther); + InplaceVectorIter& operator=(InplaceVectorIter&& inOther) noexcept; + template T2> Offset operator-(const T2& inOther) const; template T2> bool operator==(const T2& inOther) const; template T2> bool operator!=(const T2& inOther) const; @@ -126,14 +134,14 @@ namespace Common { static constexpr size_t memorySize = elementSize * N; template I> void CheckIterValid(const I& inIter) const; - template void EmplaceConstruct(size_t inIndex, Args&&... inArgs); - template I, typename... Args> void EmplaceConstruct(const I& inIter, Args&&... inArgs); - template I> void EmplaceDestruct(const I& inIter); + template void InplaceConstruct(size_t inIndex, Args&&... inArgs); + template I, typename... Args> void InplaceConstruct(const I& inIter, Args&&... inArgs); + template I> void InplaceDestruct(const I& inIter); template T& InsertInternal(size_t inIndex, T2&& inElement); template I, typename T2> T& InsertInternal(const I& inIter, T2&& inElement); template I> void EraseInternal(const I& inIter); template I> void EraseSwapLastInternal(const I& inIter); - void EmplaceDestruct(size_t inIndex); + void InplaceDestruct(size_t inIndex); T& TypedMemory(size_t inIndex); const T& TypedMemory(size_t inIndex) const; void CheckIndexValid(size_t inIndex) const; @@ -142,6 +150,118 @@ namespace Common { size_t size; std::array memory; }; + + // container which perform inplace destruct and leave a slot for re-alloc when erase + template + class Trunk { + public: + using TraverseFunc = std::function; + using ConstTraverseFunc = std::function; + + static constexpr size_t Capacity(); + + Trunk(); + ~Trunk(); + + Trunk(const Trunk& inOther); + Trunk(Trunk&& inOther) noexcept; + Trunk& operator=(const Trunk& inOther); + Trunk& operator=(Trunk&& inOther) noexcept; + + template size_t Emplace(Args&&... inArgs); + bool Valid(size_t inIndex) const; + void Erase(size_t inIndex); + T* Try(size_t inIndex); + const T* Try(size_t inIndex) const; + T& At(size_t inIndex); + const T& At(size_t inIndex) const; + void Each(const TraverseFunc& inFunc); + void Each(const ConstTraverseFunc& inFunc) const; + bool HasFree() const; + size_t Free() const; + size_t Allocated() const; + bool Empty() const; + void Clear(); + explicit operator bool() const; + T& operator[](size_t inIndex); + const T& operator[](size_t inIndex) const; + + private: + static constexpr size_t elemMemSize = sizeof(T); + static constexpr size_t totalMemSize = elemMemSize * N; + static bool Contains(size_t inIndex); + + T& TypedMemory(size_t inIndex); + const T& TypedMemory(size_t inIndex) const; + template void InplaceConstruct(size_t inIndex, Args&&... inArgs); + void InplaceDestruct(size_t inIndex); + + std::bitset allocated; + std::array memory; + }; + + // pointer stable + template + class TrunkList { + public: + using TraverseFunc = typename Trunk::TraverseFunc; + using ConstTraverseFunc = typename Trunk::ConstTraverseFunc; + + class ConstHandle { + public: + ConstHandle(const TrunkList* inOwner, const Trunk* inTrunk, size_t inIndex); + + explicit operator bool() const; + T* operator->() const; + T& operator*() const; + + private: + friend class TrunkList; + + void Valid(); + + const TrunkList* owner; + const Trunk* trunk; + size_t index; + }; + + class Handle { + public: + Handle(TrunkList* inOwner, Trunk* inTrunk, size_t inIndex); + + ConstHandle Const() const; + explicit operator bool() const; + const T* operator->() const; + const T& operator*() const; + + private: + friend class TrunkList; + + void Valid(); + + TrunkList* owner; + Trunk* trunk; + size_t index; + }; + + TrunkList(); + ~TrunkList(); + + template Handle Emplace(Args&&... inArgs); + void Erase(const Handle& inHandle); + void Erase(const ConstHandle& inHandle); + void Each(const TraverseFunc& inFunc); + void Each(const ConstTraverseFunc& inFunc) const; + void Reserve(size_t inIndex); + size_t Allocated() const; + size_t Capacity() const; + size_t Free() const; + bool Empty() const; + explicit operator bool() const; + + private: + std::list> trunks; + }; } namespace Common { // NOLINT @@ -176,6 +296,14 @@ namespace Common { return result; } + template + std::vector VectorUtils::GetDifferences(const std::vector& lhs, const std::vector& rhs) + { + std::vector result; + std::set_difference(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::back_inserter(result)); + return result; + } + template std::unordered_set SetUtils::GetIntersection(const std::unordered_set& lhs, const std::unordered_set& rhs) { @@ -206,7 +334,7 @@ namespace Common { } template - void SetUtils::GetUnionInline(std::unordered_set& lhs, const std::unordered_set& rhs) + void SetUtils::GetUnionInplace(std::unordered_set& lhs, const std::unordered_set& rhs) { lhs.reserve(lhs.size() + rhs.size()); for (const auto& element : rhs) { @@ -214,6 +342,38 @@ namespace Common { } } + template + InplaceVectorIter::InplaceVectorIter(T* inPtr) + : ptr(inPtr) + { + } + + template + InplaceVectorIter::InplaceVectorIter(const InplaceVectorIter& inOther) + : ptr(inOther.ptr) + { + } + + template + InplaceVectorIter::InplaceVectorIter(InplaceVectorIter&& inOther) noexcept + : ptr(inOther.ptr) + { + } + + template + InplaceVectorIter& InplaceVectorIter::operator=(const InplaceVectorIter& inOther) + { + ptr = inOther.ptr; + return *this; + } + + template + InplaceVectorIter& InplaceVectorIter::operator=(InplaceVectorIter&& inOther) noexcept + { + ptr = inOther.ptr; + return *this; + } + template template T2> typename InplaceVectorIter::Offset InplaceVectorIter::operator-(const T2& inOther) const @@ -263,12 +423,6 @@ namespace Common { return ptr <= inOther.Ptr(); } - template - InplaceVectorIter::InplaceVectorIter(T* inPtr) - : ptr(inPtr) - { - } - template T& InplaceVectorIter::operator*() const { @@ -361,7 +515,7 @@ namespace Common { : size(inSize) { for (auto i = 0; i < size; i++) { - EmplaceConstruct(i, inDefault); + InplaceConstruct(i, inDefault); } } @@ -369,7 +523,7 @@ namespace Common { InplaceVector::~InplaceVector() { for (auto i = 0; i < size; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } } @@ -379,7 +533,7 @@ namespace Common { { static_assert(std::is_copy_constructible_v); for (auto i = 0; i < size; i++) { - EmplaceConstruct(i, inOther.TypedMemory(i)); + InplaceConstruct(i, inOther.TypedMemory(i)); } } @@ -389,7 +543,7 @@ namespace Common { { static_assert(std::is_move_constructible_v); for (auto i = 0; i < size; i++) { - EmplaceConstruct(i, std::move(inOther.TypedMemory(i))); + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); } } @@ -400,14 +554,14 @@ namespace Common { const auto oldSize = size; size = inOther.size; for (auto i = size; i < oldSize; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } for (auto i = 0; i < size; i++) { if (i < oldSize) { TypedMemory(i) = inOther.TypedMemory(i); } else { - EmplaceConstruct(i, inOther.TypedMemory(i)); + InplaceConstruct(i, inOther.TypedMemory(i)); } } return *this; @@ -420,14 +574,14 @@ namespace Common { const auto oldSize = size; size = inOther.size; for (auto i = size; i < oldSize; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } for (auto i = 0; i < size; i++) { if (i < oldSize) { TypedMemory(i) = std::move(inOther.TypedMemory(i)); } else { - EmplaceConstruct(i, std::move(inOther.TypedMemory(i))); + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); } } return *this; @@ -439,7 +593,7 @@ namespace Common { { CheckInsertible(); auto lastIndex = size++; - EmplaceConstruct(lastIndex, std::forward(inArgs)...); + InplaceConstruct(lastIndex, std::forward(inArgs)...); return TypedMemory(lastIndex); } @@ -494,7 +648,7 @@ namespace Common { template void InplaceVector::PopBack() { - EmplaceDestruct(size - 1); + InplaceDestruct(size - 1); size--; } @@ -513,7 +667,7 @@ namespace Common { Assert(false); } } - EmplaceDestruct(size - 1); + InplaceDestruct(size - 1); size--; } @@ -542,7 +696,7 @@ namespace Common { } else { Assert(false); } - EmplaceDestruct(size - 1); + InplaceDestruct(size - 1); size--; } @@ -594,14 +748,14 @@ namespace Common { const auto oldSize = size; size = inSize; for (auto i = size; i < oldSize; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } for (auto i = 0; i < size; i++) { if (i < oldSize) { TypedMemory(i) = inDefault; } else { - EmplaceConstruct(i, inDefault); + InplaceConstruct(i, inDefault); } } } @@ -732,7 +886,7 @@ namespace Common { template template - void InplaceVector::EmplaceConstruct(size_t inIndex, Args&&... inArgs) + void InplaceVector::InplaceConstruct(size_t inIndex, Args&&... inArgs) { CheckIndexValid(inIndex); new(reinterpret_cast(memory.data()) + inIndex) T(std::forward(inArgs)...); @@ -740,7 +894,7 @@ namespace Common { template template I, typename ... Args> - void InplaceVector::EmplaceConstruct(const I& inIter, Args&&... inArgs) + void InplaceVector::InplaceConstruct(const I& inIter, Args&&... inArgs) { CheckIterValid(inIter); new(&*inIter) T(std::forward(inArgs)...); @@ -748,7 +902,7 @@ namespace Common { template template I> - void InplaceVector::EmplaceDestruct(const I& inIter) + void InplaceVector::InplaceDestruct(const I& inIter) { CheckIterValid(inIter); inIter->~T(); @@ -771,9 +925,9 @@ namespace Common { for (auto i = size - 1; i > inIndex; i--) { if (i == size - 1) { if constexpr (std::is_move_constructible_v) { - EmplaceConstruct(i, std::move(TypedMemory(i - 1))); + InplaceConstruct(i, std::move(TypedMemory(i - 1))); } else if constexpr (std::is_copy_constructible_v) { - EmplaceConstruct(i, TypedMemory(i - 1)); + InplaceConstruct(i, TypedMemory(i - 1)); } else { Assert(false); } @@ -809,9 +963,9 @@ namespace Common { for (auto iter = End() - 1; iter > inIter; --iter) { if (iter == End() - 1) { if constexpr (std::is_move_constructible_v) { - EmplaceConstruct(iter, std::move(*(iter - 1))); + InplaceConstruct(iter, std::move(*(iter - 1))); } else if constexpr (std::is_copy_constructible_v) { - EmplaceConstruct(iter, TypedMemory(*(iter - 1))); + InplaceConstruct(iter, TypedMemory(*(iter - 1))); } else { Assert(false); } @@ -846,7 +1000,7 @@ namespace Common { Assert(false); } } - EmplaceDestruct(End() - 1); + InplaceDestruct(End() - 1); size--; } @@ -864,12 +1018,12 @@ namespace Common { } else { Assert(false); } - EmplaceDestruct(End() - 1); + InplaceDestruct(End() - 1); size--; } template - void InplaceVector::EmplaceDestruct(size_t inIndex) + void InplaceVector::InplaceDestruct(size_t inIndex) { CheckIndexValid(inIndex); TypedMemory(inIndex).~T(); @@ -900,4 +1054,419 @@ namespace Common { { Assert(size + inNum <= N); } + + template + constexpr size_t Trunk::Capacity() + { + return N; + } + + template + Trunk::Trunk() = default; + + template + Trunk::~Trunk() + { + Clear(); + } + + template + Trunk::Trunk(const Trunk& inOther) + : allocated(inOther.allocated) + , memory() + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + InplaceConstruct(i, inOther.TypedMemory(i)); + } + } + } + + template + Trunk::Trunk(Trunk&& inOther) noexcept + : allocated(std::move(inOther.allocated)) + , memory() + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); + } + } + } + + template + Trunk& Trunk::operator=(const Trunk& inOther) + { + auto oldAllocated = allocated; + allocated = inOther.allocated; + + for (auto i = 0; i < allocated.size(); i++) { + if (oldAllocated.test(i) && !allocated.test(i)) { + InplaceDestruct(i); + } + if (!oldAllocated.test(i) && allocated.test(i)) { + InplaceConstruct(i, inOther.TypedMemory(i)); + } + if (oldAllocated.test(i) && allocated.test(i)) { + TypedMemory(i) = inOther.TypedMemory(i); + } + } + return *this; + } + + template + Trunk& Trunk::operator=(Trunk&& inOther) noexcept + { + auto oldAllocated = allocated; + allocated = inOther.allocated; + + for (auto i = 0; i < allocated.size(); i++) { + if (oldAllocated.test(i) && !allocated.test(i)) { + InplaceDestruct(i); + } + if (!oldAllocated.test(i) && allocated.test(i)) { + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); + } + if (oldAllocated.test(i) && allocated.test(i)) { + TypedMemory(i) = std::move(inOther.TypedMemory(i)); + } + } + return *this; + } + + template + template + size_t Trunk::Emplace(Args&&... inArgs) + { + for (auto i = 0; i < allocated.size(); i++) { + if (!allocated.test(i)) { + allocated.set(i, true); + InplaceConstruct(i, std::forward(inArgs)...); + return i; + } + } + QuickFailWithReason("container is full"); + return 0; + } + + template + bool Trunk::Valid(size_t inIndex) const + { + if (!Contains(inIndex)) { + return false; + } + return allocated.test(inIndex); + } + + template + void Trunk::Erase(size_t inIndex) + { + Assert(Valid(inIndex)); + allocated.set(inIndex, false); + InplaceDestruct(inIndex); + } + + template + T* Trunk::Try(size_t inIndex) + { + return Valid(inIndex) ? &TypedMemory(inIndex) : nullptr; + } + + template + const T* Trunk::Try(size_t inIndex) const + { + return Valid(inIndex) ? &TypedMemory(inIndex) : nullptr; + } + + template + T& Trunk::At(size_t inIndex) + { + Assert(Valid(inIndex)); + return TypedMemory(inIndex); + } + + template + const T& Trunk::At(size_t inIndex) const + { + Assert(Valid(inIndex)); + return TypedMemory(inIndex); + } + + template + void Trunk::Each(const TraverseFunc& inFunc) + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + inFunc(TypedMemory(i)); + } + } + } + + template + void Trunk::Each(const ConstTraverseFunc& inFunc) const + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + inFunc(TypedMemory(i)); + } + } + } + + template + bool Trunk::HasFree() const + { + return Free() > 0; + } + + template + size_t Trunk::Free() const + { + return Capacity() - Allocated(); + } + + template + size_t Trunk::Allocated() const + { + return allocated.count(); + } + + template + bool Trunk::Empty() const + { + return Allocated() == 0; + } + + template + void Trunk::Clear() + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + InplaceDestruct(i); + } + } + } + + template + Trunk::operator bool() const + { + return !Empty(); + } + + template + T& Trunk::operator[](size_t inIndex) + { + return At(inIndex); + } + + template + const T& Trunk::operator[](size_t inIndex) const + { + return At(inIndex); + } + + template + bool Trunk::Contains(size_t inIndex) + { + return inIndex < Capacity(); + } + + template + T& Trunk::TypedMemory(size_t inIndex) + { + Assert(Contains(inIndex)); + auto* data = reinterpret_cast(memory.data()); + return data[inIndex]; + } + + template + const T& Trunk::TypedMemory(size_t inIndex) const + { + Assert(Contains(inIndex)); + const auto* data = reinterpret_cast(memory.data()); + return data[inIndex]; + } + + template + template + void Trunk::InplaceConstruct(size_t inIndex, Args&&... inArgs) + { + new(&TypedMemory(inIndex)) T(std::forward(inArgs)...); + } + + template + void Trunk::InplaceDestruct(size_t inIndex) + { + TypedMemory(inIndex).~T(); + } + + template + TrunkList::ConstHandle::ConstHandle(const TrunkList* inOwner, const Trunk* inTrunk, size_t inIndex) + : owner(inOwner) + , trunk(inTrunk) + , index(inIndex) + { + } + + template + TrunkList::ConstHandle::operator bool() const + { + return Valid(); + } + + template + T* TrunkList::ConstHandle::operator->() const + { + return trunk->Try(index); + } + + template + T& TrunkList::ConstHandle::operator*() const + { + return trunk->At(index); + } + + template + void TrunkList::ConstHandle::Valid() + { + return trunk->Valid(index); + } + + template + TrunkList::Handle::Handle(TrunkList* inOwner, Trunk* inTrunk, size_t inIndex) + : owner(inOwner) + , trunk(inTrunk) + , index(inIndex) + { + } + + template + typename TrunkList::ConstHandle TrunkList::Handle::Const() const + { + return { trunk, index }; + } + + template + TrunkList::Handle::operator bool() const + { + return Valid(); + } + + template + const T* TrunkList::Handle::operator->() const + { + return trunk->Try(index); + } + + template + const T& TrunkList::Handle::operator*() const + { + return trunk->At(index); + } + + template + void TrunkList::Handle::Valid() + { + return trunk->Valid(index); + } + + template + TrunkList::TrunkList() = default; + + template + TrunkList::~TrunkList() = default; + + template + template + typename TrunkList::Handle TrunkList::Emplace(Args&&... inArgs) + { + Trunk* allocator = nullptr; + for (auto& trunk : trunks) { + if (trunk.HasFree()) { + allocator = &trunk; + break; + } + } + if (allocator == nullptr) { + allocator = &trunks.emplace_back(); + } + return { this, allocator, allocator->Emplace(std::forward(inArgs)...) }; + } + + template + void TrunkList::Erase(const Handle& inHandle) + { + Assert(this == inHandle.owner); + inHandle.trunk->Erase(inHandle.index); + } + + template + void TrunkList::Erase(const ConstHandle& inHandle) + { + Assert(this == inHandle.owner); + inHandle.trunk->Erase(inHandle.index); + } + + template + void TrunkList::Each(const TraverseFunc& inFunc) + { + for (auto& trunk : trunks) { + trunk.Each(inFunc); + } + } + + template + void TrunkList::Each(const ConstTraverseFunc& inFunc) const + { + for (auto& trunk : trunks) { + trunk.Each(inFunc); + } + } + + template + void TrunkList::Reserve(size_t inIndex) + { + auto trunkNum = DivideAndRoundUp(inIndex, N); + if (trunkNum <= trunks.size()) { + return; + } + trunks.reserve(trunkNum); + } + + template + size_t TrunkList::Allocated() const + { + size_t result = 0; + for (const auto& trunk : trunks) { + result += trunk.Allocated(); + } + return result; + } + + template + size_t TrunkList::Capacity() const + { + return trunks.size() * N; + } + + template + size_t TrunkList::Free() const + { + size_t result = 0; + for (const auto& trunk : trunks) { + result += trunk.Free(); + } + return result; + } + + template + bool TrunkList::Empty() const + { + return Allocated() == 0; + } + + template + TrunkList::operator bool() const + { + return Empty(); + } } diff --git a/Engine/Source/Common/Include/Common/Debug.h b/Engine/Source/Common/Include/Common/Debug.h index 595f91e4..df754bd3 100644 --- a/Engine/Source/Common/Include/Common/Debug.h +++ b/Engine/Source/Common/Include/Common/Debug.h @@ -23,4 +23,9 @@ namespace Common { private: Debug(); }; + + // for compile-time check type from compile error + // sample: + // TypeDiagnosis xType; + template class TypeDiagnosis; } diff --git a/Engine/Source/Common/Include/Common/Event.h b/Engine/Source/Common/Include/Common/Event.h new file mode 100644 index 00000000..cf8db02d --- /dev/null +++ b/Engine/Source/Common/Include/Common/Event.h @@ -0,0 +1,141 @@ +// +// Created by johnk on 2024/11/5. +// + +#pragma once + +#include +#include +#include + +#include + +#define IMPL_INDEX_TO_STD_PLACEHOLDER(I) \ + template <> struct IndexToStdPlaceholder { static constexpr auto value = std::placeholders::_##I; }; \ + +namespace Common::Internal { + template struct IndexToStdPlaceholder {}; + + IMPL_INDEX_TO_STD_PLACEHOLDER(1) + IMPL_INDEX_TO_STD_PLACEHOLDER(2) + IMPL_INDEX_TO_STD_PLACEHOLDER(3) + IMPL_INDEX_TO_STD_PLACEHOLDER(4) + IMPL_INDEX_TO_STD_PLACEHOLDER(5) + IMPL_INDEX_TO_STD_PLACEHOLDER(6) + IMPL_INDEX_TO_STD_PLACEHOLDER(7) + IMPL_INDEX_TO_STD_PLACEHOLDER(8) + IMPL_INDEX_TO_STD_PLACEHOLDER(9) + IMPL_INDEX_TO_STD_PLACEHOLDER(10) +} + +namespace Common { + using ReceiverHandle = size_t; + + template + class Event { + public: + Event(); + + template ReceiverHandle BindStatic(); + template ReceiverHandle BindMember(C& inObj); + template ReceiverHandle BindLambda(F&& inLambda); + template void Broadcast(Args&&... inArgs) const; + void Unbind(ReceiverHandle inHandle); + size_t ReceiversCount() const; + void Reset(); + + private: + template void BindStaticInternal(ReceiverHandle inHandle, std::index_sequence); + template void BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence); + template void BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence); + + ReceiverHandle counter; + std::vector>> receivers; + }; +} + +namespace Common { + template + Event::Event() + : counter(0) + { + } + + template + template + ReceiverHandle Event::BindStatic() + { + const auto handle = counter++; + BindStaticInternal(handle, std::make_index_sequence()); + return handle; + } + + template + template + ReceiverHandle Event::BindMember(C& inObj) + { + const auto handle = counter++; + BindMemberInternal(handle, inObj, std::make_index_sequence()); + return handle; + } + + template + template + ReceiverHandle Event::BindLambda(F&& inLambda) + { + const auto handle = counter++; + BindLambdaInternal(handle, std::forward(inLambda), std::make_index_sequence()); + return handle; + } + + template + template + void Event::Broadcast(Args&&... inArgs) const + { + for (const auto& [_, receiver] : receivers) { + receiver(std::forward(inArgs)...); + } + } + + template + void Event::Unbind(ReceiverHandle inHandle) + { + auto iter = std::find_if(receivers.begin(), receivers.end(), [&](const auto& pair) -> bool { return pair.first == inHandle; }); + Assert(iter != receivers.end()); + receivers.erase(iter); + } + + template + size_t Event::ReceiversCount() const + { + return receivers.size(); + } + + template + void Event::Reset() + { + counter = 0; + receivers.clear(); + } + + template + template + void Event::BindStaticInternal(ReceiverHandle inHandle, std::index_sequence) + { + receivers.emplace_back(inHandle, std::bind(F, Internal::IndexToStdPlaceholder::value...)); + } + + template + template + void Event::BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence) + { + receivers.emplace_back(inHandle, std::bind(F, &inObj, Internal::IndexToStdPlaceholder::value...)); + } + + template + template + void Event::BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence) + { + receivers.emplace_back(inHandle, std::bind(inLambda, Internal::IndexToStdPlaceholder::value...)); + } +} // namespace Common diff --git a/Engine/Source/Common/Include/Common/Math/Box.h b/Engine/Source/Common/Include/Common/Math/Box.h index 72540c80..39e644ce 100644 --- a/Engine/Source/Common/Include/Common/Math/Box.h +++ b/Engine/Source/Common/Include/Common/Math/Box.h @@ -76,7 +76,7 @@ namespace Common { // NOLINT struct StringConverter> { static std::string ToString(const Box& inValue) { - return fmt::format( + return std::format( "{}min={}, max={}{}", "{", StringConverter>::ToString(inValue.min), diff --git a/Engine/Source/Common/Include/Common/Math/Color.h b/Engine/Source/Common/Include/Common/Math/Color.h index ed66412f..0511eaad 100644 --- a/Engine/Source/Common/Include/Common/Math/Color.h +++ b/Engine/Source/Common/Include/Common/Math/Color.h @@ -115,7 +115,7 @@ namespace Common { struct StringConverter { static std::string ToString(const Color& inValue) { - return fmt::format( + return std::format( "{}r={}, g={}, b={}, a={}{}", "{", StringConverter::ToString(inValue.r), @@ -130,7 +130,7 @@ namespace Common { struct StringConverter { static std::string ToString(const LinearColor& inValue) { - return fmt::format( + return std::format( "{}r={}, g={}, b={}, a={}{}", "{", StringConverter::ToString(inValue.r), diff --git a/Engine/Source/Common/Include/Common/Math/Projection.h b/Engine/Source/Common/Include/Common/Math/Projection.h index 553481a8..8a68ead1 100644 --- a/Engine/Source/Common/Include/Common/Math/Projection.h +++ b/Engine/Source/Common/Include/Common/Math/Projection.h @@ -111,7 +111,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const ReversedZOrthogonalProjection& inValue) { - return fmt::format( + return std::format( "{}width={}, height={}, near={}, far={}{}", "{", StringConverter::ToString(inValue.width), @@ -126,7 +126,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const ReversedZPerspectiveProjection& inValue) { - return fmt::format( + return std::format( "{}fov={}, width={}, height={}, near={}, far={}{}", "{", StringConverter::ToString(inValue.fov), diff --git a/Engine/Source/Common/Include/Common/Math/Quaternion.h b/Engine/Source/Common/Include/Common/Math/Quaternion.h index 9def2483..761ed579 100644 --- a/Engine/Source/Common/Include/Common/Math/Quaternion.h +++ b/Engine/Source/Common/Include/Common/Math/Quaternion.h @@ -184,7 +184,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Angle& inValue) { - return fmt::format("a{}", StringConverter::ToString(inValue.value)); + return std::format("a{}", StringConverter::ToString(inValue.value)); } }; @@ -200,7 +200,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Quaternion& inValue) { - return fmt::format( + return std::format( "({}, {}, {}, {})", StringConverter::ToString(inValue.w), StringConverter::ToString(inValue.x), diff --git a/Engine/Source/Common/Include/Common/Math/Rect.h b/Engine/Source/Common/Include/Common/Math/Rect.h index 723859b5..170a0d92 100644 --- a/Engine/Source/Common/Include/Common/Math/Rect.h +++ b/Engine/Source/Common/Include/Common/Math/Rect.h @@ -74,7 +74,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Rect& inValue) { - return fmt::format( + return std::format( "{}min={}, max={}{}", "{", StringConverter>::ToString(inValue.min), diff --git a/Engine/Source/Common/Include/Common/Math/Sphere.h b/Engine/Source/Common/Include/Common/Math/Sphere.h index bdf106ed..da447fb0 100644 --- a/Engine/Source/Common/Include/Common/Math/Sphere.h +++ b/Engine/Source/Common/Include/Common/Math/Sphere.h @@ -62,7 +62,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Sphere& inValue) { - return fmt::format( + return std::format( "{}center={}, radius={}{}", "{", StringConverter>::ToString(inValue.center), diff --git a/Engine/Source/Common/Include/Common/Math/Transform.h b/Engine/Source/Common/Include/Common/Math/Transform.h index 315095dd..5b991b36 100644 --- a/Engine/Source/Common/Include/Common/Math/Transform.h +++ b/Engine/Source/Common/Include/Common/Math/Transform.h @@ -92,7 +92,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Transform& inValue) { - return fmt::format( + return std::format( "{}scale={}, rotation={}, translation={}{}", "{", StringConverter>::ToString(inValue.scale), diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index 746259ba..995b80fa 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -30,13 +30,15 @@ namespace Common { NonCopyable(BinarySerializeStream) virtual ~BinarySerializeStream(); - virtual void Write(const void* data, size_t size) = 0; + template void Write(const T& value); virtual void Seek(int64_t offset) = 0; virtual size_t Loc() = 0; virtual std::endian Endian() = 0; protected: BinarySerializeStream(); + + virtual void WriteInternal(const void* data, size_t size) = 0; }; class BinaryDeserializeStream { @@ -44,13 +46,15 @@ namespace Common { NonCopyable(BinaryDeserializeStream); virtual ~BinaryDeserializeStream(); - virtual void Read(void* data, size_t size) = 0; + template void Read(T& value); virtual void Seek(int64_t offset) = 0; virtual size_t Loc() = 0; virtual std::endian Endian() = 0; protected: BinaryDeserializeStream(); + + virtual void ReadInternal(void* data, size_t size) = 0; }; template @@ -59,12 +63,15 @@ namespace Common { NonCopyable(BinaryFileSerializeStream) explicit BinaryFileSerializeStream(const std::string& inFileName); ~BinaryFileSerializeStream() override; - void Write(const void* data, size_t size) override; + void Seek(int64_t offset) override; size_t Loc() override; std::endian Endian() override; void Close(); + protected: + void WriteInternal(const void* data, size_t size) override; + private: std::ofstream file; }; @@ -75,12 +82,15 @@ namespace Common { NonCopyable(BinaryFileDeserializeStream) explicit BinaryFileDeserializeStream(const std::string& inFileName); ~BinaryFileDeserializeStream() override; - void Read(void* data, size_t size) override; + void Seek(int64_t offset) override; size_t Loc() override; std::endian Endian() override; void Close(); + protected: + void ReadInternal(void* data, size_t size) override; + private: std::ifstream file; size_t fileSize; @@ -92,11 +102,14 @@ namespace Common { NonCopyable(MemorySerializeStream) explicit MemorySerializeStream(std::vector& inBytes, size_t pointerBegin = 0); ~MemorySerializeStream() override; - void Write(const void* data, size_t size) override; + void Seek(int64_t offset) override; size_t Loc() override; std::endian Endian() override; + protected: + void WriteInternal(const void* data, size_t size) override; + private: size_t pointer; std::vector& bytes; @@ -108,11 +121,13 @@ namespace Common { NonCopyable(MemoryDeserializeStream) explicit MemoryDeserializeStream(const std::vector& inBytes, size_t pointerBegin = 0); ~MemoryDeserializeStream() override; - void Read(void* data, size_t size) override; void Seek(int64_t offset) override; std::endian Endian() override; size_t Loc() override; + protected: + void ReadInternal(void* data, size_t size) override; + private: size_t pointer; const std::vector& bytes; @@ -152,13 +167,13 @@ namespace Common { \ static size_t Serialize(BinarySerializeStream& stream, const typeName& value) \ { \ - stream.Write(&value, sizeof(typeName)); \ + stream.Write(value); \ return sizeof(typeName); \ } \ \ static size_t Deserialize(BinaryDeserializeStream& stream, typeName& value) \ { \ - stream.Read(&value, sizeof(typeName)); \ + stream.Read(value); \ return sizeof(typeName); \ } \ }; \ @@ -186,6 +201,26 @@ namespace Common::Internal { } namespace Common { + template + void BinarySerializeStream::Write(const T& value) + { + if (std::endian::native == Endian()) { + WriteInternal(&value, sizeof(T)); + } else { + const auto swapped = Internal::SwapEndian(&value, sizeof(T)); + WriteInternal(reinterpret_cast(swapped.data()), static_cast(swapped.size())); + } + } + + template + void BinaryDeserializeStream::Read(T& value) + { + ReadInternal(&value, sizeof(T)); + if (std::endian::native != Endian()) { + Internal::SwapEndianInplace(&value, sizeof(T)); + } + } + template BinaryFileSerializeStream::BinaryFileSerializeStream(const std::string& inFileName) { @@ -203,14 +238,9 @@ namespace Common { } template - void BinaryFileSerializeStream::Write(const void* data, const size_t size) + void BinaryFileSerializeStream::WriteInternal(const void* data, const size_t size) { - if (std::endian::native == E) { - file.write(static_cast(data), static_cast(size)); - } else { - const auto swapped = Internal::SwapEndian(data, size); - file.write(reinterpret_cast(swapped.data()), static_cast(swapped.size())); - } + file.write(static_cast(data), static_cast(size)); } template @@ -260,13 +290,10 @@ namespace Common { } template - void BinaryFileDeserializeStream::Read(void* data, const size_t size) + void BinaryFileDeserializeStream::ReadInternal(void* data, const size_t size) { Assert(static_cast(file.tellg()) + size <= fileSize); file.read(static_cast(data), static_cast(size)); - if (std::endian::native != E) { - Internal::SwapEndianInplace(data, size); - } } template @@ -312,7 +339,7 @@ namespace Common { MemorySerializeStream::~MemorySerializeStream() = default; template - void MemorySerializeStream::Write(const void* data, const size_t size) + void MemorySerializeStream::WriteInternal(const void* data, const size_t size) { const auto newPointer = pointer + size; if (newPointer > bytes.size()) { @@ -321,12 +348,7 @@ namespace Common { } bytes.resize(newPointer); } - if (std::endian::native == E) { - memcpy(bytes.data() + pointer, data, size); - } else { - const auto swaped = Internal::SwapEndian(data, size); - memcpy(bytes.data() + pointer, swaped.data(), swaped.size()); - } + memcpy(bytes.data() + pointer, data, size); pointer = newPointer; } @@ -360,14 +382,11 @@ namespace Common { MemoryDeserializeStream::~MemoryDeserializeStream() = default; template - void MemoryDeserializeStream::Read(void* data, const size_t size) + void MemoryDeserializeStream::ReadInternal(void* data, const size_t size) { const auto newPointer = pointer + size; Assert(newPointer <= bytes.size()); memcpy(data, bytes.data() + pointer, size); - if (std::endian::native != E) { - Internal::SwapEndianInplace(data, size); - } pointer = newPointer; } @@ -436,6 +455,23 @@ namespace Common { struct Header { size_t typeId; size_t contentSize; + + void Serialize(BinarySerializeStream& stream) const + { + stream.Write(static_cast(typeId)); + stream.Write(static_cast(contentSize)); + } + + void Deserialize(BinaryDeserializeStream& stream) + { + uint64_t tempTypeId; + stream.Read(tempTypeId); + typeId = static_cast(tempTypeId); + + uint64_t tempContentSize; + stream.Read(tempContentSize); + contentSize = static_cast(tempContentSize); + } }; static size_t Serialize(BinarySerializeStream& stream, const T& value) @@ -446,7 +482,7 @@ namespace Common { stream.Seek(sizeof(Header)); header.contentSize = Serializer::Serialize(stream, value); stream.Seek(-static_cast(sizeof(Header)) - static_cast(header.contentSize)); - stream.Write(&header, sizeof(Header)); + header.Serialize(stream); stream.Seek(header.contentSize); return sizeof(Header) + header.contentSize; } @@ -454,7 +490,7 @@ namespace Common { static std::pair Deserialize(BinaryDeserializeStream& stream, T& value) { Header header {}; - stream.Read(&header, sizeof(Header)); + header.Deserialize(stream); if (header.typeId != Serializer::typeId) { stream.Seek(header.contentSize); @@ -493,7 +529,11 @@ namespace Common { const uint64_t size = value.size(); serialized += Serializer::Serialize(stream, size); - stream.Write(value.data(), value.size()); + const auto* data = reinterpret_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Write(data[i]); + } + serialized += size; return serialized; } @@ -506,7 +546,11 @@ namespace Common { deserialized += Serializer::Deserialize(stream, size); value.resize(size); - stream.Read(value.data(), size); + auto* data = reinterpret_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Read(data[i]); + } + deserialized += size; return deserialized; } @@ -515,16 +559,22 @@ namespace Common { template <> struct Serializer { static constexpr size_t typeId = HashUtils::StrCrc32("std::wstring"); + // windows: 16, macOS: 32 + static_assert(sizeof(std::wstring::value_type) <= sizeof(uint32_t)); static size_t Serialize(BinarySerializeStream& stream, const std::wstring& value) { size_t serialized = 0; - const uint64_t size = value.size() * sizeof(std::wstring::value_type); + const uint64_t size = value.size(); serialized += Serializer::Serialize(stream, size); - stream.Write(value.data(), size); - serialized += size; + const auto* data = static_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Write(static_cast(data[i])); + } + + serialized += size * sizeof(uint32_t); return serialized; } @@ -535,9 +585,15 @@ namespace Common { uint64_t size; deserialized += Serializer::Deserialize(stream, size); - value.resize(size / sizeof(std::wstring::value_type)); - stream.Read(value.data(), size); - deserialized += size; + value.resize(size); + auto* data = static_cast(value.data()); + for (auto i = 0; i < size; i++) { + uint32_t tempValue; + stream.Read(tempValue); + data[i] = static_cast(tempValue); + } + + deserialized += size * sizeof(uint32_t); return deserialized; } }; diff --git a/Engine/Source/Common/Include/Common/String.h b/Engine/Source/Common/Include/Common/String.h index 22d42e0c..a67d3fdb 100644 --- a/Engine/Source/Common/Include/Common/String.h +++ b/Engine/Source/Common/Include/Common/String.h @@ -15,9 +15,7 @@ #include #include #include - -#define FMT_HEADER_ONLY 1 -#include +#include #include #include @@ -95,7 +93,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const std::pair& inValue) { - return fmt::format( + return std::format( "{}: {}", StringConverter::ToString(inValue.first), StringConverter::ToString(inValue.second)); diff --git a/Engine/Source/Common/Src/DynamicLibrary.cpp b/Engine/Source/Common/Src/DynamicLibrary.cpp index 6df1a2e4..c6e2c149 100644 --- a/Engine/Source/Common/Src/DynamicLibrary.cpp +++ b/Engine/Source/Common/Src/DynamicLibrary.cpp @@ -2,6 +2,8 @@ // Created by johnk on 28/12/2021. // +#include + #include #include @@ -38,19 +40,17 @@ namespace Common { } DynamicLibrary::DynamicLibrary(DynamicLibrary&& inOther) noexcept - : loaded(inOther.loaded) - , fullPath(std::move(inOther.fullPath)) - , handle(inOther.handle) + : loaded(std::exchange(inOther.loaded, false)) + , fullPath(std::exchange(inOther.fullPath, "")) + , handle(std::exchange(inOther.handle, nullptr)) { - inOther.loaded = false; } DynamicLibrary& DynamicLibrary::operator=(DynamicLibrary&& inOther) noexcept { - loaded = inOther.loaded; - fullPath = std::move(inOther.fullPath); - handle = inOther.handle; - inOther.loaded = false; + loaded = std::exchange(inOther.loaded, false); + fullPath = std::exchange(inOther.fullPath, ""); + handle = std::exchange(inOther.handle, nullptr); return *this; } diff --git a/Engine/Source/Common/Src/Event.cpp b/Engine/Source/Common/Src/Event.cpp new file mode 100644 index 00000000..84430cae --- /dev/null +++ b/Engine/Source/Common/Src/Event.cpp @@ -0,0 +1,5 @@ +// +// Created by johnk on 2024/11/5. +// + +#include diff --git a/Engine/Source/Common/Test/ContainerTest.cpp b/Engine/Source/Common/Test/ContainerTest.cpp index eba61b06..36d12fad 100644 --- a/Engine/Source/Common/Test/ContainerTest.cpp +++ b/Engine/Source/Common/Test/ContainerTest.cpp @@ -6,6 +6,66 @@ #include using namespace Common; +enum class ConstructType : uint8_t { + cDefault, + cCopy, + cMove, + max +}; + +struct CopyAndMoveTest { + ConstructType constructType; + bool copyAssigned; + bool moveAssigned; + + CopyAndMoveTest() + : constructType(ConstructType::cDefault) + , copyAssigned(false) + , moveAssigned(false) + { + } + + CopyAndMoveTest(ConstructType inType, bool inCopyAssigned, bool inMoveAssigned) + : constructType(inType) + , copyAssigned(inCopyAssigned) + , moveAssigned(inMoveAssigned) + { + } + + CopyAndMoveTest(const CopyAndMoveTest& inOther) + : constructType(ConstructType::cCopy) + , copyAssigned(false) + , moveAssigned(false) + { + } + + CopyAndMoveTest(CopyAndMoveTest&& inOther) noexcept + : constructType(ConstructType::cMove) + , copyAssigned(false) + , moveAssigned(false) + { + } + + CopyAndMoveTest& operator=(const CopyAndMoveTest& inOther) + { + copyAssigned = true; + return *this; + } + + CopyAndMoveTest& operator=(CopyAndMoveTest&& inOther) noexcept + { + moveAssigned = true; + return *this; + } + + bool operator==(const CopyAndMoveTest& inOther) const + { + return constructType == inOther.constructType + && copyAssigned == inOther.copyAssigned + && moveAssigned == inOther.moveAssigned; + } +}; + TEST(ContainerTest, VectorSwapDeleteTest) { std::vector vec0 = { 1, 2, 3, 4, 5 }; @@ -44,6 +104,19 @@ TEST(ContainerTest, VectorGetIntersection) ASSERT_EQ(result, (std::vector { 3, 4, 5 })); } +TEST(ContainerTest, VectorGetDifferences) +{ + std::vector a = { 1, 2, 5, 5, 5, 9 }; + std::vector b = { 2, 5, 7 }; + auto result = VectorUtils::GetDifferences(a, b); + ASSERT_EQ(result, (std::vector { 1, 5, 5, 9 })); + + a = { 1, 2, 3, 4, 5 }; + b = { 4, 5, 6, 7, 8 }; + result = VectorUtils::GetDifferences(a, b); + ASSERT_EQ(result, (std::vector { 1, 2, 3 })); +} + TEST(ContainerTest, SetGetIntersection) { const std::unordered_set a = { 1, 2, 3, 4, 5 }; @@ -164,86 +237,26 @@ TEST(ContainerTest, InplaceVectorIter) TEST(ContainerTest, InplaceVectorCopyAndMove) { - enum class ConstructType : uint8_t { - cDefault, - cCopy, - cMove, - max - }; - - struct S0 { - ConstructType constructType; - bool copyAssigned; - bool moveAssigned; - - S0() - : constructType(ConstructType::cDefault) - , copyAssigned(false) - , moveAssigned(false) - { - } - - S0(ConstructType inType, bool inCopyAssigned, bool inMoveAssigned) - : constructType(inType) - , copyAssigned(inCopyAssigned) - , moveAssigned(inMoveAssigned) - { - } - - S0(const S0& inOther) - : constructType(ConstructType::cCopy) - , copyAssigned(false) - , moveAssigned(false) - { - } - - S0(S0&& inOther) noexcept - : constructType(ConstructType::cMove) - , copyAssigned(false) - , moveAssigned(false) - { - } - - S0& operator=(const S0& inOther) - { - copyAssigned = true; - return *this; - } - - S0& operator=(S0&& inOther) noexcept - { - moveAssigned = true; - return *this; - } - - bool operator==(const S0& inOther) const - { - return constructType == inOther.constructType - && copyAssigned == inOther.copyAssigned - && moveAssigned == inOther.moveAssigned; - } - }; - - InplaceVector t0; + InplaceVector t0; t0.EmplaceBack(); t0.EmplaceBack(); ASSERT_EQ(t0[0].constructType, ConstructType::cDefault); ASSERT_EQ(t0[1].constructType, ConstructType::cDefault); - t0.PushBack(S0()); + t0.PushBack(CopyAndMoveTest()); ASSERT_EQ(t0[2].constructType, ConstructType::cMove); - const S0 temp0; + const CopyAndMoveTest temp0; t0.PushBack(temp0); ASSERT_EQ(t0[3].constructType, ConstructType::cCopy); // copy assign - InplaceVector t2; + InplaceVector t2; t2.Resize(2); ASSERT_EQ(t2[0].constructType, ConstructType::cCopy); ASSERT_EQ(t2[1].constructType, ConstructType::cCopy); t2 = t0; - S0 temp1; + CopyAndMoveTest temp1; temp1.constructType = ConstructType::cCopy; temp1.copyAssigned = true; temp1.moveAssigned = false; @@ -254,7 +267,7 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t2[3], temp1); // move assign - InplaceVector t3; + InplaceVector t3; t3.Resize(1); t3 = std::move(t2); temp1.constructType = ConstructType::cCopy; @@ -269,7 +282,7 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t3[3], temp1); // copy construct - InplaceVector t4 = t3; + InplaceVector t4 = t3; temp1.constructType = ConstructType::cCopy; temp1.copyAssigned = false; temp1.moveAssigned = false; @@ -279,7 +292,7 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t4[3], temp1); // move construct - InplaceVector t5 = std::move(t4); + InplaceVector t5 = std::move(t4); temp1.constructType = ConstructType::cMove; temp1.copyAssigned = false; temp1.moveAssigned = false; @@ -288,3 +301,144 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t5[2], temp1); ASSERT_EQ(t5[3], temp1); } + +TEST(ContainerTest, TrunkBasic) +{ + Trunk t0; + ASSERT_TRUE(t0.HasFree()); + ASSERT_TRUE(t0.Empty()); + ASSERT_EQ(t0.Free(), 4); + ASSERT_EQ(t0.Allocated(), 0); + ASSERT_EQ(t0.Capacity(), 4); // NOLINT + + const size_t v0 = t0.Emplace(1); + ASSERT_TRUE(t0.HasFree()); + ASSERT_FALSE(t0.Empty()); + ASSERT_EQ(t0.Free(), 3); + ASSERT_EQ(t0.Allocated(), 1); + ASSERT_EQ(t0[v0], 1); + + const size_t v1 = t0.Emplace(2); + ASSERT_TRUE(t0.HasFree()); + ASSERT_FALSE(t0.Empty()); + ASSERT_EQ(t0.Free(), 2); + ASSERT_EQ(t0.Allocated(), 2); + ASSERT_EQ(t0[v1], 2); + + t0.Erase(v0); + ASSERT_EQ(t0.Free(), 3); + ASSERT_EQ(t0.Allocated(), 1); + + const size_t v2 = t0.Emplace(3); + ASSERT_EQ(t0.Free(), 2); + ASSERT_EQ(t0.Allocated(), 2); + ASSERT_EQ(v0, v2); + ASSERT_EQ(t0[v2], 3); +} + +TEST(ContainerTest, TrunkEachTest) +{ + Trunk t0; + constexpr auto count = 2; + for (auto i = 0; i < count; i++) { + t0.Emplace(i + 1); + } + + int i = 0; + t0.Each([&](auto elem) -> void { + ASSERT_EQ(elem, ++i); + }); + ASSERT_EQ(i, 2); +} + +TEST(ContainerTest, TrunkCopyAndMove) +{ + Trunk t0; + t0.Emplace(); + t0.Emplace(); + ASSERT_EQ(t0[0].constructType, ConstructType::cDefault); + ASSERT_EQ(t0[1].constructType, ConstructType::cDefault); + + t0.Emplace(CopyAndMoveTest()); + ASSERT_EQ(t0[2].constructType, ConstructType::cMove); + + CopyAndMoveTest temp0; + t0.Emplace(temp0); + ASSERT_EQ(t0[3].constructType, ConstructType::cCopy); + + // copy assign + Trunk t1; + t1.Emplace(); + t1 = t0; + ASSERT_EQ(t1.Allocated(), 4); + ASSERT_TRUE(t1[0].copyAssigned); + ASSERT_TRUE(!t1[1].copyAssigned && t1[1].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t1[2].copyAssigned && t1[2].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t1[3].copyAssigned && t1[3].constructType == ConstructType::cCopy); + + Trunk t2; + t2.Emplace(); + t2.Emplace(); + t2.Emplace(); + t2.Emplace(); + t2.Emplace(); + t2 = t0; + ASSERT_EQ(t2.Allocated(), 4); + ASSERT_TRUE(t2[0].copyAssigned); + ASSERT_TRUE(t2[0].copyAssigned); + ASSERT_TRUE(t2[0].copyAssigned); + ASSERT_TRUE(t2[0].copyAssigned); + + // move assign + Trunk t3; + t3.Emplace(); + t3 = std::move(t1); + ASSERT_EQ(t3.Allocated(), 4); + ASSERT_TRUE(t3[0].moveAssigned); + ASSERT_TRUE(!t3[1].moveAssigned && t3[1].constructType == ConstructType::cMove); + ASSERT_TRUE(!t3[2].moveAssigned && t3[2].constructType == ConstructType::cMove); + ASSERT_TRUE(!t3[3].moveAssigned && t3[3].constructType == ConstructType::cMove); + + // copy ctor + Trunk t4(t3); + ASSERT_EQ(t4.Allocated(), 4); + ASSERT_TRUE(!t4[0].copyAssigned && t4[0].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t4[1].copyAssigned && t4[1].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t4[2].copyAssigned && t4[2].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t4[3].copyAssigned && t4[3].constructType == ConstructType::cCopy); + + // move ctor + Trunk t5(std::move(t4)); + ASSERT_EQ(t5.Allocated(), 4); + ASSERT_TRUE(!t5[0].moveAssigned && t5[0].constructType == ConstructType::cMove); + ASSERT_TRUE(!t5[1].moveAssigned && t5[1].constructType == ConstructType::cMove); + ASSERT_TRUE(!t5[2].moveAssigned && t5[2].constructType == ConstructType::cMove); + ASSERT_TRUE(!t5[3].moveAssigned && t5[3].constructType == ConstructType::cMove); +} + +TEST(ContainerTest, TrunkListBasic) +{ + TrunkList t0; + const auto i0 = t0.Emplace(1); + t0.Emplace(2); + t0.Emplace(3); + ASSERT_EQ(t0.Allocated(), 3); + ASSERT_EQ(t0.Free(), 1); + ASSERT_EQ(t0.Capacity(), 4); + + t0.Emplace(4); + t0.Emplace(5); + ASSERT_EQ(t0.Allocated(), 5); + ASSERT_EQ(t0.Free(), 3); + ASSERT_EQ(t0.Capacity(), 8); + + t0.Erase(i0); + ASSERT_EQ(t0.Allocated(), 4); + ASSERT_EQ(t0.Free(), 4); + ASSERT_EQ(t0.Capacity(), 8); + + int count = 2; + t0.Each([&](auto elem) -> void { + ASSERT_EQ(elem, count++); + }); +} diff --git a/Engine/Source/Common/Test/EventTest.cpp b/Engine/Source/Common/Test/EventTest.cpp new file mode 100644 index 00000000..fd94a5da --- /dev/null +++ b/Engine/Source/Common/Test/EventTest.cpp @@ -0,0 +1,43 @@ +// +// Created by johnk on 2024/11/5. +// + +#include + +static int counter = 0; + +static void StaticReceiver(int a, bool b) +{ + counter++; + ASSERT_EQ(a, 1); + ASSERT_EQ(b, true); +} + +class Receiver { +public: + Receiver() = default; + + void Receive(int a, bool b) // NOLINT + { + counter++; + ASSERT_EQ(a, 1); + ASSERT_EQ(b, true); + } +}; + +TEST(EventTest, BasicTest) +{ + Receiver receiver; + + Event event; + ASSERT_EQ(event.BindStatic<&StaticReceiver>(), 0); + ASSERT_EQ(event.BindMember<&Receiver::Receive>(receiver), 1); + ASSERT_EQ(event.BindLambda([](int a, bool b) -> void { + counter++; + ASSERT_EQ(a, 1); + ASSERT_EQ(b, true); + }), 2); + + event.Broadcast(1, true); + ASSERT_EQ(counter, 3); +} diff --git a/Engine/Source/Common/Test/MathTest.cpp b/Engine/Source/Common/Test/MathTest.cpp index bc571298..e66d9634 100644 --- a/Engine/Source/Common/Test/MathTest.cpp +++ b/Engine/Source/Common/Test/MathTest.cpp @@ -674,27 +674,27 @@ TEST(MathTest, ToStringTest) // mat ASSERT_EQ( ToString(HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f)), - fmt::format("({}, {}, {}, {}, {}, {})", + std::format("({}, {}, {}, {}, {}, {})", std::to_string(2.0f), std::to_string(3.0f), std::to_string(4.0f), std::to_string(5.0f), std::to_string(6.0f), std::to_string(7.0f))); // angle/radian - ASSERT_EQ(ToString(FAngle(75.0f)), fmt::format("a{}", std::to_string(75.0f))); + ASSERT_EQ(ToString(FAngle(75.0f)), std::format("a{}", std::to_string(75.0f))); ASSERT_EQ(ToString(FRadian(1.5f * pi)), std::to_string(1.5f * pi)); // quaternion ASSERT_EQ( ToString(FQuat(1.0f, 0.1f, 0.2f, 0.5f)), - fmt::format("({}, {}, {}, {})", + std::format("({}, {}, {}, {})", std::to_string(1.0f), std::to_string(0.1f), std::to_string(0.2f), std::to_string(0.5f))); // color ASSERT_EQ( ToString(Color(1, 2, 3, 1)), - fmt::format("{}r={}, g={}, b={}, a={}{}", "{", 1, 2, 3, 1, "}")); + std::format("{}r={}, g={}, b={}, a={}{}", "{", 1, 2, 3, 1, "}")); ASSERT_EQ( ToString(LinearColor(1.0f, 0.5f, 0.2f, 1.0f)), - fmt::format("{}r={}, g={}, b={}, a={}{}", + std::format("{}r={}, g={}, b={}, a={}{}", "{", std::to_string(1.0f), std::to_string(0.5f), std::to_string(0.2f), std::to_string(1.0f), @@ -703,7 +703,7 @@ TEST(MathTest, ToStringTest) // react ASSERT_EQ( ToString(FRect(1.0f, 2.0f, 3.0f, 4.0f)), - fmt::format("{}min=({}, {}), max=({}, {}){}", + std::format("{}min=({}, {}), max=({}, {}){}", "{", std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(4.0f), @@ -712,7 +712,7 @@ TEST(MathTest, ToStringTest) // box ASSERT_EQ( ToString(FBox(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f)), - fmt::format("{}min=({}, {}, {}), max=({}, {}, {}){}", + std::format("{}min=({}, {}, {}), max=({}, {}, {}){}", "{", std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(4.0f), std::to_string(5.0f), std::to_string(6.0f), @@ -721,7 +721,7 @@ TEST(MathTest, ToStringTest) // sphere ASSERT_EQ( ToString(FSphere(1.0f, 2.0f, 3.0f, 1.0f)), - fmt::format("{}center=({}, {}, {}), radius={}{}", + std::format("{}center=({}, {}, {}), radius={}{}", "{", std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(1.0f), "}")); @@ -729,7 +729,7 @@ TEST(MathTest, ToStringTest) // transform ASSERT_EQ( ToString(FTransform(FVec3(2.0f, 2.0f, 2.0f), FQuat(0.5f, 0.2f, 0.1f, 0.3f), FVec3(1.0f, 2.0f, 3.0f))), - fmt::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", + std::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", "{", std::to_string(2.0f), std::to_string(2.0f), std::to_string(2.0f), std::to_string(0.5f), std::to_string(0.2f), std::to_string(0.1f), std::to_string(0.3f), @@ -739,7 +739,7 @@ TEST(MathTest, ToStringTest) // view transform ASSERT_EQ( ToString(FViewTransform(FQuat(0.5f, 0.2f, 0.1f, 0.3f), FVec3(1.0f, 2.0f, 3.0f))), - fmt::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", + std::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", "{", std::to_string(1.0f), std::to_string(1.0f), std::to_string(1.0f), std::to_string(0.5f), std::to_string(0.2f), std::to_string(0.1f), std::to_string(0.3f), @@ -749,13 +749,13 @@ TEST(MathTest, ToStringTest) // projection ASSERT_EQ( ToString(FReversedZOrthoProjection(1024.0f, 768.0f, 1.0f, 500.0f)), - fmt::format("{}width={}, height={}, near={}, far={}{}", + std::format("{}width={}, height={}, near={}, far={}{}", "{", std::to_string(1024.0f), std::to_string(768.0f), std::to_string(1.0f), std::to_string(500.0f), "}")); ASSERT_EQ( ToString(FReversedZPerspectiveProjection(90.0f, 1024.0f, 768.0f, 1.0f, 500.0f)), - fmt::format("{}fov={}, width={}, height={}, near={}, far={}{}", + std::format("{}fov={}, width={}, height={}, near={}, far={}{}", "{", std::to_string(90.0f), std::to_string(1024.0f), std::to_string(768.0f), std::to_string(1.0f), std::to_string(500.0f), "}")); @@ -767,22 +767,22 @@ TEST(MathTest, JsonSerializationTest) PerformJsonSerializationTest(HFloat(1.0f), FltToJson(1.0f)); // vec - PerformJsonSerializationTest(FVec1(1.0f), fmt::format("[{}]", FltToJson(1.0f))); - PerformJsonSerializationTest(HVec2(2.0f, 3.0f), fmt::format("[{},{}]", FltToJson(2.0f), FltToJson(3.0f))); + PerformJsonSerializationTest(FVec1(1.0f), std::format("[{}]", FltToJson(1.0f))); + PerformJsonSerializationTest(HVec2(2.0f, 3.0f), std::format("[{},{}]", FltToJson(2.0f), FltToJson(3.0f))); PerformJsonSerializationTest(IVec3(1, 2, 3), "[1,2,3]"); PerformJsonSerializationTest(UVec4(1, 2, 3, 4), "[1,2,3,4]"); // mat - PerformJsonSerializationTest(FMat1x1(1.0f), fmt::format("[{}]", FltToJson(1.0f))); + PerformJsonSerializationTest(FMat1x1(1.0f), std::format("[{}]", FltToJson(1.0f))); PerformJsonSerializationTest( HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f), - fmt::format("[{},{},{},{},{},{}]", FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), FltToJson(7.0f))); + std::format("[{},{},{},{},{},{}]", FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), FltToJson(7.0f))); PerformJsonSerializationTest( IMat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), "[1,2,3,4,5,6,7,8,9,10,11,12]"); PerformJsonSerializationTest( FMat4x4(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f), - fmt::format("[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]", + std::format("[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), FltToJson(7.0f), FltToJson(8.0f), FltToJson(9.0f), FltToJson(10.0f), FltToJson(11.0f), FltToJson(12.0f), @@ -793,13 +793,13 @@ TEST(MathTest, JsonSerializationTest) PerformJsonSerializationTest(FRadian(1.0f), FltToJson(1.0f)); // quaternion - PerformJsonSerializationTest(FQuat(1.0f, 0.1f, 0.2f, 0.5f), fmt::format("[{},{},{},{}]", FltToJson(1.0f), FltToJson(0.1f), FltToJson(0.2f), FltToJson(0.5f))); + PerformJsonSerializationTest(FQuat(1.0f, 0.1f, 0.2f, 0.5f), std::format("[{},{},{},{}]", FltToJson(1.0f), FltToJson(0.1f), FltToJson(0.2f), FltToJson(0.5f))); // color PerformJsonSerializationTest(Color(1, 2, 3, 1), R"({"r":1,"g":2,"b":3,"a":1})"); PerformJsonSerializationTest( LinearColor(1.0f, 0.5f, 0.2f, 1.0f), - fmt::format(R"({}"r":{},"g":{},"b":{},"a":{}{})", + std::format(R"({}"r":{},"g":{},"b":{},"a":{}{})", "{", FltToJson(1.0f), FltToJson(0.5f), FltToJson(0.2f), FltToJson(1.0f), "}")); @@ -807,7 +807,7 @@ TEST(MathTest, JsonSerializationTest) // rect PerformJsonSerializationTest( FRect(1.0f, 2.0f, 3.0f, 4.0f), - fmt::format(R"({}"min":[{},{}],"max":[{},{}]{})", + std::format(R"({}"min":[{},{}],"max":[{},{}]{})", "{", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), @@ -816,7 +816,7 @@ TEST(MathTest, JsonSerializationTest) // box PerformJsonSerializationTest( FBox(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f), - fmt::format(R"({}"min":[{},{},{}],"max":[{},{},{}]{})", + std::format(R"({}"min":[{},{},{}],"max":[{},{},{}]{})", "{", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), @@ -825,7 +825,7 @@ TEST(MathTest, JsonSerializationTest) // sphere PerformJsonSerializationTest( FSphere(1.0f, 2.0f, 3.0f, 1.0f), - fmt::format(R"({}"center":[{},{},{}],"radius":{}{})", + std::format(R"({}"center":[{},{},{}],"radius":{}{})", "{", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(1.0f), @@ -835,7 +835,7 @@ TEST(MathTest, JsonSerializationTest) const FTransform transform(FVec3(2.0f, 2.0f, 2.0f), FQuat(1.0f, 0.2f, 0.3f, 0.4f), FVec3(1.0f, 2.0f, 3.0f)); PerformJsonSerializationTest( transform, - fmt::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", + std::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", "{", FltToJson(2.0f), FltToJson(2.0f), FltToJson(2.0f), FltToJson(1.0f), FltToJson(0.2f), FltToJson(0.3f), FltToJson(0.4f), @@ -845,7 +845,7 @@ TEST(MathTest, JsonSerializationTest) // view transform PerformJsonSerializationTest( FViewTransform(transform), - fmt::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", + std::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", "{", FltToJson(2.0f), FltToJson(2.0f), FltToJson(2.0f), FltToJson(1.0f), FltToJson(0.2f), FltToJson(0.3f), FltToJson(0.4f), @@ -855,13 +855,13 @@ TEST(MathTest, JsonSerializationTest) // projection PerformJsonSerializationTest( FReversedZOrthoProjection(512.0f, 1024.0f, 1.0f), - fmt::format(R"({}"width":{},"height":{},"near":{},"far":{}{})", + std::format(R"({}"width":{},"height":{},"near":{},"far":{}{})", "{", FltToJson(512.0f), FltToJson(1024.0f), FltToJson(1.0f), "null", "}")); PerformJsonSerializationTest( FReversedZPerspectiveProjection(90.0f, 512.0f, 1024.0f, 1.0f, 500.0f), - fmt::format(R"({}"fov":{},"width":{},"height":{},"near":{},"far":{}{})", + std::format(R"({}"fov":{},"width":{},"height":{},"near":{},"far":{}{})", "{", FltToJson(90.0f), FltToJson(512.0f), FltToJson(1024.0f), FltToJson(1.0f), FltToJson(500.0f), "}")); diff --git a/Engine/Source/Common/Test/SerializationTest.cpp b/Engine/Source/Common/Test/SerializationTest.cpp index 55f9d019..32bd7819 100644 --- a/Engine/Source/Common/Test/SerializationTest.cpp +++ b/Engine/Source/Common/Test/SerializationTest.cpp @@ -19,7 +19,7 @@ TEST(SerializationTest, FileStreamTest) BinaryFileSerializeStream stream(fileName.string()); stream.Seek(3); - stream.Write(&value, sizeof(uint32_t)); + stream.Write(value); } { @@ -27,7 +27,7 @@ TEST(SerializationTest, FileStreamTest) BinaryFileDeserializeStream stream(fileName.string()); stream.Seek(3); - stream.Read(&value, sizeof(uint32_t)); + stream.Read(value); ASSERT_EQ(value, 5); } } @@ -42,14 +42,14 @@ TEST(SerializationTest, ByteStreamTest) const uint32_t value = 5; // NOLINT MemorySerializeStream stream(memory); stream.Seek(3); - stream.Write(&value, sizeof(uint32_t)); + stream.Write(value); } { uint32_t value; MemoryDeserializeStream stream(memory); stream.Seek(3); - stream.Read(&value, sizeof(uint32_t)); + stream.Read(value); ASSERT_EQ(value, 5); } } diff --git a/Engine/Source/Common/Test/SerializationTest.h b/Engine/Source/Common/Test/SerializationTest.h index b0eca051..120a022d 100644 --- a/Engine/Source/Common/Test/SerializationTest.h +++ b/Engine/Source/Common/Test/SerializationTest.h @@ -25,8 +25,8 @@ inline std::string FltToJson(float value) template void PerformTypedSerializationTestWithStream( - const std::function()>& createSerializeStream, - const std::function()>& createDeserializeStream, + const std::function()>& createSerializeStream, + const std::function()>& createDeserializeStream, const T& inValue) { { @@ -50,14 +50,14 @@ void PerformTypedSerializationTestWithEndian(const T& inValue) std::filesystem::create_directories(fileName.parent_path()); PerformTypedSerializationTestWithStream( - []() -> Common::UniqueRef { return { new BinaryFileSerializeStream(fileName.string()) }; }, - []() -> Common::UniqueRef { return { new BinaryFileDeserializeStream(fileName.string()) }; }, + []() -> Common::UniqueRef { return { new Common::BinaryFileSerializeStream(fileName.string()) }; }, + []() -> Common::UniqueRef { return { new Common::BinaryFileDeserializeStream(fileName.string()) }; }, inValue); std::vector buffer; PerformTypedSerializationTestWithStream( - [&]() -> Common::UniqueRef { return { new MemorySerializeStream(buffer) }; }, - [&]() -> Common::UniqueRef { return { new MemoryDeserializeStream(buffer) }; }, + [&]() -> Common::UniqueRef { return { new Common::MemorySerializeStream(buffer) }; }, + [&]() -> Common::UniqueRef { return { new Common::MemoryDeserializeStream(buffer) }; }, inValue); } diff --git a/Engine/Source/Core/Src/Module.cpp b/Engine/Source/Core/Src/Module.cpp index dee1a5e1..19d70606 100644 --- a/Engine/Source/Core/Src/Module.cpp +++ b/Engine/Source/Core/Src/Module.cpp @@ -151,7 +151,7 @@ namespace Core { if (auto extension = path.extension().string(); (extension == ".dll" || extension == ".so" || extension == ".dylib") - && (fileName == fmt::format("{}{}", moduleName, extension) || fileName == fmt::format("lib{}{}", moduleName, extension))) + && (fileName == std::format("{}{}", moduleName, extension) || fileName == std::format("lib{}{}", moduleName, extension))) { return path.string(); } diff --git a/Engine/Source/Mirror/Include/Mirror/Meta.h b/Engine/Source/Mirror/Include/Mirror/Meta.h index 39bb2e22..ebfbad28 100644 --- a/Engine/Source/Mirror/Include/Mirror/Meta.h +++ b/Engine/Source/Mirror/Include/Mirror/Meta.h @@ -5,10 +5,10 @@ #pragma once #if __clang__ -#define EProperty(...) __attribute__((annotate("property;" #__VA_ARGS__))) -#define EFunc(...) __attribute__((annotate("func;" #__VA_ARGS__))) -#define EClass(...) __attribute__((annotate("class;" #__VA_ARGS__))) -#define EEnum(...) __attribute__((annotate("enum;" #__VA_ARGS__))) +#define EProperty(...) __attribute__((annotate("property," #__VA_ARGS__))) +#define EFunc(...) __attribute__((annotate("func," #__VA_ARGS__))) +#define EClass(...) __attribute__((annotate("class," #__VA_ARGS__))) +#define EEnum(...) __attribute__((annotate("enum," #__VA_ARGS__))) #define EMeta(...) __attribute__((annotate(#__VA_ARGS__))) #else #define EProperty(...) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 8f2d8875..12ff4fe2 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -48,6 +48,7 @@ namespace Mirror { const uint32_t isLValueReference : 1; const uint32_t isLValueConstReference : 1; const uint32_t isRValueReference : 1; + const uint32_t isReference : 1; const uint32_t isPointer : 1; const uint32_t isConstPointer : 1; const uint32_t isClass : 1; @@ -84,10 +85,15 @@ namespace Mirror { class Any; + using TemplateViewId = uint32_t; + using TemplateViewRttiPtr = const void*; + struct AnyRtti { using DetorFunc = void(void*) noexcept; using CopyConstructFunc = void(void*, const void*); using MoveConstructFunc = void(void*, void*) noexcept; + using CopyAssignFunc = void(void*, const void*); + using MoveAssignFunc = void(void*, void*) noexcept; using EqualFunc = bool(const void*, const void*); using GetTypeInfoFunc = const TypeInfo*(); using GetPtrFunc = Any(void*); @@ -98,10 +104,13 @@ namespace Mirror { using JsonSerializeFunc = void(const void*, rapidjson::Value&, rapidjson::Document::AllocatorType&); using JsonDeserializeFunc = void(void*, const rapidjson::Value&); using ToStringFunc = std::string(const void*); + using GetTemplateViewRttiFunc = std::pair(); template static void Detor(void* inThis) noexcept; template static void CopyConstruct(void* inThis, const void* inOther); template static void MoveConstruct(void* inThis, void* inOther) noexcept; + template static void CopyAssign(void* inThis, const void* inOther); + template static void MoveAssign(void* inThis, void* inOther) noexcept; template static bool Equal(const void* inThis, const void* inOther) noexcept; template static const TypeInfo* GetValueType(); template static const TypeInfo* GetConstValueType(); @@ -118,10 +127,13 @@ namespace Mirror { template static void JsonSerialize(const void* inThis, rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator); template static void JsonDeserialize(void* inThis, const rapidjson::Value& inJsonValue); template static std::string ToString(const void* inThis); + template static std::pair GetTemplateViewRtti(); DetorFunc* detor; CopyConstructFunc* copyConstruct; MoveConstructFunc* moveConstruct; + CopyAssignFunc* copyAssign; + MoveAssignFunc* moveAssign; EqualFunc* equal; GetTypeInfoFunc* getValueType; GetTypeInfoFunc* getConstValueType; @@ -138,6 +150,7 @@ namespace Mirror { JsonSerializeFunc* jsonSerialize; JsonDeserializeFunc* jsonDeserialize; ToStringFunc* toString; + GetTemplateViewRttiFunc* getTemplateViewRtti; }; template @@ -145,6 +158,8 @@ namespace Mirror { &AnyRtti::Detor, &AnyRtti::CopyConstruct, &AnyRtti::MoveConstruct, + &AnyRtti::CopyAssign, + &AnyRtti::MoveAssign, &AnyRtti::Equal, &AnyRtti::GetValueType, &AnyRtti::GetConstValueType, @@ -160,7 +175,20 @@ namespace Mirror { &AnyRtti::Deserialize, &AnyRtti::JsonSerialize, &AnyRtti::JsonDeserialize, - &AnyRtti::ToString + &AnyRtti::ToString, + &AnyRtti::GetTemplateViewRtti + }; + + template + struct TemplateViewRttiGetter { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + template + concept ValidTemplateView = requires(T object) + { + { T::id } -> std::convertible_to; }; class MIRROR_API Any { @@ -183,9 +211,10 @@ namespace Mirror { template Any(std::reference_wrapper&& inArrayRef); // NOLINT template Any(const std::reference_wrapper& inArrayRef); // NOLINT + // NOTICE: Any::operator=() is designed to reset this and re-construct from new value + // if you want to call assign operator, use CopyAssign() and MoveAssign() instead. Any& operator=(const Any& inOther); Any& operator=(Any&& inOther) noexcept; - template Any& operator=(T&& inValue); template Any& operator=(std::reference_wrapper& inRef); template Any& operator=(std::reference_wrapper&& inRef); @@ -196,6 +225,16 @@ namespace Mirror { template Any& operator=(std::reference_wrapper&& inArrayRef); // NOLINT template Any& operator=(const std::reference_wrapper& inArrayRef); // NOLINT + Any& CopyAssign(Any& inOther); + Any& CopyAssign(const Any& inOther); + Any& MoveAssign(Any& inOther) noexcept; + Any& MoveAssign(const Any& inOther) noexcept; + const Any& CopyAssign(Any& inOther) const; + const Any& CopyAssign(const Any& inOther) const; + const Any& MoveAssign(Any& inOther) const noexcept; + const Any& MoveAssign(const Any& inOther) const noexcept; + // TODO rvalue version CopyAssign/MoveAssign + template bool Convertible(); template bool Convertible() const; @@ -206,6 +245,9 @@ namespace Mirror { template T PolyAs(); template T PolyAs() const; + template bool CanAsTemplateView() const; + TemplateViewRttiPtr GetTemplateViewRtti() const; + bool IsArray() const; Any At(uint32_t inIndex); Any At(uint32_t inIndex) const; @@ -289,11 +331,12 @@ namespace Mirror { template void ConstructFromArrayValue(T (&inValue)[N]); template void ConstructFromArrayValue(T (&&inValue)[N]); template void ConstructFromArrayRef(std::reference_wrapper inRef); - void PerformCopyConstruct(const Any& inOther); void PerformCopyConstructWithPolicy(const Any& inOther, AnyPolicy inPolicy); void PerformCopyConstructForElementWithPolicy(const Any& inOther, AnyPolicy inPolicy, uint32_t inIndex); - void PerformMoveConstruct(Any&& inOther); + void PerformMoveConstruct(Any&& inOther) noexcept; + void PerformCopyAssign(const Any& inOther) const; + void PerformMoveAssign(const Any& inOther) const noexcept; uint32_t ElementNum() const; uint32_t arrayLength; @@ -319,6 +362,9 @@ namespace Mirror { template T As() const; + template bool CanAsTemplateView() const; + TemplateViewRttiPtr GetTemplateViewRtti() const; + bool IsMemoryHolder() const; bool IsRef() const; bool IsNonConstRef() const; @@ -328,6 +374,8 @@ namespace Mirror { const TypeInfo* AddPointerType() const; const TypeInfo* RemovePointerType() const; + // TODO more proxy func + private: template decltype(auto) Delegate(F&& inFunc) const; @@ -336,6 +384,13 @@ namespace Mirror { using ArgumentList = std::vector; + template Any ForwardAsAny(T&& value); + template Argument ForwardAsArg(T&& value); + template ArgumentList ForwardAsArgList(Args&&... args); + template Any ForwardAsAnyByValue(T&& value); + template Argument ForwardAsArgByValue(T&& value); + template ArgumentList ForwardAsArgListByValue(Args&&... args); + struct MIRROR_API Id { static Id null; @@ -384,6 +439,13 @@ namespace Mirror { std::unordered_map metas; }; + enum class FieldAccess : uint8_t { + faPrivate, + faProtected, + faPublic, + max + }; + class MIRROR_API Variable final : public ReflNode { public: ~Variable() override; @@ -394,6 +456,7 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; const Class* GetOwner() const; + FieldAccess GetAccess() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& inArgument) const; Any GetDyn() const; @@ -410,6 +473,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; size_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -419,6 +483,7 @@ namespace Mirror { explicit Variable(ConstructParams&& params); Id owner; + FieldAccess access; size_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -432,6 +497,7 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; const Class* GetOwner() const; + FieldAccess GetAccess() const; template Any Invoke(Args&&... args) const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; @@ -450,6 +516,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -459,6 +526,7 @@ namespace Mirror { explicit Function(ConstructParams&& params); Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -471,10 +539,12 @@ namespace Mirror { template Any Construct(Args&&... args) const; template Any New(Args&&... args) const; + template Any InplaceNew(Args&&... args) const; const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; uint8_t GetArgsNum() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; const std::vector& GetArgTypeInfos() const; @@ -485,6 +555,7 @@ namespace Mirror { Any ConstructDyn(const ArgumentList& arguments) const; Any NewDyn(const ArgumentList& arguments) const; + Any InplaceNewDyn(void* ptr, const ArgumentList& arguments) const; private: friend class Registry; @@ -492,39 +563,47 @@ namespace Mirror { template friend class ClassRegistry; using Invoker = std::function; + using InplaceInvoker = std::function; struct ConstructParams { Id id; Id owner; + FieldAccess access; uint8_t argsNum; std::vector argTypeInfos; std::vector argRemoveRefTypeInfos; std::vector argRemovePointerTypeInfos; Invoker stackConstructor; Invoker heapConstructor; + InplaceInvoker inplaceConstructor; }; explicit Constructor(ConstructParams&& params); Id owner; + FieldAccess access; uint8_t argsNum; std::vector argTypeInfos; std::vector argRemoveRefTypeInfos; std::vector argRemovePointerTypeInfos; Invoker stackConstructor; Invoker heapConstructor; + InplaceInvoker inplaceConstructor; }; class MIRROR_API Destructor final : public ReflNode { public: ~Destructor() override; - template void Invoke(C&& object) const; + template void Destruct(C&& object) const; + template void Delete(C* object) const; const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; - void InvokeDyn(const Argument& argument) const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; + void DestructDyn(const Argument& argument) const; + void DeleteDyn(const Argument& argument) const; private: friend class Registry; @@ -535,13 +614,17 @@ namespace Mirror { struct ConstructParams { Id owner; + FieldAccess access; Invoker destructor; + Invoker deleter; }; explicit Destructor(ConstructParams&& params); Id owner; + FieldAccess access; Invoker destructor; + Invoker deleter; }; class MIRROR_API MemberVariable final : public ReflNode { @@ -553,8 +636,9 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; - uint32_t SizeOf() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; + size_t SizeOf() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& object, const Argument& value) const; Any GetDyn(const Argument& object) const; @@ -570,7 +654,8 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; - uint32_t memorySize; + FieldAccess access; + size_t memorySize; const TypeInfo* typeInfo; Setter setter; Getter getter; @@ -579,7 +664,8 @@ namespace Mirror { explicit MemberVariable(ConstructParams&& params); Id owner; - uint32_t memorySize; + FieldAccess access; + size_t memorySize; const TypeInfo* typeInfo; Setter setter; Getter getter; @@ -593,7 +679,8 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; @@ -609,6 +696,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -618,6 +706,7 @@ namespace Mirror { explicit MemberFunction(ConstructParams&& params); Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -677,14 +766,19 @@ namespace Mirror { ~Class() override; - template Any Construct(Args&&... args); - template Any New(Args&&... args); + template Any Construct(Args&&... args) const; + template Any New(Args&&... args) const; + template Any InplaceNew(void* ptr, Args&&... args) const; + template void Destruct(C&& object) const; + template void Delete(C* object) const; + Any InplaceGetObject(void* ptr) const; void ForEachStaticVariable(const VariableTraverser& func) const; void ForEachStaticFunction(const FunctionTraverser& func) const; void ForEachMemberVariable(const MemberVariableTraverser& func) const; void ForEachMemberFunction(const MemberFunctionTraverser& func) const; const TypeInfo* GetTypeInfo() const; + size_t SizeOf() const; bool HasDefaultConstructor() const; const Class* GetBaseClass() const; bool IsBaseOf(const Class* derivedClass) const; @@ -715,6 +809,9 @@ namespace Mirror { Any ConstructDyn(const ArgumentList& arguments) const; Any NewDyn(const ArgumentList& arguments) const; + Any InplaceNewDyn(void* ptr, const ArgumentList& arguments) const; + void DestructDyn(const Argument& argument) const; + void DeleteDyn(const Argument& argument) const; private: static std::unordered_map typeToIdMap; @@ -723,11 +820,14 @@ namespace Mirror { template friend class ClassRegistry; using BaseClassGetter = std::function; + using InplaceGetter = std::function; struct ConstructParams { Id id; const TypeInfo* typeInfo; + size_t memorySize; BaseClassGetter baseClassGetter; + InplaceGetter inplaceGetter; std::function defaultObjectCreator; std::optional destructorParams; std::optional defaultConstructorParams; @@ -744,7 +844,9 @@ namespace Mirror { MemberFunction& EmplaceMemberFunction(const Id& inId, MemberFunction::ConstructParams&& inParams); const TypeInfo* typeInfo; + size_t memorySize; BaseClassGetter baseClassGetter; + InplaceGetter inplaceGetter; Any defaultObject; std::optional destructor; std::unordered_map constructors; @@ -854,6 +956,652 @@ namespace Mirror { }; } +namespace Mirror { + // ---------------- begin std::optional ---------------- + struct StdOptionalViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdOptionalView"); + + using GetElementTypeFunc = const TypeInfo*(); + using HasValueFunc = bool(const Argument&); + using GetValueFunc = Any(const Argument&); + + template static const TypeInfo* GetElementType(); + template static bool HasValue(const Argument& inArg); + template static Any GetValue(const Argument& inArg); + + GetElementTypeFunc* getElementType; + HasValueFunc* hasValue; + GetValueFunc* getValue; + }; + + template + static constexpr StdOptionalViewRtti stdOptionalViewRttiImpl = { + &StdOptionalViewRtti::GetElementType, + &StdOptionalViewRtti::HasValue, + &StdOptionalViewRtti::GetValue + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdOptionalView { + public: + static constexpr TemplateViewId id = StdOptionalViewRtti::id; + + explicit StdOptionalView(const Argument& inObj); + NonCopyable(StdOptionalView) + NonMovable(StdOptionalView) + + const TypeInfo* ElementType() const; + bool HasValue() const; + Any Value() const; + + private: + const Argument& obj; + const StdOptionalViewRtti* rtti; + }; + // ---------------- end std::optional-- ---------------- + + // ---------------- begin std::pair ----------------- + struct StdPairViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdPairView"); + + using GetKeyTypeFunc = const TypeInfo*(); + using GetValueTypeFunc = const TypeInfo*(); + using GetKeyFunc = Any(const Argument&); + using GetValueFunc = Any(const Argument&); + + template static const TypeInfo* GetKeyType(); + template static const TypeInfo* GetValueType(); + template static Any GetKey(const Argument& inObj); + template static Any GetValue(const Argument& inObj); + template static Any GetConstKey(const Argument& inObj); + template static Any GetConstValue(const Argument& inObj); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + GetKeyFunc* getKey; + GetValueFunc* getValue; + GetKeyFunc* getConstKey; + GetValueFunc* getConstValue; + }; + + template + static constexpr StdPairViewRtti stdPairViewRttiImpl = { + &StdPairViewRtti::GetKeyType, + &StdPairViewRtti::GetValueType, + &StdPairViewRtti::GetKey, + &StdPairViewRtti::GetValue, + &StdPairViewRtti::GetConstKey, + &StdPairViewRtti::GetConstValue + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdPairView { + public: + static constexpr TemplateViewId id = StdPairViewRtti::id; + + explicit StdPairView(const Argument& inObj); + NonCopyable(StdPairView) + NonMovable(StdPairView) + + const TypeInfo* KeyType() const; + const TypeInfo* ValueType() const; + Any Key() const; + Any Value() const; + Any ConstKey() const; + Any ConstValue() const; + + private: + const Argument& obj; + const StdPairViewRtti* rtti; + }; + // ---------------- end std::pair ------------------- + + // ---------------- begin std::array ------------------- + struct StdArrayViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdArrayView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(); + using GetElementFunc = Any(const Argument&, size_t); + using GetConstElementFunc = Any(const Argument&, size_t); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(); + template static Any GetElement(const Argument& inObj, size_t inIndex); + template static Any GetConstElement(const Argument& inObj, size_t inIndex); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + GetElementFunc* getElement; + GetConstElementFunc* getConstElement; + }; + + template + static constexpr StdArrayViewRtti stdArrayViewRttiImpl = { + &StdArrayViewRtti::GetElementType, + &StdArrayViewRtti::GetSize, + &StdArrayViewRtti::GetElement, + &StdArrayViewRtti::GetConstElement, + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdArrayView { + public: + static constexpr TemplateViewId id = StdArrayViewRtti::id; + + explicit StdArrayView(const Argument& inObj); + NonCopyable(StdArrayView) + NonMovable(StdArrayView) + + const TypeInfo* ElementType() const; + size_t Size() const; + Any At(size_t inIndex) const; + Any ConstAt(size_t inIndex) const; + + private: + const Argument& obj; + const StdArrayViewRtti* rtti; + }; + // ---------------- end std::array --------------------- + + // ---------------- begin std::vector ------------------ + struct StdVectorViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdVectorView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using GetElementFunc = Any(const Argument&, size_t); + using GetConstElementFunc = Any(const Argument&, size_t); + using EmplaceBackFunc = Any(const Argument&, const Argument&); + using EraseFunc = void(const Argument&, size_t); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static Any GetElement(const Argument& inObj, size_t inIndex); + template static Any GetConstElement(const Argument& inObj, size_t inIndex); + template static Any EmplaceBack(const Argument& inObj, const Argument& inTempObj); + template static void Erase(const Argument& inObj, size_t inIndex); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + GetElementFunc* getElement; + GetConstElementFunc* getConstElement; + EmplaceBackFunc* emplaceBack; + EraseFunc* erase; + }; + + template + static constexpr StdVectorViewRtti stdVectorViewRttiImpl = { + &StdVectorViewRtti::GetElementType, + &StdVectorViewRtti::GetSize, + &StdVectorViewRtti::GetElement, + &StdVectorViewRtti::GetConstElement, + &StdVectorViewRtti::EmplaceBack, + &StdVectorViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdVectorView { + public: + static constexpr TemplateViewId id = StdVectorViewRtti::id; + + explicit StdVectorView(const Argument& inObj); + NonCopyable(StdVectorView) + NonMovable(StdVectorView) + + const TypeInfo* ElementType() const; + size_t Size() const; + Any At(size_t inIndex) const; + Any ConstAt(size_t inIndex) const; + Any EmplaceBack(const Argument& inNewObj) const; + void Erase(size_t inIndex) const; + + private: + const Argument& obj; + const StdVectorViewRtti* rtti; + }; + // ---------------- end std::vector -------------------- + + // ---------------- begin std::list -------------------- + struct StdListViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdListViewRtti"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using EmplaceFrontFunc = Any(const Argument&, const Argument&); + using EmplaceBackFunc = Any(const Argument&, const Argument&); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static Any EmplaceFront(const Argument& inObj, const Argument& inTempObj); + template static Any EmplaceBack(const Argument& inObj, const Argument& inTempObj); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + EmplaceFrontFunc* emplaceFront; + EmplaceBackFunc* emplaceBack; + }; + + template + static constexpr StdListViewRtti stdListViewRttiImpl = { + &StdListViewRtti::GetElementType, + &StdListViewRtti::GetSize, + &StdListViewRtti::Traverse, + &StdListViewRtti::ConstTraverse, + &StdListViewRtti::EmplaceFront, + &StdListViewRtti::EmplaceBack + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdListView { + public: + using ElementTraverser = std::function; + static constexpr TemplateViewId id = StdListViewRtti::id; + + explicit StdListView(const Argument& inObj); + NonCopyable(StdListView) + NonMovable(StdListView) + + const TypeInfo* ElementType() const; + size_t Size() const; + void Traverse(const ElementTraverser& inTraverser) const; + void ConstTraverse(const ElementTraverser& inTraverser) const; + Any EmplaceFront(const Argument& inTempObj) const; + Any EmplaceBack(const Argument& inTempObj) const; + + private: + const Argument& obj; + const StdListViewRtti* rtti; + }; + // ---------------- end std::list ---------------------- + + // ------------- begin std::unordered_set -------------- + struct StdUnorderedSetViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdUnorderedSetView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inElement); + template static void Emplace(const Argument& inObj, const Argument& inTempObj); + template static void Erase(const Argument& inObj, const Argument& inElement); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdUnorderedSetViewRtti stdUnorderedSetViewRttiImpl = { + &StdUnorderedSetViewRtti::GetElementType, + &StdUnorderedSetViewRtti::GetSize, + &StdUnorderedSetViewRtti::Traverse, + &StdUnorderedSetViewRtti::ConstTraverse, + &StdUnorderedSetViewRtti::Contains, + &StdUnorderedSetViewRtti::Emplace, + &StdUnorderedSetViewRtti::Erase, + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdUnorderedSetView { + public: + using ElementTraverser = std::function; + static constexpr TemplateViewId id = StdUnorderedSetViewRtti::id; + + explicit StdUnorderedSetView(const Argument& inObj); + NonCopyable(StdUnorderedSetView) + NonMovable(StdUnorderedSetView) + + const TypeInfo* ElementType() const; + size_t Size() const; + void Traverse(const ElementTraverser& inTraverser) const; + void ConstTraverse(const ElementTraverser& inTraverser) const; + bool Contains(const Argument& inElement) const; + void Emplace(const Argument& inTempObj) const; + void Erase(const Argument& inElement) const; + + private: + const Argument& obj; + const StdUnorderedSetViewRtti* rtti; + }; + // ------------- end std::unordered_set ---------------- + + // ----------------- begin std::set -------------------- + struct StdSetViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdSetView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inElement); + template static void Emplace(const Argument& inObj, const Argument& inTempObj); + template static void Erase(const Argument& inObj, const Argument& inElement); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + TraverseFunc* traverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdSetViewRtti stdSetViewRttiImpl = { + &StdSetViewRtti::GetElementType, + &StdSetViewRtti::GetSize, + &StdSetViewRtti::Traverse, + &StdSetViewRtti::Contains, + &StdSetViewRtti::Emplace, + &StdSetViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdSetView { + public: + using ElementTraverser = std::function; + static constexpr TemplateViewId id = StdSetViewRtti::id; + + explicit StdSetView(const Argument& inObj); + NonCopyable(StdSetView) + NonMovable(StdSetView) + + const TypeInfo* ElementType() const; + size_t Size() const; + void Traverse(const ElementTraverser& inTraverser) const; + bool Contains(const Argument& inElement) const; + void Emplace(const Argument& inTempObj) const; + void Erase(const Argument& inElement) const; + + private: + const Argument& obj; + const StdSetViewRtti* rtti; + }; + // ----------------- end std::set ---------------------- + + // ------------- begin std::unordered_map ----------- + struct StdUnorderedMapViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdUnorderedMapView"); + + using GetKeyTypeFunc = const TypeInfo*(); + using GetValueTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using AtFunc = Any(const Argument&, const Argument&); + using GetOrAddFunc = Any(const Argument&, const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetKeyType(); + template static const TypeInfo* GetValueType(); + template static size_t GetSize(const Argument& inObj); + template static Any At(const Argument& inObj, const Argument& inKey); + template static Any GetOrAdd(const Argument& inObj, const Argument& inKey); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inKey); + template static void Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue); + template static void Erase(const Argument& inObj, const Argument& inKey); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + GetSizeFunc* getSize; + AtFunc* at; + GetOrAddFunc* getOrAdd; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdUnorderedMapViewRtti stdUnorderedMapViewRttiImpl = { + &StdUnorderedMapViewRtti::GetKeyType, + &StdUnorderedMapViewRtti::GetValueType, + &StdUnorderedMapViewRtti::GetSize, + &StdUnorderedMapViewRtti::At, + &StdUnorderedMapViewRtti::GetOrAdd, + &StdUnorderedMapViewRtti::Traverse, + &StdUnorderedMapViewRtti::ConstTraverse, + &StdUnorderedMapViewRtti::Contains, + &StdUnorderedMapViewRtti::Emplace, + &StdUnorderedMapViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + };; + + class MIRROR_API StdUnorderedMapView { + public: + using PairTraverser = std::function; + static constexpr TemplateViewId id = StdUnorderedMapViewRtti::id; + + explicit StdUnorderedMapView(const Argument& inObj); + NonCopyable(StdUnorderedMapView) + NonMovable(StdUnorderedMapView) + + const TypeInfo* KeyType() const; + const TypeInfo* ValueType() const; + size_t Size() const; + Any At(const Argument& inKey) const; + Any GetOrAdd(const Argument& inKey) const; + void Traverse(const PairTraverser& inTraverser) const; + void ConstTraverse(const PairTraverser& inTraverser) const; + bool Contains(const Argument& inKey) const; + void Emplace(const Argument& inTempKey, const Argument& inTempValue) const; + void Erase(const Argument& inKey) const; + + private: + const Argument& obj; + const StdUnorderedMapViewRtti* rtti; + }; + // ------------- end std::unordered_map ------------- + + // ----------------- begin std::map ----------------- + struct StdMapViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdMapView"); + + using GetKeyTypeFunc = const TypeInfo*(); + using GetValueTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using AtFunc = Any(const Argument&, const Argument&); + using GetOrAddFunc = Any(const Argument&, const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetKeyType(); + template static const TypeInfo* GetValueType(); + template static size_t GetSize(const Argument& inObj); + template static Any At(const Argument& inObj, const Argument& inKey); + template static Any GetOrAdd(const Argument& inObj, const Argument& inKey); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inKey); + template static void Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue); + template static void Erase(const Argument& inObj, const Argument& inKey); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + GetSizeFunc* getSize; + AtFunc* at; + GetOrAddFunc* getOrAdd; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdMapViewRtti stdMapViewRttiImpl = { + &StdMapViewRtti::GetKeyType, + &StdMapViewRtti::GetValueType, + &StdMapViewRtti::GetSize, + &StdMapViewRtti::At, + &StdMapViewRtti::GetOrAdd, + &StdMapViewRtti::Traverse, + &StdMapViewRtti::ConstTraverse, + &StdMapViewRtti::Contains, + &StdMapViewRtti::Emplace, + &StdMapViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdMapView { + public: + using PairTraverser = std::function; + static constexpr TemplateViewId id = StdMapViewRtti::id; + + explicit StdMapView(const Argument& inObj); + NonCopyable(StdMapView) + NonMovable(StdMapView) + + const TypeInfo* KeyType() const; + const TypeInfo* ValueType() const; + size_t Size() const; + Any At(const Argument& inKey) const; + Any GetOrAdd(const Argument& inKey) const; + void Traverse(const PairTraverser& inTraverser) const; + void ConstTraverse(const PairTraverser& inTraverser) const; + bool Contains(const Argument& inKey) const; + void Emplace(const Argument& inTempKey, const Argument& inTempValue) const; + void Erase(const Argument& inKey) const; + + private: + const Argument& obj; + const StdMapViewRtti* rtti; + }; + // ----------------- end std::map ------------------- + + // --------------- begin std::tuple ----------------- + struct StdTupleRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdTupleView"); + + using GetSizeFunc = size_t(); + using GetElementTypeFunc = const TypeInfo*(size_t); + using GetElementFunc = Any(const Argument&, size_t); + using TraverseFunc = void(const Argument&, const std::function&); + + template static size_t GetSize(); + template static const TypeInfo* GetElementType(size_t inIndex); + template static Any GetElement(const Argument&, size_t inIndex); + template static void Traverse(const Argument&, const std::function& inVisitor); + + GetSizeFunc* getSize; + GetElementTypeFunc* getElementType; + GetElementFunc* getElement; + TraverseFunc* traverse; + }; + + template + static constexpr StdTupleRtti stdTupleRttiImpl = { + &StdTupleRtti::GetSize, + &StdTupleRtti::GetElementType, + &StdTupleRtti::GetElement, + &StdTupleRtti::Traverse + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdTupleView { + public: + using Visitor = std::function; + static constexpr TemplateViewId id = StdTupleRtti::id; + + explicit StdTupleView(const Argument& inObj); + NonCopyable(StdTupleView) + NonMovable(StdTupleView) + + size_t Size() const; + const TypeInfo* ElementType(size_t inIndex) const; + Any Get(size_t inIndex) const; + void Traverse(const Visitor& inVisitor) const; + + private: + const Argument& obj; + const StdTupleRtti* rtti; + }; + // --------------- end std::tuple ------------------- +} + namespace Mirror::Internal { template void StaticCheckArgumentType() @@ -864,34 +1612,23 @@ namespace Mirror::Internal { "static version reflection method do no support use Any/Any*/const Any*/Argument as argument, please check you arguments"); } - template - Any ForwardAsAny(T&& value) - { - StaticCheckArgumentType(); - - if constexpr (std::is_lvalue_reference_v) { - return { std::ref(std::forward(value)) }; - } else { - return { std::forward(value) }; - } - } - - template - Argument ForwardAsArgument(T&& value) + template + static std::array, sizeof...(T)> BuildTupleDynGetterArray(std::index_sequence) { - StaticCheckArgumentType(); - return ForwardAsAny(std::forward(value)); + return { + [](const Argument& inObj) -> Any { + return std::get(inObj.As&>()); + }... + }; } - template - ArgumentList ForwardAsArgumentList(Args&&... args) + template + static void TraverseTupleDyn(const Argument& inObj, const std::function& inVisitor, std::index_sequence) { - ArgumentList result; - result.reserve(sizeof...(args)); + auto& tuple = inObj.As&>(); (void) std::initializer_list { ([&]() -> void { - result.emplace_back(ForwardAsArgument(std::forward(args))); + inVisitor(std::ref(std::get(tuple))); }(), 0)... }; - return result; } } @@ -1020,12 +1757,12 @@ namespace Common { // NOLINT static size_t Serialize(BinarySerializeStream& stream, const T& value) { - return SerializeDyn(stream, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(value)); + return SerializeDyn(stream, Mirror::Class::Get(), Mirror::ForwardAsArg(value)); } static size_t Deserialize(BinaryDeserializeStream& stream, T& value) { - return DeserializeDyn(stream, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(value)); + return DeserializeDyn(stream, Mirror::Class::Get(), Mirror::ForwardAsArg(value)); } }; @@ -1361,24 +2098,18 @@ namespace Common { // NOLINT struct JsonSerializer { static void JsonSerializeDyn(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Class& clazz, const Mirror::Argument& inObj) { - const auto& className = clazz.GetName(); const auto* baseClass = clazz.GetBaseClass(); const auto& memberVariables = clazz.GetMemberVariables(); const auto defaultObject = clazz.GetDefaultObject(); - rapidjson::Value classNameJson; - JsonSerializer::JsonSerialize(classNameJson, inAllocator, className); + if (!outJsonValue.IsObject()) { + outJsonValue.SetObject(); + } - rapidjson::Value baseClassJson; if (baseClass != nullptr) { - JsonSerializeDyn(baseClassJson, inAllocator, *baseClass, inObj); - } else { - baseClassJson.SetNull(); + JsonSerializeDyn(outJsonValue, inAllocator, *baseClass, inObj); } - rapidjson::Value membersJson; - membersJson.SetObject(); - for (const auto& memberVariable : memberVariables | std::views::values) { if (memberVariable.IsTransient()) { continue; @@ -1391,24 +2122,17 @@ namespace Common { // NOLINT rapidjson::Value memberNameJson; JsonSerializer::JsonSerialize(memberNameJson, inAllocator, memberVariable.GetName()); - rapidjson::Value memberContentJson; if (sameAsDefault) { - memberContentJson.SetNull(); - } else { - memberVariable.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); + continue; } - membersJson.AddMember(memberNameJson, memberContentJson, inAllocator); + rapidjson::Value memberContentJson; + memberVariable.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); + outJsonValue.AddMember(memberNameJson, memberContentJson, inAllocator); } - - outJsonValue.SetObject(); - outJsonValue.AddMember("className", classNameJson, inAllocator); - outJsonValue.AddMember("baseClass", baseClassJson, inAllocator); - outJsonValue.AddMember("members", membersJson, inAllocator); } static void JsonDeserializeDyn(const rapidjson::Value& inJsonValue, const Mirror::Class& clazz, const Mirror::Argument& outObj) { - const auto& className = clazz.GetName(); const auto* baseClass = clazz.GetBaseClass(); const auto defaultObject = clazz.GetDefaultObject(); @@ -1416,56 +2140,30 @@ namespace Common { // NOLINT return; } - if (!inJsonValue.HasMember("className")) { - return; - } - std::string aspectClassName; - JsonSerializer::JsonDeserialize(inJsonValue["className"], aspectClassName); - if (aspectClassName != className) { - return; - } - - if (inJsonValue.HasMember("baseClass") && baseClass != nullptr) { - JsonDeserializeDyn(inJsonValue["baseClass"], *baseClass, outObj); - } - - if (!inJsonValue.HasMember("members")) { - return; - } - - const auto& membersJson = inJsonValue["members"]; - if (!membersJson.IsObject()) { - return; + if (baseClass != nullptr) { + JsonDeserializeDyn(inJsonValue, *baseClass, outObj); } - for (auto iter = membersJson.MemberBegin(); iter != membersJson.MemberEnd(); ++iter) { - std::string memberName; - JsonSerializer::JsonDeserialize(iter->name, memberName); - - if (!clazz.HasMemberVariable(memberName)) { - continue; - } - const auto& memberVariable = clazz.GetMemberVariable(memberName); - - if ( const auto& valueJson = iter->value; - valueJson.IsNull()) { + for (const auto& memberVariable : clazz.GetMemberVariables() | std::views::values) { + const auto& memberName = memberVariable.GetName(); + if (inJsonValue.HasMember(memberName.c_str())) { + memberVariable.GetDyn(outObj).JsonDeserialize(inJsonValue[memberName.c_str()]); + } else { if (!defaultObject.Empty()) { memberVariable.SetDyn(outObj, memberVariable.GetDyn(defaultObject)); } - } else { - memberVariable.GetDyn(outObj).JsonDeserialize(valueJson); } } } static void JsonSerialize(rapidjson::Value& outValue, rapidjson::Document::AllocatorType& inAllocator, const T& inValue) { - JsonSerializeDyn(outValue, inAllocator, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(inValue)); + JsonSerializeDyn(outValue, inAllocator, Mirror::Class::Get(), Mirror::ForwardAsArg(inValue)); } static void JsonDeserialize(const rapidjson::Value& inValue, T& outValue) { - JsonDeserializeDyn(inValue, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(outValue)); + JsonDeserializeDyn(inValue, Mirror::Class::Get(), Mirror::ForwardAsArg(outValue)); } }; @@ -1816,7 +2514,7 @@ namespace Common { // NOLINT stream << "{ "; auto count = 0; for (const auto& [id, var] : memberVariables) { - stream << fmt::format("{}: {}", id.name, var.GetDyn(argument).ToString()); + stream << std::format("{}: {}", id.name, var.GetDyn(argument).ToString()); if (count++ != memberVariables.size() - 1) { stream << ", "; } @@ -1827,7 +2525,7 @@ namespace Common { // NOLINT static std::string ToString(const T& inValue) { - return ToStringDyn(Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(inValue)); + return ToStringDyn(Mirror::Class::Get(), Mirror::ForwardAsArg(inValue)); } }; @@ -1837,7 +2535,7 @@ namespace Common { // NOLINT { if (const Mirror::Enum* metaEnum = Mirror::Enum::Find(); metaEnum != nullptr) { - return fmt::format( + return std::format( "{}::{}", StringConverter::ToString(metaEnum->GetName()), StringConverter::ToString(metaEnum->GetValue(inValue).GetName())); @@ -1857,7 +2555,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}{}{}", ownerName, ownerName.empty() ? "" : ":", name); + return std::format("{}{}{}", ownerName, ownerName.empty() ? "" : ":", name); } }; @@ -1871,7 +2569,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}{}{}{}", ownerName, ownerName.empty() ? "" : ":", name, name.empty() ? "" : "()"); + return std::format("{}{}{}{}", ownerName, ownerName.empty() ? "" : ":", name, name.empty() ? "" : "()"); } }; @@ -1885,7 +2583,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}({})", ownerName, StringUtils::AfterLast(ownerName, "::"), name); + return std::format("{}::{}({})", ownerName, StringUtils::AfterLast(ownerName, "::"), name); } }; @@ -1894,7 +2592,7 @@ namespace Common { // NOLINT static std::string ToString(const Mirror::Destructor* inValue) { const std::string ownerName = inValue != nullptr ? inValue->GetOwnerName() : ""; - return fmt::format("{}::~{}()", ownerName, StringUtils::AfterLast(ownerName, "::")); + return std::format("{}::~{}()", ownerName, StringUtils::AfterLast(ownerName, "::")); } }; @@ -1908,7 +2606,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}", ownerName, name); + return std::format("{}::{}", ownerName, name); } }; @@ -1922,7 +2620,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}()", ownerName, name); + return std::format("{}::{}()", ownerName, name); } }; @@ -1944,7 +2642,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}", ownerName, name); + return std::format("{}::{}", ownerName, name); } }; @@ -1972,6 +2670,7 @@ namespace Mirror { Common::CppLValueRef, Common::CppLValueConstRef, Common::CppRValueRef, + Common::CppRef, Common::CppPointer, Common::CppConstPointer, Common::CppClass, @@ -2001,7 +2700,7 @@ namespace Mirror { if constexpr (std::is_copy_constructible_v) { new(inThis) T(*static_cast(inOther)); } else { - QuickFailWithReason(fmt::format("type {} is no support copy construct", GetTypeInfo()->name)); + QuickFailWithReason(std::format("type {} is no support copy construct", GetTypeInfo()->name)); } } @@ -2011,7 +2710,27 @@ namespace Mirror { if constexpr (std::is_move_constructible_v) { new(inThis) T(std::move(*static_cast(inOther))); } else { - QuickFailWithReason(fmt::format("type {} is no support move construct", GetTypeInfo()->name)); + QuickFailWithReason(std::format("type {} is no support move construct", GetTypeInfo()->name)); + } + } + + template + void AnyRtti::CopyAssign(void* inThis, const void* inOther) + { + if constexpr (std::is_copy_assignable_v) { + *static_cast(inThis) = *static_cast(inOther); + } else { + QuickFailWithReason(std::format("type {} is no support copy assign", GetTypeInfo()->name)); + } + } + + template + void AnyRtti::MoveAssign(void* inThis, void* inOther) noexcept + { + if constexpr (std::is_move_assignable_v) { + *static_cast(inThis) = std::move(*static_cast(inOther)); + } else { + QuickFailWithReason(std::format("type {} is no support move assign", GetTypeInfo()->name)); } } @@ -2021,7 +2740,7 @@ namespace Mirror { if constexpr (Common::EqualComparable) { return *static_cast(inThis) == *static_cast(inOther); } else { - QuickFailWithReason(fmt::format("type {} is no support equal compare", GetTypeInfo()->name)); + QuickFailWithReason(std::format("type {} is no support equal compare", GetTypeInfo()->name)); return false; } } @@ -2131,6 +2850,27 @@ namespace Mirror { return Common::ToString(*static_cast(inThis)); } + template + std::pair AnyRtti::GetTemplateViewRtti() + { + return { + TemplateViewRttiGetter::Id(), + TemplateViewRttiGetter::Get() + }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter::Id() + { + return 0; + } + + template + const void* TemplateViewRttiGetter::Get() + { + return nullptr; + } + template Any::Any(T&& inValue) { @@ -2279,14 +3019,14 @@ namespace Mirror { T Any::As() { Assert(Convertible()); - return *static_cast*>(Data()); + return static_cast(*static_cast*>(Data())); } template T Any::As() const { Assert(Convertible()); - return *static_cast*>(Data()); + return static_cast(*static_cast*>(Data())); } template @@ -2323,6 +3063,13 @@ namespace Mirror { return dynamic_cast(As()); } + template + bool Any::CanAsTemplateView() const + { + Assert(!Empty()); + return rtti->getTemplateViewRtti().first == V::id; + } + template void Any::ConstructFromValue(T&& inValue) { @@ -2343,7 +3090,7 @@ namespace Mirror { arrayLength = 0; policy = std::is_const_v ? AnyPolicy::constRef : AnyPolicy::nonConstRef; rtti = &anyRttiImpl; - info = RefInfo(const_cast(&inRef.get()), sizeof(RawType)); + info = RefInfo(const_cast(std::addressof(inRef.get())), sizeof(RawType)); } template @@ -2393,6 +3140,14 @@ namespace Mirror { }); } + template + bool Argument::CanAsTemplateView() const + { + return Delegate([](auto&& value) -> decltype(auto) { + return value.template CanAsTemplateView(); + }); + } + template decltype(auto) Argument::Delegate(F&& inFunc) const { @@ -2410,59 +3165,127 @@ namespace Mirror { return inFunc(Any {}); } - template - Id::Id(const char(&inName)[N]) - : hash(Common::HashUtils::StrCrc32(inName)) - , name(inName) + template + Any ForwardAsAny(T&& value) { + Internal::StaticCheckArgumentType(); + + if constexpr (std::is_lvalue_reference_v) { + return { std::ref(std::forward(value)) }; + } else { + return { std::forward(value) }; + } } template - void Variable::Set(T&& value) const + Argument ForwardAsArg(T&& value) { - SetDyn(Internal::ForwardAsArgument(std::forward(value))); + Internal::StaticCheckArgumentType(); + return ForwardAsAny(std::forward(value)); + } + + template + ArgumentList ForwardAsArgList(Args&&... args) + { + ArgumentList result; + result.reserve(sizeof...(args)); + (void) std::initializer_list { ([&]() -> void { + result.emplace_back(ForwardAsArg(std::forward(args))); + }(), 0)... }; + return result; + } + + template + Any ForwardAsAnyByValue(T&& value) + { + Internal::StaticCheckArgumentType(); + auto any = ForwardAsAny(std::forward(value)); + return any.IsMemoryHolder() ? any : any.Value(); + } + + template + Argument ForwardAsArgByValue(T&& value) + { + Internal::StaticCheckArgumentType(); + return { ForwardAsAnyByValue(std::forward(value)) }; + } + + template + ArgumentList ForwardAsArgListByValue(Args&&... args) + { + ArgumentList result; + result.reserve(sizeof...(args)); + (void) std::initializer_list { ([&]() -> void { + result.emplace_back(ForwardAsArgByValue(std::forward(args))); + }(), 0)... }; + return result; + } + + template + Id::Id(const char(&inName)[N]) + : hash(Common::HashUtils::StrCrc32(inName)) + , name(inName) + { + } + + template + void Variable::Set(T&& value) const + { + SetDyn(ForwardAsArg(std::forward(value))); } template Any Function::Invoke(Args&&... args) const { - return InvokeDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return InvokeDyn(ForwardAsArgList(std::forward(args)...)); } template Any Constructor::Construct(Args&&... args) const { - return ConstructDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return ConstructDyn(ForwardAsArgList(std::forward(args)...)); } template Any Constructor::New(Args&&... args) const { - return NewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return NewDyn(ForwardAsArgList(std::forward(args)...)); + } + + template + Any Constructor::InplaceNew(Args&&... args) const + { + return InplaceNewDyn(ForwardAsArgList(std::forward(args)...)); } template - void Destructor::Invoke(C&& object) const + void Destructor::Destruct(C&& object) const { - InvokeDyn(Internal::ForwardAsArgument(std::forward(object))); + DestructDyn(ForwardAsArg(std::forward(object))); + } + + template + void Destructor::Delete(C* object) const + { + DeleteDyn(ForwardAsArg(object)); } template void MemberVariable::Set(C&& object, T&& value) const { - SetDyn(Internal::ForwardAsArgument(std::forward(object)), Internal::ForwardAsArgument(std::forward(value))); + SetDyn(ForwardAsArg(std::forward(object)), ForwardAsArg(std::forward(value))); } template Any MemberVariable::Get(C&& object) const { - return GetDyn(Internal::ForwardAsArgument(std::forward(object))); + return GetDyn(ForwardAsArg(std::forward(object))); } template Any MemberFunction::Invoke(C&& object, Args&&... args) const { - return InvokeDyn(Internal::ForwardAsArgument(std::forward(object)), Internal::ForwardAsArgumentList(std::forward(args)...)); + return InvokeDyn(ForwardAsArg(std::forward(object)), ForwardAsArgList(std::forward(args)...)); } template @@ -2484,21 +3307,33 @@ namespace Mirror { } template - Any Class::Construct(Args&&... args) + Any Class::Construct(Args&&... args) const { - auto arguments = Internal::ForwardAsArgumentList(std::forward(args)...); - const auto* constructor = FindSuitableConstructor(arguments); - Assert(constructor != nullptr); - return constructor->Construct(arguments); + return ConstructDyn(ForwardAsArgList(std::forward(args)...)); } template - Any Class::New(Args&&... args) + Any Class::New(Args&&... args) const { - auto arguments = Internal::ForwardAsArgumentList(std::forward(args)...); - const auto* constructor = FindSuitableConstructor(arguments); - Assert(constructor != nullptr); - return constructor->New(arguments); + return NewDyn(ForwardAsArgList(std::forward(args)...)); + } + + template + Any Class::InplaceNew(void* ptr, Args&&... args) const + { + return InplaceNewDyn(ptr, ForwardAsArgList(std::forward(args)...)); + } + + template + void Class::Destruct(C&& object) const + { + DestructDyn(ForwardAsArg(std::forward(object))); + } + + template + void Class::Delete(C* object) const + { + DeleteDyn(ForwardAsArg(object)); } template @@ -2522,30 +3357,568 @@ namespace Mirror { template void EnumValue::Set(E& value) const { - SetDyn(Internal::ForwardAsArgument(value)); + SetDyn(ForwardAsArg(value)); } template bool EnumValue::Compare(const E& value) const { - return Compare(Internal::ForwardAsArgument(value)); + return Compare(ForwardAsArg(value)); } template bool Enum::HasValue(E inValue) const { - return HasValue(Internal::ForwardAsArgument(inValue)); + return HasValue(ForwardAsArg(inValue)); } template const EnumValue* Enum::FindValue(E inValue) const { - return FindValue(Internal::ForwardAsArgument(inValue)); + return FindValue(ForwardAsArg(inValue)); } template const EnumValue& Enum::GetValue(E inValue) const { - return GetValue(Internal::ForwardAsArgument(inValue)); + return GetValue(ForwardAsArg(inValue)); } -} + + template + const TypeInfo* StdOptionalViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + bool StdOptionalViewRtti::HasValue(const Argument& inArg) + { + return inArg.As&>().has_value(); + } + + template + Any StdOptionalViewRtti::GetValue(const Argument& inArg) + { + return std::ref(inArg.As&>().value()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdOptionalViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdOptionalViewRttiImpl; + } + + template + const TypeInfo* StdPairViewRtti::GetKeyType() + { + return GetTypeInfo(); + } + + template + const TypeInfo* StdPairViewRtti::GetValueType() + { + return GetTypeInfo(); + } + + template + Any StdPairViewRtti::GetKey(const Argument& inObj) + { + return { std::ref(inObj.As&>().first) }; + } + + template + Any StdPairViewRtti::GetValue(const Argument& inObj) + { + return { std::ref(inObj.As&>().second) }; + } + + template + Any StdPairViewRtti::GetConstKey(const Argument& inObj) + { + return { std::ref(inObj.As&>().first) }; + } + + template + Any StdPairViewRtti::GetConstValue(const Argument& inObj) + { + return { std::ref(inObj.As&>().second) }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdPairViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdPairViewRttiImpl; + } + + template + const TypeInfo* StdArrayViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdArrayViewRtti::GetSize() + { + return N; + } + + template + Any StdArrayViewRtti::GetElement(const Argument& inObj, size_t inIndex) + { + return { std::ref(inObj.As&>()[inIndex]) }; + } + + template + Any StdArrayViewRtti::GetConstElement(const Argument& inObj, size_t inIndex) + { + return { std::ref(inObj.As&>()[inIndex]) }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdArrayViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdArrayViewRttiImpl; + } + + template + const TypeInfo* StdVectorViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdVectorViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + Any StdVectorViewRtti::GetElement(const Argument& inObj, size_t inIndex) + { + if constexpr (std::is_same_v) { + return { inObj.As&>()[inIndex] }; + } else { + return { std::ref(inObj.As&>()[inIndex]) }; + } + } + + template + Any StdVectorViewRtti::GetConstElement(const Argument& inObj, size_t inIndex) + { + if constexpr (std::is_same_v) { + return { inObj.As&>()[inIndex] }; + } else { + return { std::ref(inObj.As&>()[inIndex]) }; + } + } + + template + Any StdVectorViewRtti::EmplaceBack(const Argument& inObj, const Argument& inTempObj) + { + if constexpr (std::is_same_v) { + return { inObj.As&>().emplace_back(std::move(inTempObj.As())) }; + } else { + return { std::ref(inObj.As&>().emplace_back(std::move(inTempObj.As()))) }; + } + } + + template + void StdVectorViewRtti::Erase(const Argument& inObj, size_t inIndex) + { + auto& vec = inObj.As&>(); + vec.erase(vec.begin() + inIndex); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdVectorViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdVectorViewRttiImpl; + } + + template + const TypeInfo* StdListViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdListViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + void StdListViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& list = inObj.As&>(); // NOLINT + for (auto& element : list) { + inTraverser(std::ref(element)); + } + } + + template + void StdListViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& list = inObj.As&>(); // NOLINT + for (const auto& element : list) { + inTraverser(std::ref(element)); + } + } + + template + Any StdListViewRtti::EmplaceFront(const Argument& inObj, const Argument& inTempObj) + { + T& elemRef = inObj.As&>().emplace_front(std::move(inTempObj.As())); + return { std::ref(elemRef) }; + } + + template + Any StdListViewRtti::EmplaceBack(const Argument& inObj, const Argument& inTempObj) + { + T& elemRef = inObj.As&>().emplace_back(std::move(inTempObj.As())); + return { std::ref(elemRef) }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdListViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdListViewRttiImpl; + } + + template + const TypeInfo* StdUnorderedSetViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdUnorderedSetViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + void StdUnorderedSetViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& set = inObj.As&>(); // NOLINT + for (auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + void StdUnorderedSetViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& set = inObj.As&>(); // NOLINT + for (const auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + bool StdUnorderedSetViewRtti::Contains(const Argument& inObj, const Argument& inElement) + { + return inObj.As&>().contains(inElement.As()); + } + + template + void StdUnorderedSetViewRtti::Emplace(const Argument& inObj, const Argument& inTempObj) + { + inObj.As&>().emplace(std::move(inTempObj.As())); + } + + template + void StdUnorderedSetViewRtti::Erase(const Argument& inObj, const Argument& inElement) + { + inObj.As&>().erase(inElement.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdUnorderedSetViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdUnorderedSetViewRttiImpl; + } + + template + const TypeInfo* StdSetViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdSetViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + void StdSetViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& set = inObj.As&>(); // NOLINT + for (const auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + bool StdSetViewRtti::Contains(const Argument& inObj, const Argument& inElement) + { + return inObj.As&>().contains(inElement.As()); + } + + template + void StdSetViewRtti::Emplace(const Argument& inObj, const Argument& inTempObj) + { + inObj.As&>().emplace(inTempObj.As()); + } + + template + void StdSetViewRtti::Erase(const Argument& inObj, const Argument& inElement) + { + inObj.As&>().erase(inElement.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdSetViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdSetViewRttiImpl; + } + + template + const TypeInfo* StdUnorderedMapViewRtti::GetKeyType() + { + return GetTypeInfo(); + } + + template + const TypeInfo* StdUnorderedMapViewRtti::GetValueType() + { + return GetTypeInfo(); + } + + template + size_t StdUnorderedMapViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + Any StdUnorderedMapViewRtti::At(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>().at(inKey.As())) }; + } + + template + Any StdUnorderedMapViewRtti::GetOrAdd(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>()[inKey.As()]) }; + } + + template + void StdUnorderedMapViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& map = inObj.As&>(); // NOLINT + for (auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + void StdUnorderedMapViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& map = inObj.As&>(); // NOLINT + for (const auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + bool StdUnorderedMapViewRtti::Contains(const Argument& inObj, const Argument& inKey) + { + return inObj.As&>().contains(inKey.As()); + } + + template + void StdUnorderedMapViewRtti::Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue) + { + inObj.As&>().emplace(std::move(inTempKey.As()), std::move(inTempValue.As())); + } + + template + void StdUnorderedMapViewRtti::Erase(const Argument& inObj, const Argument& inKey) + { + inObj.As&>().erase(inKey.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdUnorderedMapViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdUnorderedMapViewRttiImpl; + } + + template + const TypeInfo* StdMapViewRtti::GetKeyType() + { + return GetTypeInfo(); + } + + template + const TypeInfo* StdMapViewRtti::GetValueType() + { + return GetTypeInfo(); + } + + template + size_t StdMapViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + Any StdMapViewRtti::At(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>().at(inKey.As())) }; + } + + template + Any StdMapViewRtti::GetOrAdd(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>()[inKey.As()]) }; + } + + template + void StdMapViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& map = inObj.As&>(); // NOLINT + for (auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + void StdMapViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& map = inObj.As&>(); // NOLINT + for (const auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + bool StdMapViewRtti::Contains(const Argument& inObj, const Argument& inKey) + { + return inObj.As&>().contains(inKey.As()); + } + + template + void StdMapViewRtti::Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue) + { + inObj.As&>().emplace(std::move(inTempKey.As()), std::move(inTempValue.As())); + } + + template + void StdMapViewRtti::Erase(const Argument& inObj, const Argument& inKey) + { + inObj.As&>().erase(inKey.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdMapViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdMapViewRttiImpl; + } + + template + size_t StdTupleRtti::GetSize() + { + return std::tuple_size_v>; + } + + template + const TypeInfo* StdTupleRtti::GetElementType(size_t inIndex) + { + static std::array types = { GetTypeInfo()... }; + Assert(inIndex < types.size()); + return types[inIndex]; + } + + template + Any StdTupleRtti::GetElement(const Argument& inObj, size_t inIndex) + { + static std::array, sizeof...(T)> getters = Internal::BuildTupleDynGetterArray(std::make_index_sequence {}); + Assert(inIndex < getters.size()); + return getters[inIndex](inObj); + } + + template + void StdTupleRtti::Traverse(const Argument& inObj, const std::function& inVisitor) + { + Internal::TraverseTupleDyn(inObj, inVisitor, std::make_index_sequence {}); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdTupleRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdTupleRttiImpl; + } +} // namespace Mirror diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index a603b312..d9d0ce2c 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -17,11 +17,11 @@ namespace Mirror::Internal { template struct MemberFunctionTraits {}; template auto GetArgTypeInfosByArgsTuple(std::index_sequence); - template auto ForwardArgumentsListAsTuple(const ArgumentList& args, std::index_sequence); - template decltype(auto) InvokeFunction(ArgsTuple& args, std::index_sequence); - template decltype(auto) InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence); - template decltype(auto) InvokeConstructorStack(ArgsTuple& args, std::index_sequence); - template decltype(auto) InvokeConstructorNew(ArgsTuple& args, std::index_sequence); + template decltype(auto) InvokeFunction(const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeMemberFunction(Class& object, const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeConstructorStack(const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeConstructorNew(const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeConstructorInplace(void* ptr, const ArgumentList& args, std::index_sequence); } namespace Mirror { @@ -46,12 +46,13 @@ namespace Mirror { public: ~ClassRegistry() override; - template ClassRegistry& Constructor(const Id& inId); - template ClassRegistry& StaticVariable(const Id& inId); - template ClassRegistry& StaticFunction(const Id& inId); - template ClassRegistry& MemberVariable(const Id& inId); + template ClassRegistry& Constructor(const Id& inId); + template ClassRegistry& StaticVariable(const Id& inId); + template ClassRegistry& StaticFunction(const Id& inId); + template ClassRegistry& MemberVariable(const Id& inId); // TODO support overload - template ClassRegistry& MemberFunction(const Id& inId); + // TODO virtual function support + template ClassRegistry& MemberFunction(const Id& inId); private: friend class Registry; @@ -102,8 +103,11 @@ namespace Mirror { GlobalRegistry Global(); - template B = void> ClassRegistry Class(const Id& inId); - template EnumRegistry Enum(const Id& inId); + template B = void, FieldAccess DefaultCtorAccess = FieldAccess::faPublic, FieldAccess DetorAccess = FieldAccess::faPublic> + ClassRegistry Class(const Id& inId); + + template EnumRegistry + Enum(const Id& inId); private: friend class GlobalScope; @@ -159,34 +163,35 @@ namespace Mirror::Internal { return std::vector { GetTypeInfo>()... }; } - template - auto ForwardArgumentsListAsTuple(const ArgumentList& args, std::index_sequence) + template + decltype(auto) InvokeFunction(const ArgumentList& args, std::index_sequence) { - return ArgsTuple { args[I].template As>()... }; + return Ptr(args[I].template As>()...); } - template - decltype(auto) InvokeFunction(ArgsTuple& args, std::index_sequence) + template + decltype(auto) InvokeMemberFunction(Class& object, const ArgumentList& args, std::index_sequence) { - return Ptr(std::get(args)...); + return (object.*Ptr)(args[I].template As>()...); } - template - decltype(auto) InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence) + template + decltype(auto) InvokeConstructorStack(const ArgumentList& args, std::index_sequence) { - return (object.*Ptr)(std::get(args)...); + return Class(args[I].template As>()...); } template - decltype(auto) InvokeConstructorStack(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeConstructorNew(const ArgumentList& args, std::index_sequence) { - return Class(std::get(args)...); + return new Class(args[I].template As>()...); } template - decltype(auto) InvokeConstructorNew(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeConstructorInplace(void* ptr, const ArgumentList& args, std::index_sequence) { - return new Class(std::get(args)...); + new(ptr) Class(args[I].template As>()...); + return *static_cast(ptr); } } @@ -226,7 +231,7 @@ namespace Mirror { ClassRegistry::~ClassRegistry() = default; template - template + template ClassRegistry& ClassRegistry::Constructor(const Id& inId) { using ArgsTupleType = std::tuple; @@ -238,26 +243,29 @@ namespace Mirror { Constructor::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.argsNum = sizeof...(Args); params.argTypeInfos = { GetTypeInfo()... }; params.argRemoveRefTypeInfos = { GetTypeInfo>()... }; params.argRemovePointerTypeInfos = { GetTypeInfo>()... }; params.stackConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); - return Internal::ForwardAsAny(Internal::InvokeConstructorStack(argsTuple, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeConstructorStack(args, std::make_index_sequence {})); }; params.heapConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); - return Internal::ForwardAsAny(Internal::InvokeConstructorNew(argsTuple, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeConstructorNew(args, std::make_index_sequence {})); + }; + params.inplaceConstructor = [](void* ptr, const ArgumentList& args) -> Any { + Assert(argsTupleSize == args.size()); + return ForwardAsAny(Internal::InvokeConstructorInplace(ptr, args, std::make_index_sequence {})); }; return MetaDataRegistry::SetContext(&clazz.EmplaceConstructor(inId, std::move(params))); } template - template + template ClassRegistry& ClassRegistry::StaticVariable(const Id& inId) { using ValueType = typename Internal::VariableTraits::ValueType; @@ -268,6 +276,7 @@ namespace Mirror { Variable::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& value) -> void { @@ -285,7 +294,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::StaticFunction(const Id& inId) { using ArgsTupleType = typename Internal::FunctionTraits::ArgsTupleType; @@ -299,18 +308,18 @@ namespace Mirror { Function::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); params.invoker = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); if constexpr (std::is_void_v) { - Internal::InvokeFunction(argsTuple, std::make_index_sequence {}); + Internal::InvokeFunction(args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeFunction(argsTuple, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); } }; @@ -318,7 +327,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::MemberVariable(const Id& inId) { using ClassType = typename Internal::MemberVariableTraits::ClassType; @@ -330,6 +339,7 @@ namespace Mirror { MemberVariable::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& object, const Argument& value) -> void { @@ -346,7 +356,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::MemberFunction(const Id& inId) { // ClassType here contains const, #see Internal::MemberFunctionTraits @@ -362,18 +372,18 @@ namespace Mirror { MemberFunction::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); params.invoker = [](const Argument& object, const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); if constexpr (std::is_void_v) { - Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {}); + Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {})); } }; @@ -391,6 +401,7 @@ namespace Mirror { Variable::ConstructParams params; params.id = inId; params.owner = Id::null; + params.access = FieldAccess::max; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& argument) -> void { @@ -420,18 +431,18 @@ namespace Mirror { Function::ConstructParams params; params.id = inId; params.owner = Id::null; + params.access = FieldAccess::max; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); params.invoker = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); if constexpr (std::is_void_v) { - Internal::InvokeFunction(argsTuple, std::make_index_sequence {}); + Internal::InvokeFunction(args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeFunction(argsTuple, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); } }; @@ -473,7 +484,7 @@ namespace Mirror { return MetaDataRegistry>::SetContext(&enumInfo.EmplaceElement(inId, std::move(params))); } - template B> + template B, FieldAccess DefaultCtorAccess, FieldAccess DetorAccess> ClassRegistry Registry::Class(const Id& inId) { const auto typeId = GetTypeInfo()->id; @@ -483,6 +494,7 @@ namespace Mirror { Class::ConstructParams params; params.id = inId; params.typeInfo = GetTypeInfo(); + params.memorySize = sizeof(C); params.baseClassGetter = []() -> const Mirror::Class* { if constexpr (std::is_void_v) { return nullptr; @@ -490,6 +502,9 @@ namespace Mirror { return &Mirror::Class::Get(); } }; + params.inplaceGetter = [](void* ptr) -> Any { + return { std::ref(*static_cast(ptr)) }; + }; if constexpr (std::is_default_constructible_v) { params.defaultObjectCreator = []() -> Any { return { C() }; @@ -498,16 +513,20 @@ namespace Mirror { if constexpr (std::is_destructible_v) { Destructor::ConstructParams detorParams; detorParams.owner = inId; + detorParams.access = DetorAccess; detorParams.destructor = [](const Argument& object) -> void { - Assert(!object.IsConstRef()); object.As().~C(); }; + detorParams.deleter = [](const Argument& object) -> void { + delete object.As(); + }; params.destructorParams = detorParams; } if constexpr (std::is_default_constructible_v) { Constructor::ConstructParams ctorParams; ctorParams.id = IdPresets::defaultCtor.name; ctorParams.owner = inId; + ctorParams.access = DefaultCtorAccess; ctorParams.argsNum = 0; ctorParams.argTypeInfos = {}; ctorParams.stackConstructor = [](const ArgumentList& args) -> Any { diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 9e66f654..fb4d0032 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -33,7 +33,7 @@ namespace Mirror { const auto [dstRaw, dstRemoveRef, dstRemovePointer] = inDstType; const bool checkPointer = srcRaw->isPointer && dstRaw->isPointer; - const bool checkRef = dstRaw->isLValueReference; + const bool checkRef = dstRaw->isReference; if (!checkPointer && !checkRef) { return false; @@ -56,7 +56,7 @@ namespace Mirror { if (srcClass == nullptr || dstClass == nullptr || !dstClass->IsBaseOf(srcClass)) { return false; } - return !srcRemoveRefOrPtr->isConst || dstRemoveRefOrPtr->isConst; + return !srcRemoveRefOrPtr->isConst || dstRaw->isRValueReference || dstRemoveRefOrPtr->isConst; } bool Convertible(const TypeInfoCompact& inSrcType, const TypeInfoCompact& inDstType) @@ -64,15 +64,11 @@ namespace Mirror { const auto [srcRaw, srcRemoveRef, srcRemovePointer] = inSrcType; const auto [dstRaw, dstRemoveRef, dstRemovePointer] = inDstType; - if (dstRaw->isRValueReference) { - return false; - } - if (srcRaw->id == dstRaw->id) { // NOLINT - if (!dstRaw->isLValueReference) { + if (!dstRaw->isReference) { return true; } - return !srcRemoveRef->isConst || dstRemoveRef->isConst; + return !srcRemoveRef->isConst || dstRaw->isRValueReference || dstRemoveRef->isConst; } return PointerConvertible(inSrcType, inDstType) || PolymorphismConvertible(inSrcType, inDstType); } @@ -134,6 +130,66 @@ namespace Mirror { return *this; } + Any& Any::CopyAssign(Any& inOther) + { + Assert(!IsConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + Any& Any::CopyAssign(const Any& inOther) + { + Assert(!IsConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + Any& Any::MoveAssign(Any& inOther) noexcept + { + Assert(!IsConstRef()); + Assert(!inOther.IsRef() || inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + + Any& Any::MoveAssign(const Any& inOther) noexcept + { + Assert(!IsConstRef()); + Assert(inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + + const Any& Any::CopyAssign(Any& inOther) const + { + Assert(IsNonConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + const Any& Any::CopyAssign(const Any& inOther) const + { + Assert(IsNonConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + const Any& Any::MoveAssign(Any& inOther) const noexcept + { + Assert(IsNonConstRef()); + Assert(!inOther.IsRef() || inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + + const Any& Any::MoveAssign(const Any& inOther) const noexcept + { + Assert(IsNonConstRef()); + Assert(inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + void Any::PerformCopyConstruct(const Any& inOther) { arrayLength = inOther.arrayLength; @@ -193,7 +249,7 @@ namespace Mirror { } } - void Any::PerformMoveConstruct(Any&& inOther) + void Any::PerformMoveConstruct(Any&& inOther) noexcept { arrayLength = inOther.arrayLength; policy = inOther.policy; @@ -214,11 +270,35 @@ namespace Mirror { } } + void Any::PerformCopyAssign(const Any& inOther) const + { + Assert(!Empty() && !inOther.Empty() && arrayLength == inOther.arrayLength && rtti == inOther.rtti); + + for (auto i = 0; i < ElementNum(); i++) { + rtti->copyAssign(Data(i), inOther.Data(i)); + } + } + + void Any::PerformMoveAssign(const Any& inOther) const noexcept + { + Assert(!Empty() && !inOther.Empty() && arrayLength == inOther.arrayLength && rtti == inOther.rtti); + + for (auto i = 0; i < ElementNum(); i++) { + rtti->moveAssign(Data(i), inOther.Data(i)); + } + } + uint32_t Any::ElementNum() const { return std::max(1u, arrayLength); } + TemplateViewRttiPtr Any::GetTemplateViewRtti() const + { + Assert(!Empty()); + return rtti->getTemplateViewRtti().second; + } + bool Any::IsArray() const { return arrayLength > 0; @@ -645,6 +725,13 @@ namespace Mirror { return *this; } + TemplateViewRttiPtr Argument::GetTemplateViewRtti() const + { + return Delegate([](auto&& value) -> decltype(auto) { + return value.GetTemplateViewRtti(); + }); + } + bool Argument::IsMemoryHolder() const { return Delegate([](auto&& value) -> decltype(auto) { @@ -759,7 +846,7 @@ namespace Mirror { std::stringstream stream; uint32_t count = 0; for (const auto& [key, value] : metas) { - stream << fmt::format("{}={}", key.name, value); + stream << std::format("{}={}", key.name, value); count++; if (count != metas.size()) { @@ -804,6 +891,7 @@ namespace Mirror { Variable::Variable(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , memorySize(params.memorySize) , typeInfo(params.typeInfo) , setter(std::move(params.setter)) @@ -833,6 +921,12 @@ namespace Mirror { return owner.IsNull() ? nullptr : Class::Find(owner); } + FieldAccess Variable::GetAccess() const + { + Assert(!owner.IsNull()); + return access; + } + const TypeInfo* Variable::GetTypeInfo() const { return typeInfo; @@ -851,6 +945,7 @@ namespace Mirror { Function::Function(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , argsNum(params.argsNum) , retTypeInfo(params.retTypeInfo) , argTypeInfos(std::move(params.argTypeInfos)) @@ -875,6 +970,12 @@ namespace Mirror { return owner.IsNull() ? nullptr : Class::Find(owner); } + FieldAccess Function::GetAccess() const + { + Assert(!owner.IsNull()); + return access; + } + uint8_t Function::GetArgsNum() const { return argsNum; @@ -903,12 +1004,14 @@ namespace Mirror { Constructor::Constructor(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , argsNum(params.argsNum) , argTypeInfos(std::move(params.argTypeInfos)) , argRemoveRefTypeInfos(std::move(params.argRemoveRefTypeInfos)) , argRemovePointerTypeInfos(std::move(params.argRemovePointerTypeInfos)) , stackConstructor(std::move(params.stackConstructor)) , heapConstructor(std::move(params.heapConstructor)) + , inplaceConstructor(std::move(params.inplaceConstructor)) { } @@ -924,9 +1027,16 @@ namespace Mirror { return owner; } - const Class* Constructor::GetOwner() const + const Class& Constructor::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess Constructor::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } uint8_t Constructor::GetArgsNum() const @@ -974,10 +1084,17 @@ namespace Mirror { return heapConstructor(arguments); } + Any Constructor::InplaceNewDyn(void* ptr, const ArgumentList& arguments) const + { + return inplaceConstructor(ptr, arguments); + } + Destructor::Destructor(ConstructParams&& params) : ReflNode(std::string(IdPresets::detor.name)) , owner(std::move(params.owner)) + , access(params.access) , destructor(std::move(params.destructor)) + , deleter(std::move(params.deleter)) { } @@ -993,19 +1110,32 @@ namespace Mirror { return owner; } - const Class* Destructor::GetOwner() const + const Class& Destructor::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess Destructor::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } - void Destructor::InvokeDyn(const Argument& argument) const + void Destructor::DestructDyn(const Argument& argument) const { destructor(argument); } + void Destructor::DeleteDyn(const Argument& argument) const + { + deleter(argument); + } + MemberVariable::MemberVariable(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , memorySize(params.memorySize) , typeInfo(params.typeInfo) , setter(std::move(params.setter)) @@ -1025,12 +1155,19 @@ namespace Mirror { return owner; } - const Class* MemberVariable::GetOwner() const + const Class& MemberVariable::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess MemberVariable::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } - uint32_t MemberVariable::SizeOf() const + size_t MemberVariable::SizeOf() const { return memorySize; } @@ -1058,6 +1195,7 @@ namespace Mirror { MemberFunction::MemberFunction(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , argsNum(params.argsNum) , retTypeInfo(params.retTypeInfo) , argTypeInfos(std::move(params.argTypeInfos)) @@ -1077,9 +1215,16 @@ namespace Mirror { return owner; } - const Class* MemberFunction::GetOwner() const + const Class& MemberFunction::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess MemberFunction::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } uint8_t MemberFunction::GetArgsNum() const @@ -1185,7 +1330,9 @@ namespace Mirror { Class::Class(ConstructParams&& params) : ReflNode(std::move(params.id)) , typeInfo(params.typeInfo) + , memorySize(params.memorySize) , baseClassGetter(std::move(params.baseClassGetter)) + , inplaceGetter(std::move(params.inplaceGetter)) { CreateDefaultObject(params.defaultObjectCreator); if (params.destructorParams.has_value()) { @@ -1196,6 +1343,8 @@ namespace Mirror { } } + Class::~Class() = default; + bool Class::Has(const Id& inId) { const auto& classes = Registry::Get().classes; @@ -1284,7 +1433,10 @@ namespace Mirror { return result; } - Class::~Class() = default; + Any Class::InplaceGetObject(void* ptr) const + { + return inplaceGetter(ptr); + } void Class::ForEachStaticVariable(const VariableTraverser& func) const { @@ -1368,6 +1520,11 @@ namespace Mirror { return typeInfo; } + size_t Class::SizeOf() const + { + return memorySize; + } + bool Class::HasDefaultConstructor() const { return HasConstructor(IdPresets::defaultCtor); @@ -1428,7 +1585,10 @@ namespace Mirror { const Constructor* Class::FindSuitableConstructor(const ArgumentList& arguments) const { - for (const auto& [constructorName, constructor] : constructors) { + std::vector> candidateAndRates; + candidateAndRates.reserve(constructors.size()); + + for (const auto& constructor : constructors | std::views::values) { const auto& argTypeInfos = constructor.GetArgTypeInfos(); const auto& argRemoveRefTypeInfos = constructor.GetArgRemoveRefTypeInfos(); const auto& argRemovePointerTypeInfos = constructor.GetArgRemovePointerTypeInfos(); @@ -1437,11 +1597,13 @@ namespace Mirror { continue; } + uint32_t rate = 0; bool bSuitable = true; for (auto i = 0; i < arguments.size(); i++) { const TypeInfoCompact srcType { arguments[i].Type(), arguments[i].RemoveRefType(), arguments[i].RemovePointerType() }; // NOLINT const TypeInfoCompact dstType { argTypeInfos[i], argRemoveRefTypeInfos[i], argRemovePointerTypeInfos[i] }; // NOLINT if (Convertible(srcType, dstType)) { + rate += dstType.raw->isRValueReference ? 2 : 1; continue; } @@ -1450,10 +1612,11 @@ namespace Mirror { } if (bSuitable) { - return &constructor; + candidateAndRates.emplace_back(&constructor, rate); } } - return nullptr; + std::ranges::sort(candidateAndRates, [](const auto& lhs, const auto& rhs) -> bool { return lhs.second < rhs.second; }); + return candidateAndRates.empty() ? nullptr : candidateAndRates.back().first; } Any Class::ConstructDyn(const ArgumentList& arguments) const @@ -1470,6 +1633,23 @@ namespace Mirror { return constructor->NewDyn(arguments); } + Any Class::InplaceNewDyn(void* ptr, const ArgumentList& arguments) const + { + const auto* constructor = FindSuitableConstructor(arguments); + Assert(constructor != nullptr); + return constructor->InplaceNewDyn(ptr, arguments); + } + + void Class::DestructDyn(const Argument& argument) const + { + GetDestructor().DestructDyn(argument); + } + + void Class::DeleteDyn(const Argument& argument) const + { + GetDestructor().DeleteDyn(argument); + } + const Constructor* Class::FindConstructor(const Id& inId) const { const auto iter = constructors.find(inId); @@ -1736,4 +1916,384 @@ namespace Mirror { values.emplace(inId, EnumValue(std::move(inParams))); return values.at(inId); } -} + + StdOptionalView::StdOptionalView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdOptionalView::ElementType() const + { + return rtti->getElementType(); + } + + bool StdOptionalView::HasValue() const + { + return rtti->hasValue(obj); + } + + Any StdOptionalView::Value() const + { + return rtti->getValue(obj); + } + + StdPairView::StdPairView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdPairView::KeyType() const + { + return rtti->getKeyType(); + } + + const TypeInfo* StdPairView::ValueType() const + { + return rtti->getValueType(); + } + + Any StdPairView::Key() const + { + return rtti->getKey(obj); + } + + Any StdPairView::Value() const + { + return rtti->getValue(obj); + } + + Any StdPairView::ConstKey() const + { + return rtti->getConstKey(obj); + } + + Any StdPairView::ConstValue() const + { + return rtti->getConstValue(obj); + } + + StdArrayView::StdArrayView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdArrayView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdArrayView::Size() const + { + return rtti->getSize(); + } + + Any StdArrayView::At(size_t inIndex) const + { + return rtti->getElement(obj, inIndex); + } + + Any StdArrayView::ConstAt(size_t inIndex) const + { + return rtti->getConstElement(obj, inIndex); + } + + StdVectorView::StdVectorView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdVectorView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdVectorView::Size() const + { + return rtti->getSize(obj); + } + + Any StdVectorView::At(size_t inIndex) const + { + return rtti->getElement(obj, inIndex); + } + + Any StdVectorView::ConstAt(size_t inIndex) const + { + return rtti->getConstElement(obj, inIndex); + } + + Any StdVectorView::EmplaceBack(const Argument& inNewObj) const + { + return rtti->emplaceBack(obj, inNewObj); + } + + void StdVectorView::Erase(size_t inIndex) const + { + rtti->erase(obj, inIndex); + } + + StdListView::StdListView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdListView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdListView::Size() const + { + return rtti->getSize(obj); + } + + void StdListView::Traverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdListView::ConstTraverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + Any StdListView::EmplaceFront(const Argument& inTempObj) const + { + return rtti->emplaceFront(obj, inTempObj); + } + + Any StdListView::EmplaceBack(const Argument& inTempObj) const + { + return rtti->emplaceBack(obj, inTempObj); + } + + StdUnorderedSetView::StdUnorderedSetView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdUnorderedSetView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdUnorderedSetView::Size() const + { + return rtti->getSize(obj); + } + + void StdUnorderedSetView::Traverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdUnorderedSetView::ConstTraverse(const ElementTraverser& inTraverser) const + { + rtti->constTraverse(obj, inTraverser); + } + + bool StdUnorderedSetView::Contains(const Argument& inElement) const + { + return rtti->contains(obj, inElement); + } + + void StdUnorderedSetView::Emplace(const Argument& inTempObj) const + { + rtti->emplace(obj, inTempObj); + } + + void StdUnorderedSetView::Erase(const Argument& inElement) const + { + rtti->erase(obj, inElement); + } + + StdSetView::StdSetView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdSetView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdSetView::Size() const + { + return rtti->getSize(obj); + } + + void StdSetView::Traverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + bool StdSetView::Contains(const Argument& inElement) const + { + return rtti->contains(obj, inElement); + } + + void StdSetView::Emplace(const Argument& inTempObj) const + { + rtti->emplace(obj, inTempObj); + } + + void StdSetView::Erase(const Argument& inElement) const + { + rtti->erase(obj, inElement); + } + + StdUnorderedMapView::StdUnorderedMapView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdUnorderedMapView::KeyType() const + { + return rtti->getKeyType(); + } + + const TypeInfo* StdUnorderedMapView::ValueType() const + { + return rtti->getValueType(); + } + + size_t StdUnorderedMapView::Size() const + { + return rtti->getSize(obj); + } + + Any StdUnorderedMapView::At(const Argument& inKey) const + { + return rtti->at(obj, inKey); + } + + Any StdUnorderedMapView::GetOrAdd(const Argument& inKey) const + { + return rtti->getOrAdd(obj, inKey); + } + + void StdUnorderedMapView::Traverse(const PairTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdUnorderedMapView::ConstTraverse(const PairTraverser& inTraverser) const + { + rtti->constTraverse(obj, inTraverser); + } + + bool StdUnorderedMapView::Contains(const Argument& inKey) const + { + return rtti->contains(obj, inKey); + } + + void StdUnorderedMapView::Emplace(const Argument& inTempKey, const Argument& inTempValue) const + { + rtti->emplace(obj, inTempKey, inTempValue); + } + + void StdUnorderedMapView::Erase(const Argument& inKey) const + { + rtti->erase(obj, inKey); + } + + StdMapView::StdMapView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdMapView::KeyType() const + { + return rtti->getKeyType(); + } + + const TypeInfo* StdMapView::ValueType() const + { + return rtti->getValueType(); + } + + size_t StdMapView::Size() const + { + return rtti->getSize(obj); + } + + Any StdMapView::At(const Argument& inKey) const + { + return rtti->at(obj, inKey); + } + + Any StdMapView::GetOrAdd(const Argument& inKey) const + { + return rtti->getOrAdd(obj, inKey); + } + + void StdMapView::Traverse(const PairTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdMapView::ConstTraverse(const PairTraverser& inTraverser) const + { + rtti->constTraverse(obj, inTraverser); + } + + bool StdMapView::Contains(const Argument& inKey) const + { + return rtti->contains(obj, inKey); + } + + void StdMapView::Emplace(const Argument& inTempKey, const Argument& inTempValue) const + { + rtti->emplace(obj, inTempKey, inTempValue); + } + + void StdMapView::Erase(const Argument& inKey) const + { + rtti->erase(obj, inKey); + } + + StdTupleView::StdTupleView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + size_t StdTupleView::Size() const + { + return rtti->getSize(); + } + + const TypeInfo* StdTupleView::ElementType(size_t inIndex) const + { + return rtti->getElementType(inIndex); + } + + Any StdTupleView::Get(size_t inIndex) const + { + return rtti->getElement(obj, inIndex); + } + + void StdTupleView::Traverse(const Visitor& inVisitor) const + { + rtti->traverse(obj, inVisitor); + } +} // namespace Mirror diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index 31a489d9..ff2718b3 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -69,6 +69,38 @@ AnyMoveCtorTest::AnyMoveCtorTest(AnyMoveCtorTest&& inOther) noexcept moveTime++; } +AnyCopyAssignTest::AnyCopyAssignTest() + : called(false) +{ +} + +AnyCopyAssignTest::AnyCopyAssignTest(AnyCopyAssignTest&& inOther) noexcept + : called(inOther.called) +{ +} + +AnyCopyAssignTest& AnyCopyAssignTest::operator=(const AnyCopyAssignTest& inOther) +{ + called = true; + return *this; +} + +AnyMoveAssignTest::AnyMoveAssignTest() + : called(false) +{ +} + +AnyMoveAssignTest::AnyMoveAssignTest(AnyMoveAssignTest&& inOther) noexcept + : called(inOther.called) +{ +} + +AnyMoveAssignTest& AnyMoveAssignTest::operator=(AnyMoveAssignTest&& inOther) noexcept +{ + called = true; + return *this; +} + bool AnyBasicTest::operator==(const AnyBasicTest& inRhs) const { return a == inRhs.a @@ -235,6 +267,26 @@ TEST(AnyTest, MoveAssignTest) ASSERT_EQ(a0.TypeId(), a1.TypeId()); } +TEST(AnyTest, ValueCopyAssignTest) +{ + Any a0 = AnyCopyAssignTest(); + ASSERT_EQ(a0.As().called, false); + + Any a1 = AnyCopyAssignTest(); + a0.CopyAssign(a1); + ASSERT_EQ(a0.As().called, true); +} + +TEST(AnyTest, ValueMoveAssignTest) +{ + Any a0 = AnyMoveAssignTest(); + ASSERT_EQ(a0.As().called, false); + + Any a1 = AnyMoveAssignTest(); + a0.MoveAssign(a1); + ASSERT_EQ(a0.As().called, true); +} + TEST(AnyTest, ValueAssignTest) { Any a0 = 1; @@ -264,7 +316,7 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); const int v0 = 1; // NOLINT a0 = v0; @@ -272,7 +324,7 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); int v1 = 1; a0 = std::ref(v1); @@ -280,14 +332,14 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); a0 = std::ref(v0); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_FALSE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); a0 = 1; Any a1 = a0.Ref(); @@ -295,21 +347,21 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); - ASSERT_FALSE(a1.Convertible()); + ASSERT_TRUE(a1.Convertible()); a1 = a1.ConstRef(); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_FALSE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); - ASSERT_FALSE(a1.Convertible()); + ASSERT_TRUE(a1.Convertible()); a1 = a1.Value(); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); - ASSERT_FALSE(a1.Convertible()); + ASSERT_TRUE(a1.Convertible()); AnyDerivedClassTest derived {}; a0 = derived; @@ -1230,3 +1282,205 @@ TEST(AnyTest, ArrayTest) ASSERT_EQ(a6.ArrayLength(), sizeof(v0) / sizeof(int)); ASSERT_EQ(a6[1].As(), 2); } + +TEST(AnyTest, StdOptionalViewTest) +{ + Any a0 = std::optional {}; + const StdOptionalView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_FALSE(v0.HasValue()); + + std::optional t0 = 1; + Any a1 = std::ref(t0); + const StdOptionalView v1(a1); + ASSERT_TRUE(v1.HasValue()); + ASSERT_EQ(v1.Value().As(), 1); +} + +TEST(AnyTest, StdPairViewTest) +{ + Any a0 = std::pair { 1, true }; + const StdPairView v0(a0); + ASSERT_EQ(v0.KeyType(), GetTypeInfo()); + ASSERT_EQ(v0.ValueType(), GetTypeInfo()); + ASSERT_EQ(v0.Key().As(), 1); + ASSERT_EQ(v0.Value().As(), true); +} + +TEST(AnyTest, StdArrayViewTest) +{ + Any a0 = std::array { 1, 2, 3 }; + const StdArrayView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + for (auto i = 0; i < 3; i++) { + ASSERT_EQ(v0.At(i).As(), i + 1); + ASSERT_EQ(v0.ConstAt(i).As(), i + 1); + }; +} + +TEST(AnyTest, StdVectorViewTest) +{ + Any a0 = std::vector { 1, 2, 3 }; + const StdVectorView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + for (auto i = 0; i < 3; i++) { + ASSERT_EQ(v0.At(i).As(), i + 1); + ASSERT_EQ(v0.ConstAt(i).As(), i + 1); + }; + v0.Erase(1); + ASSERT_EQ(v0.Size(), 2); + v0.EmplaceBack(Any(5)); + ASSERT_EQ(v0.Size(), 3); +} + +TEST(AnyTest, StdListViewTest) +{ + std::list t0 = { 1, 2, 3 }; + Any a0 = std::ref(t0); + const StdListView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + + int count = 0; + v0.Traverse([&count](const Any& inRef) -> void { + ASSERT_EQ(inRef.As(), ++count); + }); + + v0.EmplaceBack(Any(4)); + ASSERT_EQ(v0.Size(), 4); + v0.EmplaceFront(Any(0)); + ASSERT_EQ(v0.Size(), 5); + + count = 0; + v0.ConstTraverse([&count](const Any& inRef) -> void { + ASSERT_EQ(inRef.As(), count++); + }); +} + +TEST(AnyTest, StdunorderedSetViewTest) +{ + Any a0 = std::unordered_set { 1, 2, 3 }; + const StdUnorderedSetView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + + v0.Traverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 3); + }); + + v0.Emplace(Any(4)); + v0.ConstTraverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 4); + }); + v0.Erase(Any(1)); + for (auto i = 2; i <= 4; i++) { + v0.Contains(Any(std::ref(i))); + } +} + +TEST(AnyTest, StdSetViewTest) +{ + Any a0 = std::set { 1, 2, 3 }; + const StdSetView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + + v0.Traverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 3); + }); + + v0.Emplace(Any(4)); + v0.Traverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 4); + }); + v0.Erase(Any(1)); + for (auto i = 2; i <= 4; i++) { + v0.Contains(Any(std::ref(i))); + } +} + +TEST(AnyTest, StdUnorderedMapViewTest) +{ + Any a0 = std::unordered_map { + { 1, false }, + { 2, true } + }; + const StdUnorderedMapView v0(a0); + ASSERT_EQ(v0.KeyType(), GetTypeInfo()); + ASSERT_EQ(v0.ValueType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 2); + ASSERT_TRUE(v0.At(Any(2)).As()); + v0.At(Any(1)).As() = true; + + v0.GetOrAdd(Any(3)).As() = true; + ASSERT_TRUE(v0.Contains(Any(3))); + ASSERT_TRUE(v0.At(Any(3)).As()); + v0.Emplace(Any(4), Any(true)); + + auto traverser = [](const Any& inKey, const Any& inValue) -> void { + const int keyNum = inKey.As(); + ASSERT_TRUE(keyNum >= 1 && keyNum <= 4); + ASSERT_TRUE(inValue.As()); + }; + v0.Traverse(traverser); + v0.ConstTraverse(traverser); +} + +TEST(AnyTest, StdMapViewTest) +{ + Any a0 = std::map { + { 1, false }, + { 2, true } + }; + const StdMapView v0(a0); + ASSERT_EQ(v0.KeyType(), GetTypeInfo()); + ASSERT_EQ(v0.ValueType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 2); + ASSERT_TRUE(v0.At(Any(2)).As()); + v0.At(Any(1)).As() = true; + + v0.GetOrAdd(Any(3)).As() = true; + ASSERT_TRUE(v0.Contains(Any(3))); + ASSERT_TRUE(v0.At(Any(3)).As()); + v0.Emplace(Any(4), Any(true)); + + auto traverser = [](const Any& inKey, const Any& inValue) -> void { + const int keyNum = inKey.As(); + ASSERT_TRUE(keyNum >= 1 && keyNum <= 4); + ASSERT_TRUE(inValue.As()); + }; + v0.Traverse(traverser); + v0.ConstTraverse(traverser); +} + +TEST(AnyTest, StdTupleViewTest) +{ + Any a0 = std::tuple { 1, true, "2" }; + const StdTupleView v0(a0); + ASSERT_EQ(v0.Size(), 3); + ASSERT_EQ(v0.ElementType(0), GetTypeInfo()); + ASSERT_EQ(v0.ElementType(1), GetTypeInfo()); + ASSERT_EQ(v0.ElementType(2), GetTypeInfo()); + ASSERT_EQ(v0.Get(0).As(), 1); + ASSERT_TRUE(v0.Get(1).As()); + ASSERT_EQ(v0.Get(2).As(), "2"); + + int count = 0; + v0.Traverse([&](const Any& inRef) -> void { + if (count == 0) { + ASSERT_EQ(inRef.As(), 1); + } else if (count == 1) { + ASSERT_TRUE(inRef.As()); + } else if (count == 2) { + ASSERT_EQ(inRef.As(), "2"); + } + count++; + }); + ASSERT_EQ(count, 3); +} diff --git a/Engine/Source/Mirror/Test/AnyTest.h b/Engine/Source/Mirror/Test/AnyTest.h index cfd0d1d4..a91687be 100644 --- a/Engine/Source/Mirror/Test/AnyTest.h +++ b/Engine/Source/Mirror/Test/AnyTest.h @@ -34,6 +34,22 @@ struct AnyMoveCtorTest { uint8_t& moveTime; }; +struct AnyCopyAssignTest { + AnyCopyAssignTest(); + AnyCopyAssignTest(AnyCopyAssignTest&& inOther) noexcept; + AnyCopyAssignTest& operator=(const AnyCopyAssignTest& inOther); + + bool called; +}; + +struct AnyMoveAssignTest { + AnyMoveAssignTest(); + AnyMoveAssignTest(AnyMoveAssignTest&& inOther) noexcept; + AnyMoveAssignTest& operator=(AnyMoveAssignTest&& inOther) noexcept; + + bool called; +}; + struct AnyBasicTest { int a; float b; diff --git a/Engine/Source/Mirror/Test/RegistryTest.cpp b/Engine/Source/Mirror/Test/RegistryTest.cpp index b0fc2b4b..17afdce1 100644 --- a/Engine/Source/Mirror/Test/RegistryTest.cpp +++ b/Engine/Source/Mirror/Test/RegistryTest.cpp @@ -26,6 +26,11 @@ void F2(int& outValue) outValue = 1; } +int F3(int&& inValue) +{ + return std::move(inValue); +} + int C0::v0 = 0; int& C0::F0() @@ -105,6 +110,13 @@ TEST(RegistryTest, GlobalScopeTest) function.InvokeDyn({ Mirror::Any(std::ref(value)) }); ASSERT_EQ(value, 1); } + + { + const auto& function = globalScope.GetFunction("F3"); + int value = 1; + function.Invoke(std::ref(value)); + ASSERT_EQ(value, 1); + } } TEST(RegistryTest, ClassTest) @@ -147,10 +159,10 @@ TEST(RegistryTest, ClassTest) const auto& b = clazz.GetMemberVariable("b"); auto object = constructor.New(1, 2); - Mirror::Any objectRef = *object.As(); + Mirror::Any objectRef = object.Deref(); ASSERT_EQ(a.GetDyn(objectRef).As(), 1); ASSERT_EQ(b.GetDyn(objectRef).As(), 2); - destructor.InvokeDyn(objectRef); + destructor.DeleteDyn(object); } { diff --git a/Engine/Source/Mirror/Test/RegistryTest.h b/Engine/Source/Mirror/Test/RegistryTest.h index 6d801d92..2dce6c80 100644 --- a/Engine/Source/Mirror/Test/RegistryTest.h +++ b/Engine/Source/Mirror/Test/RegistryTest.h @@ -11,6 +11,7 @@ EProperty(testKey=v0) extern int v0; EFunc() int F0(const int a, const int b); EFunc() int& F1(); EFunc() void F2(int& outValue); +EFunc() int F3(int&& inValue); struct EClass(testKey=C0) C0 { EClassBody(C0) diff --git a/Engine/Source/Mirror/Test/SerializationTest.cpp b/Engine/Source/Mirror/Test/SerializationTest.cpp index e3071bda..530c8b2e 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.cpp +++ b/Engine/Source/Mirror/Test/SerializationTest.cpp @@ -10,6 +10,7 @@ #include #include #include +using namespace Mirror; int ga = 1; float gb = 2.0f; @@ -188,6 +189,13 @@ TEST(SerializationTest, ReflNodeSerializationTest) PerformSerializationTest(fileName, &enun->GetValue("a")); } +TEST(SerializationTest, MetaObjectSerializationTest) +{ + PerformJsonSerializationTest( + SerializationTestStruct2 { 1, 2.0f, "3", 4.0 }, + ""); +} + TEST(SerializationTest, EnumJsonSerializationTest) { PerformJsonSerializationTest( diff --git a/Engine/Source/Mirror/Test/SerializationTest.h b/Engine/Source/Mirror/Test/SerializationTest.h index fdd7784b..54e84d26 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.h +++ b/Engine/Source/Mirror/Test/SerializationTest.h @@ -61,6 +61,12 @@ struct EClass() SerializationTestStruct2 : SerializationTestStruct0 { EClassBody(SerializationTestStruct2); EProperty() double d; + + bool operator==(const SerializationTestStruct2& rhs) const + { + return SerializationTestStruct0::operator==(rhs) + && d == rhs.d; + } }; struct EClass() SerializationTestStruct3 { diff --git a/Engine/Source/Render/CMakeLists.txt b/Engine/Source/Render/CMakeLists.txt index f05a258f..3efbf662 100644 --- a/Engine/Source/Render/CMakeLists.txt +++ b/Engine/Source/Render/CMakeLists.txt @@ -1,20 +1,27 @@ -# TODO for dxc, replace this with real dxc lib someday ? if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(PLATFORM_LIBS VulkanSDK) endif() -file(GLOB_RECURSE SOURCES Src/*.cpp) +file(GLOB SOURCES Src/*.cpp) AddLibrary( - NAME Render + NAME Render.Static TYPE STATIC SRC ${SOURCES} PUBLIC_INC Include - LIB RHI ${PLATFORM_LIBS} dxc spirv-cross + LIB Core RHI ${PLATFORM_LIBS} dxc spirv-cross +) + +file(GLOB SHARED_SOURCES SharedSrc/*.cpp) +AddLibrary( + NAME Render + TYPE SHARED + SRC ${SHARED_SOURCES} + LIB Render.Static ) file(GLOB TEST_SOURCES Test/*.cpp) AddTest( NAME Render.Test SRC ${TEST_SOURCES} - LIB Render + LIB RHI Render.Static ) diff --git a/Engine/Source/Render/Include/Render/Canvas.h b/Engine/Source/Render/Include/Render/Canvas.h deleted file mode 100644 index 6ae6f61a..00000000 --- a/Engine/Source/Render/Include/Render/Canvas.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by johnk on 2022/8/3. -// - -#pragma once - -namespace Render { - class Canvas { - public: - void Destroy() const; - // TODO - }; -} diff --git a/Engine/Source/Rendering/Include/Rendering/RenderGraph.h b/Engine/Source/Render/Include/Render/RenderGraph.h similarity index 99% rename from Engine/Source/Rendering/Include/Rendering/RenderGraph.h rename to Engine/Source/Render/Include/Render/RenderGraph.h index 24a02272..afd71db1 100644 --- a/Engine/Source/Rendering/Include/Rendering/RenderGraph.h +++ b/Engine/Source/Render/Include/Render/RenderGraph.h @@ -10,10 +10,10 @@ #include #include -#include -#include +#include +#include -namespace Rendering { +namespace Render { class RGBuilder; enum class RGResType : uint8_t { diff --git a/Engine/Source/Rendering/Include/Rendering/RenderingModule.h b/Engine/Source/Render/Include/Render/RenderModule.h similarity index 72% rename from Engine/Source/Rendering/Include/Rendering/RenderingModule.h rename to Engine/Source/Render/Include/Render/RenderModule.h index 5a511145..c7890183 100644 --- a/Engine/Source/Rendering/Include/Rendering/RenderingModule.h +++ b/Engine/Source/Render/Include/Render/RenderModule.h @@ -9,27 +9,27 @@ #include #include #include -#include +#include #include -namespace Rendering { - struct RenderingModuleInitParams { +namespace Render { + struct RenderModuleInitParams { RHI::RHIType rhiType; }; - class RENDERING_API RenderingModule final : public Core::Module { + class RENDER_API RenderModule final : public Core::Module { public: - RenderingModule(); - ~RenderingModule() override; + RenderModule(); + ~RenderModule() override; void OnLoad() override; void OnUnload() override; Core::ModuleType Type() const override; - void Initialize(const RenderingModuleInitParams& inParams); + void Initialize(const RenderModuleInitParams& inParams); + void DeInitialize(); RHI::Device* GetDevice() const; - Render::IScene* AllocateScene(); - void DestroyScene(Render::IScene* inScene); + Scene* AllocateScene(); void ShutdownRenderingThread(); void FlushAllRenderingCommands() const; diff --git a/Engine/Source/Rendering/Include/Rendering/Renderer.h b/Engine/Source/Render/Include/Render/Renderer.h similarity index 57% rename from Engine/Source/Rendering/Include/Rendering/Renderer.h rename to Engine/Source/Render/Include/Render/Renderer.h index 959df5d3..b7873aab 100644 --- a/Engine/Source/Rendering/Include/Rendering/Renderer.h +++ b/Engine/Source/Render/Include/Render/Renderer.h @@ -7,9 +7,6 @@ #include #include -#include -#include - -namespace Rendering { +namespace Render { // TODO } diff --git a/Engine/Source/Rendering/Include/Rendering/RenderingCache.h b/Engine/Source/Render/Include/Render/RenderingCache.h similarity index 99% rename from Engine/Source/Rendering/Include/Rendering/RenderingCache.h rename to Engine/Source/Render/Include/Render/RenderingCache.h index 9747d55c..15284225 100644 --- a/Engine/Source/Rendering/Include/Rendering/RenderingCache.h +++ b/Engine/Source/Render/Include/Render/RenderingCache.h @@ -9,7 +9,7 @@ #include #include -namespace Rendering { +namespace Render { class PipelineLayout; class ComputePipelineState; class RasterPipelineState; diff --git a/Engine/Source/Rendering/Include/Rendering/ResourcePool.h b/Engine/Source/Render/Include/Render/ResourcePool.h similarity index 99% rename from Engine/Source/Rendering/Include/Rendering/ResourcePool.h rename to Engine/Source/Render/Include/Render/ResourcePool.h index 1f183fe6..68733e91 100644 --- a/Engine/Source/Rendering/Include/Rendering/ResourcePool.h +++ b/Engine/Source/Render/Include/Render/ResourcePool.h @@ -11,7 +11,7 @@ #include #include -namespace Rendering { +namespace Render { template struct RHIResTraits {}; @@ -63,7 +63,7 @@ namespace Rendering { using TexturePool = RGResourcePool; } -namespace Rendering { +namespace Render { template <> struct RHIResTraits { using DescType = RHI::BufferCreateInfo; diff --git a/Engine/Source/Render/Include/Render/Scene.h b/Engine/Source/Render/Include/Render/Scene.h index bda4749c..d34a69f2 100644 --- a/Engine/Source/Render/Include/Render/Scene.h +++ b/Engine/Source/Render/Include/Render/Scene.h @@ -1,19 +1,31 @@ // -// Created by johnk on 2022/8/3. +// Created by johnk on 2023/7/22. // #pragma once +#include #include -#include namespace Render { - class IScene { + template using SPPool = Common::TrunkList; + template using SPHandle = typename SPPool::Handle; + template using SPPatcher = std::function; + + using LightSPPool = SPPool; + using LightSPH = SPHandle; + using LightSPPatcher = SPPatcher; + + class Scene final { public: - virtual ~IScene() = default; - virtual void AddLight(ILightSceneProxy* inProxy) = 0; - virtual void RemoveLight(ILightSceneProxy* inProxy) = 0; - virtual void AddPrimitive(IPrimitiveSceneProxy* inProxy) = 0; - virtual void RemovePrimitive(IPrimitiveSceneProxy* inProxy) = 0; + Scene(); + ~Scene(); + + LightSPH AddLight(const LightSceneProxy& inLight); + void RemoveLight(const LightSPH& inHandle); + void PatchLight(const LightSPH& inHandle, const LightSPPatcher& inPatcher); + + private: + LightSPPool lights; }; } diff --git a/Engine/Source/Render/Include/Render/SceneProxy/Light.h b/Engine/Source/Render/Include/Render/SceneProxy/Light.h index a6bb11b5..33c2b325 100644 --- a/Engine/Source/Render/Include/Render/SceneProxy/Light.h +++ b/Engine/Source/Render/Include/Render/SceneProxy/Light.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include @@ -15,19 +17,24 @@ namespace Render { max }; - class ILightSceneProxy { - public: - ILightSceneProxy(); - virtual ~ILightSceneProxy(); - virtual Common::FMat4x4 RGetLocalToWorld() const; - virtual LightType RGetLightType() const; - virtual Common::Color RGetColor() const; - virtual float RGetIntensity() const; - - protected: - Common::FMat4x4 worldMatrix; + struct DirectionalLightSceneProxyPart { + // TODO + }; + + struct PointLightSceneProxyPart { + float radius; + // TODO + }; + + struct SpotLightSceneProxyPart { + // TODO + }; + + struct LightSceneProxy { LightType type; + Common::FMat4x4 localToWorld; Common::Color color; float intensity; + std::variant typedPart; }; } diff --git a/Engine/Source/Render/Include/Render/SceneProxy/Primitive.h b/Engine/Source/Render/Include/Render/SceneProxy/Primitive.h deleted file mode 100644 index 81b61ac6..00000000 --- a/Engine/Source/Render/Include/Render/SceneProxy/Primitive.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by johnk on 2023/8/16. -// - -#pragma once - -namespace Render { - class IPrimitiveSceneProxy { - public: - IPrimitiveSceneProxy(); - virtual ~IPrimitiveSceneProxy(); - }; -} diff --git a/Engine/Source/Rendering/SharedSrc/RenderingModule.cpp b/Engine/Source/Render/SharedSrc/RenderModule.cpp similarity index 57% rename from Engine/Source/Rendering/SharedSrc/RenderingModule.cpp rename to Engine/Source/Render/SharedSrc/RenderModule.cpp index c70d4782..1d4cfe5b 100644 --- a/Engine/Source/Rendering/SharedSrc/RenderingModule.cpp +++ b/Engine/Source/Render/SharedSrc/RenderModule.cpp @@ -2,34 +2,34 @@ // Created by johnk on 2023/8/4. // -#include -#include +#include +#include -namespace Rendering { - RenderingModule::RenderingModule() +namespace Render { + RenderModule::RenderModule() : initialized(false) , rhiInstance(nullptr) { } - RenderingModule::~RenderingModule() = default; + RenderModule::~RenderModule() = default; - void RenderingModule::OnLoad() + void RenderModule::OnLoad() { Module::OnLoad(); } - void RenderingModule::OnUnload() + void RenderModule::OnUnload() { Module::OnUnload(); } - Core::ModuleType RenderingModule::Type() const + Core::ModuleType RenderModule::Type() const { return Core::ModuleType::mDynamic; } - void RenderingModule::Initialize(const RenderingModuleInitParams& inParams) + void RenderModule::Initialize(const RenderModuleInitParams& inParams) { Assert(!initialized); @@ -45,31 +45,34 @@ namespace Rendering { initialized = true; } - RHI::Device* RenderingModule::GetDevice() const + void RenderModule::DeInitialize() { - return rhiDevice.Get(); + renderingThread = nullptr; + rhiInstance = nullptr; + rhiDevice = nullptr; + initialized = false; } - Render::IScene* RenderingModule::AllocateScene() // NOLINT + RHI::Device* RenderModule::GetDevice() const { - return new Scene(); + return rhiDevice.Get(); } - void RenderingModule::DestroyScene(Render::IScene* inScene) // NOLINT + Render::Scene* RenderModule::AllocateScene() // NOLINT { - delete inScene; + return new Scene(); } - void RenderingModule::ShutdownRenderingThread() + void RenderModule::ShutdownRenderingThread() { renderingThread = nullptr; } - void RenderingModule::FlushAllRenderingCommands() const + void RenderModule::FlushAllRenderingCommands() const { Assert(renderingThread != nullptr); renderingThread->Flush(); } } -IMPLEMENT_DYNAMIC_MODULE(RENDERING_API, Rendering::RenderingModule); +IMPLEMENT_DYNAMIC_MODULE(RENDER_API, Render::RenderModule); diff --git a/Engine/Source/Render/Src/Canvas.cpp b/Engine/Source/Render/Src/Canvas.cpp deleted file mode 100644 index 63ba6a78..00000000 --- a/Engine/Source/Render/Src/Canvas.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by johnk on 2022/8/4. -// - -#include - -namespace Render { - void Canvas::Destroy() const - { - delete this; - } -} diff --git a/Engine/Source/Rendering/Src/RenderGraph.cpp b/Engine/Source/Render/Src/RenderGraph.cpp similarity index 99% rename from Engine/Source/Rendering/Src/RenderGraph.cpp rename to Engine/Source/Render/Src/RenderGraph.cpp index 4ac1dbf4..bb421d4e 100644 --- a/Engine/Source/Rendering/Src/RenderGraph.cpp +++ b/Engine/Source/Render/Src/RenderGraph.cpp @@ -4,11 +4,11 @@ #include -#include -#include +#include +#include #include -namespace Rendering::Internal { +namespace Render::Internal { static void ComputeReadsWritesForBindGroup(const RGBindGroupDesc& inDesc, std::unordered_set& outReads, std::unordered_set& outWrites) { for (const auto& [name, item] : inDesc.items) { @@ -55,7 +55,7 @@ namespace Rendering::Internal { } } -namespace Rendering { +namespace Render { RGResource::RGResource(const RGResType inType) : type(inType) , forceUsed(false) @@ -644,8 +644,8 @@ namespace Rendering { { auto collectQueueReadWrites = [this](const std::vector& passes, std::unordered_set& outReads, std::unordered_set& outWrites) -> void { for (auto* pass : passes) { - Common::SetUtils::GetUnionInline(outReads, passReadsMap.at(pass)); - Common::SetUtils::GetUnionInline(outWrites, passWritesMap.at(pass)); + Common::SetUtils::GetUnionInplace(outReads, passReadsMap.at(pass)); + Common::SetUtils::GetUnionInplace(outWrites, passWritesMap.at(pass)); } }; diff --git a/Engine/Source/Render/Src/Renderer.cpp b/Engine/Source/Render/Src/Renderer.cpp new file mode 100644 index 00000000..0472ce3b --- /dev/null +++ b/Engine/Source/Render/Src/Renderer.cpp @@ -0,0 +1,9 @@ +// +// Created by johnk on 2022/8/3. +// + +#include + +namespace Render { + +} diff --git a/Engine/Source/Rendering/Src/RenderingCache.cpp b/Engine/Source/Render/Src/RenderingCache.cpp similarity index 99% rename from Engine/Source/Rendering/Src/RenderingCache.cpp rename to Engine/Source/Render/Src/RenderingCache.cpp index bc479587..272ebbac 100644 --- a/Engine/Source/Rendering/Src/RenderingCache.cpp +++ b/Engine/Source/Render/Src/RenderingCache.cpp @@ -2,13 +2,13 @@ // Created by johnk on 2023/3/11. // -#include +#include #include #include -namespace Rendering { +namespace Render { class PipelineLayoutCache { public: static PipelineLayoutCache& Get(RHI::Device& device); @@ -58,7 +58,7 @@ namespace Rendering { } } -namespace Rendering { +namespace Render { RVertexBinding::RVertexBinding() : semanticName() , semanticIndex(0) diff --git a/Engine/Source/Render/Src/Scene.cpp b/Engine/Source/Render/Src/Scene.cpp new file mode 100644 index 00000000..62f2bf6f --- /dev/null +++ b/Engine/Source/Render/Src/Scene.cpp @@ -0,0 +1,12 @@ +// +// Created by johnk on 2023/8/17. +// + +#include +#include + +namespace Render { + Scene::Scene() = default; + + Scene::~Scene() = default; +} diff --git a/Engine/Source/Render/Src/SceneProxy/Light.cpp b/Engine/Source/Render/Src/SceneProxy/Light.cpp deleted file mode 100644 index 75c8a2c2..00000000 --- a/Engine/Source/Render/Src/SceneProxy/Light.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by johnk on 2023/8/14. -// - -#include - -namespace Render { - ILightSceneProxy::ILightSceneProxy() - : worldMatrix(Common::FMat4x4Consts::identity) - , type(LightType::max) - , color(Common::ColorConsts::white) - , intensity(0.f) - { - } - - ILightSceneProxy::~ILightSceneProxy() = default; - - Common::FMat4x4 ILightSceneProxy::RGetLocalToWorld() const - { - return worldMatrix; - } - - LightType ILightSceneProxy::RGetLightType() const - { - return type; - } - - Common::Color ILightSceneProxy::RGetColor() const - { - return color; - } - - float ILightSceneProxy::RGetIntensity() const - { - return intensity; - } -} diff --git a/Engine/Source/Render/Src/SceneProxy/Primitive.cpp b/Engine/Source/Render/Src/SceneProxy/Primitive.cpp deleted file mode 100644 index c6a4895f..00000000 --- a/Engine/Source/Render/Src/SceneProxy/Primitive.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by johnk on 2023/8/16. -// - -#include - -namespace Render { - IPrimitiveSceneProxy::IPrimitiveSceneProxy() = default; - - IPrimitiveSceneProxy::~IPrimitiveSceneProxy() = default; -} diff --git a/Engine/Source/Rendering/Test/ResourcePoolTest.cpp b/Engine/Source/Render/Test/ResourcePoolTest.cpp similarity index 96% rename from Engine/Source/Rendering/Test/ResourcePoolTest.cpp rename to Engine/Source/Render/Test/ResourcePoolTest.cpp index 47c1b21b..2e07f3df 100644 --- a/Engine/Source/Rendering/Test/ResourcePoolTest.cpp +++ b/Engine/Source/Render/Test/ResourcePoolTest.cpp @@ -4,9 +4,9 @@ #include -#include +#include -using namespace Rendering; +using namespace Render; struct ResourcePoolTest : testing::Test { void SetUp() override diff --git a/Engine/Source/Rendering/CMakeLists.txt b/Engine/Source/Rendering/CMakeLists.txt deleted file mode 100644 index c03250d8..00000000 --- a/Engine/Source/Rendering/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -file(GLOB SOURCES Src/*.cpp) -AddLibrary( - NAME Rendering.Static - TYPE STATIC - SRC ${SOURCES} - PUBLIC_INC Include - LIB Render Core -) - -file(GLOB SHARED_SOURCES SharedSrc/*.cpp) -AddLibrary( - NAME Rendering - TYPE SHARED - SRC ${SHARED_SOURCES} - LIB Rendering.Static -) - -file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( - NAME Rendering.Test - SRC ${TEST_SOURCES} - LIB RHI Rendering.Static -) diff --git a/Engine/Source/Rendering/Include/Rendering/Scene.h b/Engine/Source/Rendering/Include/Rendering/Scene.h deleted file mode 100644 index 6604d7e0..00000000 --- a/Engine/Source/Rendering/Include/Rendering/Scene.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by johnk on 2023/7/22. -// - -#pragma once - -#include - -#include - -namespace Rendering { - class Scene final : public Render::IScene { - public: - ~Scene() override; - void AddLight(Render::ILightSceneProxy* inProxy) override; - void RemoveLight(Render::ILightSceneProxy* inProxy) override; - void AddPrimitive(Render::IPrimitiveSceneProxy* inProxy) override; - void RemovePrimitive(Render::IPrimitiveSceneProxy* inProxy) override; - - private: - std::unordered_set lights; - std::unordered_set primitives; - }; -} diff --git a/Engine/Source/Rendering/Src/Renderer.cpp b/Engine/Source/Rendering/Src/Renderer.cpp deleted file mode 100644 index d56a9e16..00000000 --- a/Engine/Source/Rendering/Src/Renderer.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by johnk on 2022/8/3. -// - -#include - -namespace Rendering { - -} diff --git a/Engine/Source/Rendering/Src/Scene.cpp b/Engine/Source/Rendering/Src/Scene.cpp deleted file mode 100644 index 08c5b8e4..00000000 --- a/Engine/Source/Rendering/Src/Scene.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// -// Created by johnk on 2023/8/17. -// - -#include -#include - -namespace Rendering { - Scene::~Scene() = default; - - void Scene::AddLight(Render::ILightSceneProxy* inProxy) - { - Assert(!lights.contains(inProxy)); - lights.emplace(inProxy); - } - - void Scene::RemoveLight(Render::ILightSceneProxy* inProxy) - { - Assert(lights.contains(inProxy)); - lights.erase(inProxy); - } - - void Scene::AddPrimitive(Render::IPrimitiveSceneProxy* inProxy) - { - Assert(!primitives.contains(inProxy)); - primitives.erase(inProxy); - } - - void Scene::RemovePrimitive(Render::IPrimitiveSceneProxy* inProxy) - { - Assert(primitives.contains(inProxy)); - primitives.emplace(inProxy); - } -} diff --git a/Engine/Source/Runtime/CMakeLists.txt b/Engine/Source/Runtime/CMakeLists.txt index cb051bfd..3e127d5b 100644 --- a/Engine/Source/Runtime/CMakeLists.txt +++ b/Engine/Source/Runtime/CMakeLists.txt @@ -5,7 +5,7 @@ AddLibrary( SRC ${SOURCES} PUBLIC_INC Include REFLECT Include - LIB Core Mirror assimp-lib Render EnTT + LIB Core Mirror assimp-lib Render ) file(GLOB TEST_SOURCES Test/*.cpp) diff --git a/Engine/Source/Runtime/Include/Runtime/Asset.h b/Engine/Source/Runtime/Include/Runtime/Asset.h index 13aff30d..488f9c98 100644 --- a/Engine/Source/Runtime/Include/Runtime/Asset.h +++ b/Engine/Source/Runtime/Include/Runtime/Asset.h @@ -321,7 +321,7 @@ namespace Runtime { template void AsyncLoad(const Core::Uri& uri, const OnAssetLoaded& onAssetLoaded) { - threadPool.EmplaceTask([this, uri, onAssetLoaded]() -> void { + threadPool.EmplaceTask([=]() -> void { AssetRef result = nullptr; { std::unique_lock lock(mutex); diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Light.h b/Engine/Source/Runtime/Include/Runtime/Component/Light.h new file mode 100644 index 00000000..67ca0ce5 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/Light.h @@ -0,0 +1,43 @@ +// +// Created by johnk on 2024/10/14. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass() DirectionalLight final { + EClassBody(DirectionalLight) + + DirectionalLight(); + + EProperty() Common::Color color; + EProperty() float intensity; + EProperty() bool castShadows; + }; + + struct RUNTIME_API EClass() PointLight final { + EClassBody(PointLight) + + PointLight(); + + EProperty() Common::Color color; + EProperty() float intensity; + EProperty() bool castShadows; + EProperty() float radius; + }; + + struct RUNTIME_API EClass() SpotLight final { + EClassBody(SpotLight) + + SpotLight(); + + EProperty() Common::Color color; + EProperty() float intensity; + EProperty() bool castShadows; + // TODO + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Transform.h b/Engine/Source/Runtime/Include/Runtime/Component/Transform.h new file mode 100644 index 00000000..8f5bf2bb --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/Transform.h @@ -0,0 +1,20 @@ +// +// Created by johnk on 2024/10/14. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass() Transform final { + EClassBody(Transform) + + Transform(); + explicit Transform(const Common::FTransform& inLocalToWorld); + + EProperty() Common::FTransform localToWorld; + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Component/View.h b/Engine/Source/Runtime/Include/Runtime/Component/View.h new file mode 100644 index 00000000..22e6f11c --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/View.h @@ -0,0 +1,34 @@ +// +// Created by johnk on 2024/10/14. +// + +#pragma once + +#include + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass() Camera final { + EClassBody(Camera) + + Camera(); + explicit Camera(const Common::FReversedZOrthoProjection& inProjection); + explicit Camera(const Common::FReversedZPerspectiveProjection& inProjection); + + EProperty() std::variant projection; + }; + + struct RUNTIME_API EClass() SceneCapture final { + EClassBody(SceneCapture) + + SceneCapture(); + explicit SceneCapture(const Common::FReversedZOrthoProjection& inProjection); + explicit SceneCapture(const Common::FReversedZPerspectiveProjection& inProjection); + + EProperty() std::variant projection; + // TODO texture render target + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h new file mode 100644 index 00000000..17370003 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -0,0 +1,890 @@ +// +// Created by johnk on 2024/10/31. +// + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace Runtime { + using Entity = size_t; + using CompClass = const Mirror::Class*; + using GCompClass = const Mirror::Class*; + using SystemClass = const Mirror::Class*; + + class ECRegistry; + + class EClass() System { + public: + EClassBody(System) + + explicit System(ECRegistry& inRegistry); + virtual ~System(); + virtual void Execute(float inDeltaTimeMs); + + protected: + ECRegistry& registry; + }; +} + +namespace Runtime::Internal { + using ArchetypeId = Mirror::TypeId; + using ElemPtr = void*; + + template const Mirror::Class* GetClass(); + template struct LambdaTraits; + + class CompRtti { + public: + explicit CompRtti(CompClass inClass); + void Bind(size_t inOffset); + Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const; + Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const; + void Destruct(ElemPtr inElem) const; + Mirror::Any Get(ElemPtr inElem) const; + CompClass Class() const; + size_t Offset() const; + size_t Size() const; + + private: + using MoveConstructFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Any&); + using MoveAssignFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Any&); + using DestructorFunc = void(ElemPtr, size_t); + using GetFunc = Mirror::Any(ElemPtr, size_t); + + CompClass clazz; + // runtime, need Bind() + bool bound; + size_t offset; + }; + + class Archetype { + public: + explicit Archetype(const std::vector& inRttiVec); + + bool Contains(CompClass inClazz) const; + bool ContainsAll(const std::vector& inClasses) const; + bool NotContainsAny(const std::vector& inCompClasses) const; + ElemPtr EmplaceElem(Entity inEntity); + ElemPtr EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec); + Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef); + void EraseElem(Entity inEntity); + ElemPtr GetElem(Entity inEntity) const; + Mirror::Any GetComp(Entity inEntity, CompClass inCompClass); + Mirror::Any GetComp(Entity inEntity, CompClass inCompClass) const; + size_t Size() const; + auto All() const; + const std::vector& GetRttiVec() const; + ArchetypeId Id() const; + std::vector NewRttiVecByAdd(const CompRtti& inRtti) const; + std::vector NewRttiVecByRemove(const CompRtti& inRtti) const; + + private: + using CompRttiIndex = size_t; + using ElemIndex = size_t; + + const CompRtti* FindCompRtti(CompClass clazz) const; + const CompRtti& GetCompRtti(CompClass clazz) const; + size_t Capacity() const; + void Reserve(float inRatio = 1.5f); + ElemPtr AllocateNewElemBack(); + ElemPtr ElemAt(std::vector& inMemory, size_t inIndex) const; + ElemPtr ElemAt(size_t inIndex) const; + + ArchetypeId id; + size_t size; + size_t elemSize; + std::vector rttiVec; + std::unordered_map rttiMap; + std::unordered_map entityMap; + std::unordered_map elemMap; + std::vector memory; + }; + + class EntityPool { + public: + using EntityTraverseFunc = std::function; + using ConstIter = std::set::const_iterator; + + EntityPool(); + + size_t Size() const; + bool Valid(Entity inEntity) const; + Entity Allocate(); + void Free(Entity inEntity); + void Clear(); + void Each(const EntityTraverseFunc& inFunc) const; + void SetArchetype(Entity inEntity, ArchetypeId inArchetypeId); + ArchetypeId GetArchetype(Entity inEntity) const; + ConstIter Begin() const; + ConstIter End() const; + + private: + size_t counter; + std::set free; + std::set allocated; + std::unordered_map archetypeMap; + }; + + class SystemFactory { + public: + explicit SystemFactory(SystemClass inClass); + Common::UniqueRef Build(ECRegistry& inRegistry) const; + std::unordered_map GetArguments(); + const std::unordered_map& GetArguments() const; + + private: + void BuildArgumentLists(); + + SystemClass clazz; + std::unordered_map arguments; + }; +} + +namespace Runtime { + template + class ScopedUpdater { + public: + ScopedUpdater(ECRegistry& inRegistry, Entity inEntity, C& inCompRef); + ~ScopedUpdater(); + + NonCopyable(ScopedUpdater) + NonMovable(ScopedUpdater) + + C* operator->() const; + + private: + ECRegistry& registry; + Entity entity; + C& compRef; + }; + + template + class GScopedUpdater { + public: + GScopedUpdater(ECRegistry& inRegistry, G& inGlobalCompRef); + ~GScopedUpdater(); + + NonCopyable(GScopedUpdater) + NonMovable(GScopedUpdater) + + G* operator->() const; + + private: + ECRegistry& registry; + G& globalCompRef; + }; + + class ScopedUpdaterDyn { + public: + ScopedUpdaterDyn(ECRegistry& inRegistry, CompClass inClass, Entity inEntity, const Mirror::Any& inCompRef); + ~ScopedUpdaterDyn(); + + NonCopyable(ScopedUpdaterDyn) + NonMovable(ScopedUpdaterDyn) + + template T As() const; + + private: + ECRegistry& registry; + CompClass clazz; + Entity entity; + const Mirror::Any& compRef; + }; + + class GScopedUpdaterDyn { + public: + GScopedUpdaterDyn(ECRegistry& inRegistry, GCompClass inClass, const Mirror::Any& inGlobalCompRef); + ~GScopedUpdaterDyn(); + + NonCopyable(GScopedUpdaterDyn) + NonMovable(GScopedUpdaterDyn) + + template T As() const; + + private: + ECRegistry& registry; + GCompClass clazz; + const Mirror::Any& globalCompRef; + }; + + template + struct Contains {}; + + template + struct Exclude {}; + + template + class View; + + template + class View, C...> { + public: + explicit View(ECRegistry& inRegistry); + NonCopyable(View) + NonMovable(View) + + template void Each(F&& inFunc) const; + auto Begin(); + auto Begin() const; + auto End(); + auto End() const; + auto begin(); + auto begin() const; + auto end(); + auto end() const; + + private: + void Evaluate(ECRegistry& inRegistry); + + std::vector> result; + }; + + class RuntimeViewRule { + public: + RuntimeViewRule(); + template RuntimeViewRule& Include(); + template RuntimeViewRule& Exclude(); + RuntimeViewRule& IncludeDyn(CompClass inClass); + RuntimeViewRule& ExcludeDyn(CompClass inClass); + + private: + friend class RuntimeView; + + std::unordered_set includes; + std::unordered_set excludes; + }; + + class RuntimeView { + public: + explicit RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); + NonCopyable(RuntimeView) + NonMovable(RuntimeView) + + template void Each(F&& inFunc) const; + auto Begin(); + auto Begin() const; + auto End(); + auto End() const; + auto begin(); + auto begin() const; + auto end(); + auto end() const; + + private: + template void InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const; + template decltype(auto) GetCompRef(std::vector& inComps) const; + void Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); + + std::unordered_map slotMap; + std::vector resultEntities; + std::vector>> result; + }; + + class Observer { + public: + using ConstIter = std::vector::const_iterator; + using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; + using ReceiverDeleter = std::function; + + explicit Observer(ECRegistry& inRegistry); + ~Observer(); + NonCopyable(Observer) + NonMovable(Observer) + + template void ObConstructed(); + template void ObUpdated(); + template void ObRemove(); + void Each(const EntityTraverseFunc& inFunc) const; + void Clear(); + void Reset(); + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; + + private: + void OnEvent(Common::Event& inEvent); + void RecordEntity(ECRegistry& inRegistry, Entity inEntity); + + ECRegistry& registry; + std::vector> receiverHandles; + std::vector entities; + }; + + class MIRROR_API ECRegistry { + public: + using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; + using DynUpdateFunc = std::function; + using ConstIter = Internal::EntityPool::ConstIter; + using CompEvent = Common::Event; + using GCompEvent = Common::Event; + + struct CompEvents { + CompEvent onConstructed; + CompEvent onUpdated; + CompEvent onRemove; + }; + + struct GCompEvents { + GCompEvent onConstructed; + GCompEvent onUpdated; + GCompEvent onRemove; + }; + + ECRegistry(); + ~ECRegistry(); + + ECRegistry(const ECRegistry& inOther); + ECRegistry(ECRegistry&& inOther) noexcept; + ECRegistry& operator=(const ECRegistry& inOther); + ECRegistry& operator=(ECRegistry&& inOther) noexcept; + + void ResetTransients(); + + // entity + Entity Create(); + void Destroy(Entity inEntity); + bool Valid(Entity inEntity) const; + size_t Size() const; + void Clear(); + void Each(const EntityTraverseFunc& inFunc) const; + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; + + // component static + template C& Emplace(Entity inEntity, Args&&... inArgs); + template void Remove(Entity inEntity); + template void NotifyUpdated(Entity inEntity); + template void Update(Entity inEntity, F&& inFunc); + template ScopedUpdater Update(Entity inEntity); + template bool Has(Entity inEntity) const; + template C* Find(Entity inEntity); + template const C* Find(Entity inEntity) const; + template C& Get(Entity inEntity); + template const C& Get(Entity inEntity) const; + template View, C...> View(Exclude); + template CompEvents& Events(); + Observer Observer(); + + // component dynamic + Mirror::Any EmplaceDyn(CompClass inClass, Entity inEntity, const Mirror::ArgumentList& inArgs); + void RemoveDyn(CompClass inClass, Entity inEntity); + void NotifyUpdatedDyn(CompClass inClass, Entity inEntity); + void UpdateDyn(CompClass inClass, Entity inEntity, const DynUpdateFunc& inFunc); + ScopedUpdaterDyn UpdateDyn(CompClass inClass, Entity inEntity); + bool HasDyn(CompClass inClass, Entity inEntity) const; + Mirror::Any FindDyn(CompClass inClass, Entity inEntity); + Mirror::Any FindDyn(CompClass inClass, Entity inEntity) const; + Mirror::Any GetDyn(CompClass inClass, Entity inEntity); + Mirror::Any GetDyn(CompClass inClass, Entity inEntity) const; + CompEvents& EventsDyn(CompClass inClass); + RuntimeView RuntimeView(const RuntimeViewRule& inRule); + + // global component static + template G& GEmplace(Args&&... inArgs); + template void GRemove(); + template void GNotifyUpdated(); + template void GUpdate(F&& inFunc); + template GScopedUpdater GUpdate(); + template bool GHas() const; + template G* GFind(); + template const G* GFind() const; + template G& GGet(); + template const G& GGet() const; + template GCompEvents& GEvents(); + + // global component dynamic + Mirror::Any GEmplaceDyn(GCompClass inClass, const Mirror::ArgumentList& inArgs); + void GRemoveDyn(GCompClass inClass); + void GNotifyUpdatedDyn(GCompClass inClass); + void GUpdateDyn(GCompClass inClass, const DynUpdateFunc& inFunc); + GScopedUpdaterDyn GUpdateDyn(GCompClass inClass); + bool GHasDyn(GCompClass inClass) const; + Mirror::Any GFindDyn(GCompClass inClass); + Mirror::Any GFindDyn(GCompClass inClass) const; + Mirror::Any GGetDyn(GCompClass inClass); + Mirror::Any GGetDyn(GCompClass inClass) const; + GCompEvents& GEventsDyn(GCompClass inClass); + + private: + template friend class View; + friend class RuntimeView; + + template void NotifyConstructed(Entity inEntity); + template void NotifyRemove(Entity inEntity); + template void GNotifyConstructed(); + template void GNotifyRemove(); + void NotifyConstructedDyn(CompClass inClass, Entity inEntity); + void NotifyRemoveDyn(CompClass inClass, Entity inEntity); + void GNotifyConstructedDyn(GCompClass inClass); + void GNotifyRemoveDyn(CompClass inClass); + + Internal::EntityPool entities; + std::unordered_map globalComps; + std::unordered_map archetypes; + // transients + std::unordered_map compEvents; + std::unordered_map globalCompEvents; + }; + + class SystemGroup { + public: + explicit SystemGroup(std::string inName); + + Internal::SystemFactory& EmplaceSystem(SystemClass inClass); + void RemoveSystem(SystemClass inClass); + bool HasSystem(SystemClass inClass) const; + Internal::SystemFactory& GetSystem(SystemClass inClass); + const Internal::SystemFactory& GetSystem(SystemClass inClass) const; + auto GetSystems(); + auto GetSystems() const; + const std::string& GetName() const; + + private: + std::string name; + std::unordered_map systems; + }; + + class SystemGraph { + public: + SystemGraph(); + + SystemGroup& AddGroup(const std::string& inName); + void RemoveGroup(const std::string& inName); + bool HasGroup(const std::string& inName) const; + SystemGroup& GetGroup(const std::string& inName); + const SystemGroup& GetGroup(const std::string& inName) const; + const std::vector& GetGroups() const; + + private: + std::vector systemGroups; + }; + + class SystemPipeline { + public: + explicit SystemPipeline(const SystemGraph& inGraph); + + private: + struct SystemContext { + const Internal::SystemFactory& factory; + Common::UniqueRef instance; + }; + using ActionFunc = std::function; + + void ParallelPerformAction(const ActionFunc& inActionFunc); + + friend class SystemGraphExecutor; + + std::vector> systemGraph; + }; + + class SystemGraphExecutor { + public: + explicit SystemGraphExecutor(ECRegistry& inEcRegistry, const SystemGraph& inSystemGraph); + ~SystemGraphExecutor(); + + NonCopyable(SystemGraphExecutor) + NonMovable(SystemGraphExecutor) + + void Tick(float inDeltaTimeMs); + + private: + ECRegistry& ecRegistry; + SystemGraph systemGraph; + SystemPipeline pipeline; + }; +} + +namespace Runtime::Internal { + template + const Mirror::Class* GetClass() + { + return &Mirror::Class::Get(); + } + + template + struct LambdaTraits> { + static constexpr auto ArgSize = sizeof...(T); + using ArgsTupleType = std::tuple; + }; + + inline auto Archetype::All() const + { + return elemMap | std::ranges::views::values; + } +} // namespace Runtime::Internal + +namespace Runtime { + template + ScopedUpdater::ScopedUpdater(ECRegistry& inRegistry, Entity inEntity, C& inCompRef) + : registry(inRegistry) + , entity(inEntity) + , compRef(inCompRef) + { + } + + template + ScopedUpdater::~ScopedUpdater() + { + registry.NotifyUpdated(entity); + } + + template + C* ScopedUpdater::operator->() const + { + return &compRef; + } + + template + GScopedUpdater::GScopedUpdater(ECRegistry& inRegistry, G& inGlobalCompRef) + : registry(inRegistry) + , globalCompRef(inGlobalCompRef) + { + } + + template + GScopedUpdater::~GScopedUpdater() + { + registry.GNotifyUpdated(); + } + + template + G* GScopedUpdater::operator->() const + { + return &globalCompRef; + } + + template + T ScopedUpdaterDyn::As() const + { + return compRef.As(); + } + + template + T GScopedUpdaterDyn::As() const + { + return globalCompRef.As(); + } + + template + View, C...>::View(ECRegistry& inRegistry) + { + Evaluate(inRegistry); + } + + template + template + void View, C...>::Each(F&& inFunc) const + { + for (const auto& entity : result) { + std::apply(inFunc, entity); + } + } + + template + auto View, C...>::Begin() + { + return result.begin(); + } + + template + auto View, C...>::Begin() const + { + return result.begin(); + } + + template + auto View, C...>::End() + { + return result.end(); + } + + template + auto View, C...>::End() const + { + return result.end(); + } + + template + auto View, C...>::begin() + { + return Begin(); + } + + template + auto View, C...>::begin() const + { + return Begin(); + } + + template + auto View, C...>::end() + { + return End(); + } + + template + auto View, C...>::end() const + { + return End(); + } + + template + void View, C...>::Evaluate(ECRegistry& inRegistry) + { + std::vector includeCompIds; + includeCompIds.reserve(sizeof...(C)); + (void) std::initializer_list { ([&]() -> void { + includeCompIds.emplace_back(Internal::GetClass()); + }(), 0)... }; + + std::vector excludeCompIds; + excludeCompIds.reserve(sizeof...(E)); + (void) std::initializer_list { ([&]() -> void { + excludeCompIds.emplace_back(Internal::GetClass()); + }(), 0)... }; + + for (auto& archetype : inRegistry.archetypes | std::views::values) { + if (!archetype.ContainsAll(includeCompIds) || !archetype.NotContainsAny(excludeCompIds)) { + continue; + } + + result.reserve(result.size() + archetype.Size()); + for (auto entity : archetype.All()) { + result.emplace_back(entity, inRegistry.Get(entity)...); + } + } + } + + template + void RuntimeView::Each(F&& inFunc) const + { + for (const auto& pair : result) { + InvokeTraverseFuncInternal::ArgsTupleType>(std::forward(inFunc), pair, std::make_index_sequence::ArgSize> {}); + } + } + + template + void RuntimeView::InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const + { + inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); + } + + template + decltype(auto) RuntimeView::GetCompRef(std::vector& inComps) const + { + static_assert(std::is_reference_v); + const auto compIndex = slotMap.at(Internal::GetClass()); + return inComps[compIndex].template As(); + } + + template + RuntimeViewRule& RuntimeViewRule::Include() + { + const auto* clazz = Internal::GetClass(); + Assert(!includes.contains(clazz)); + includes.emplace(clazz); + return *this; + } + + template + RuntimeViewRule& RuntimeViewRule::Exclude() + { + const auto* clazz = Internal::GetClass(); + Assert(!excludes.contains(clazz)); + excludes.emplace(clazz); + return *this; + } + + template + void Observer::ObConstructed() + { + OnEvent(registry.Events().onConstructed); + } + + template + void Observer::ObUpdated() + { + OnEvent(registry.Events().onUpdated); + } + + template + void Observer::ObRemove() + { + OnEvent(registry.Events().onRemove); + } + + template + C& ECRegistry::Emplace(Entity inEntity, Args&&... inArgs) + { + return EmplaceDyn(Internal::GetClass(), inEntity, Mirror::ForwardAsArgList(std::forward(inArgs)...)).template As(); + } + + template + void ECRegistry::Remove(Entity inEntity) + { + RemoveDyn(Internal::GetClass(), inEntity); + } + + template + void ECRegistry::Update(Entity inEntity, F&& inFunc) + { + UpdateDyn(Internal::GetClass(), inEntity, std::forward(inFunc)); + } + + template + ScopedUpdater ECRegistry::Update(Entity inEntity) + { + Assert(Valid(inEntity) && Has()); + return { *this, inEntity, Get(inEntity) }; + } + + template + bool ECRegistry::Has(Entity inEntity) const + { + return HasDyn(Internal::GetClass(), inEntity); + } + + template + C* ECRegistry::Find(Entity inEntity) + { + return Has() ? &Get(inEntity) : nullptr; + } + + template + const C* ECRegistry::Find(Entity inEntity) const + { + return Has() ? &Get(inEntity) : nullptr; + } + + template + C& ECRegistry::Get(Entity inEntity) + { + return GetDyn(Internal::GetClass(), inEntity).template As(); + } + + template + const C& ECRegistry::Get(Entity inEntity) const + { + return GetDyn(Internal::GetClass(), inEntity).template As(); + } + + template + View, C...> ECRegistry::View(Exclude) + { + return { *this }; + } + + template + ECRegistry::CompEvents& ECRegistry::Events() + { + return EventsDyn(Internal::GetClass()); + } + + template + void ECRegistry::NotifyUpdated(Entity inEntity) + { + NotifyUpdatedDyn(Internal::GetClass(), inEntity); + } + + template + void ECRegistry::NotifyConstructed(Entity inEntity) + { + NotifyConstructedDyn(Internal::GetClass(), inEntity); + } + + template + void ECRegistry::NotifyRemove(Entity inEntity) + { + NotifyRemoveDyn(Internal::GetClass(), inEntity); + } + + template + G& ECRegistry::GEmplace(Args&&... inArgs) + { + return GEmplaceDyn(Internal::GetClass(), Mirror::ForwardAsArgList(std::forward(inArgs)...)); + } + + template + void ECRegistry::GRemove() + { + return GRemoveDyn(Internal::GetClass()); + } + + template + void ECRegistry::GUpdate(F&& inFunc) + { + GUpdateDyn(Internal::GetClass(), std::forward(inFunc)); + } + + template + GScopedUpdater ECRegistry::GUpdate() + { + Assert(GHas()); + return { *this, GGet() }; + } + + template + bool ECRegistry::GHas() const + { + return GHasDyn(Internal::GetClass()); + } + + template + G* ECRegistry::GFind() + { + return GHas() ? &GGet() : nullptr; + } + + template + const G* ECRegistry::GFind() const + { + return GHas() ? &GGet() : nullptr; + } + + template + G& ECRegistry::GGet() + { + return GGetDyn(Internal::GetClass()).template As(); + } + + template + const G& ECRegistry::GGet() const + { + return GGetDyn(Internal::GetClass()).template As(); + } + + template + ECRegistry::GCompEvents& ECRegistry::GEvents() + { + return GEventsDyn(Internal::GetClass()); + } + + template + void ECRegistry::GNotifyUpdated() + { + GNotifyUpdatedDyn(Internal::GetClass()); + } + + template + void ECRegistry::GNotifyConstructed() + { + GNotifyConstructedDyn(Internal::GetClass()); + } + + template + void ECRegistry::GNotifyRemove() + { + GNotifyRemoveDyn(Internal::GetClass()); + } +} // namespace Runtime diff --git a/Engine/Source/Runtime/Include/Runtime/Engine.h b/Engine/Source/Runtime/Include/Runtime/Engine.h index 5152040e..a0fae201 100644 --- a/Engine/Source/Runtime/Include/Runtime/Engine.h +++ b/Engine/Source/Runtime/Include/Runtime/Engine.h @@ -8,12 +8,14 @@ #include #include +#include namespace Runtime { class World; struct EngineInitParams { std::string projectFile; + std::string rhiType; }; class RUNTIME_API Engine { // NOLINT @@ -24,11 +26,15 @@ namespace Runtime { void MountWorld(World* inWorld); void UnmountWorld(World* inWorld); + Render::RenderModule& GetRenderModule() const; + void Tick(float inTimeMs) const; + Common::UniqueRef CreateWorld(const std::string& inName = "") const; protected: explicit Engine(const EngineInitParams& inParams); std::unordered_set worlds; + Render::RenderModule* renderModule; }; class RUNTIME_API MinEngine final : public Engine { diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 5f9d2bfc..976ae53d 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -1,309 +1,51 @@ // -// Created by johnk on 2024/8/2. +// Created by johnk on 2024/10/31. // #pragma once -#include -#include +#include +#include -#include -#include -#include -#include - -namespace Runtime::Internal { - template const Mirror::Class* GetClassChecked(); - const Mirror::Class* GetClassChecked(const std::string& inName); -} +#include +#include namespace Runtime { - using Entity = entt::entity; - constexpr auto entityNull = entt::null; - - class RUNTIME_API EClass() Component { - EClassBody(Component) - Component(); - }; - - class RUNTIME_API EClass() State { - EClassBody(State) - State(); - }; - - class Commands; - - class RUNTIME_API EClass() System { - EPolyClassBody(System) - System(); - virtual ~System(); - - EFunc() virtual void Setup(Commands& commands) const; - EFunc() virtual void Tick(Commands& commands, float inTimeMs) const; - }; - - template concept StateDerived = std::is_base_of_v; - template concept CompDerived = std::is_base_of_v; - template concept SystemDerived = std::is_base_of_v; - template struct Exclude {}; -} - -namespace Runtime { - class World; - class Ticker; - - template - class CompView { - public: - using Iterator = entt::basic_view; - - explicit CompView(const entt::basic_view& inView); - - template void Each(F&& inFunc); - - Iterator Begin() const; - Iterator End() const; - Iterator ReverseBegin() const; - Iterator ReverseEnd() const; - Iterator begin() const; - Iterator end() const; - - private: - entt::basic_view view; + enum class PlayStatus : uint8_t { + stopped, + playing, + paused, + max }; - // TODO runtime view - - using StateClass = const Mirror::Class*; - using SystemClass = const Mirror::Class*; - - class RUNTIME_API Commands { + class World { public: - ~Commands(); - - Entity CreateEntity(); - void DestroyEntity(Entity inEntity); - - template bool HasState() const; - template S& EmplaceState(Args&&... inArgs); - template S* FindState(); - template const S* FindState() const; - template S& GetState(); - template const S& GetState() const; - template bool HasComp(Entity inEntity) const; - template C& EmplaceComp(Entity inEntity, Args&&... inArgs); - template C* FindComp(Entity inEntity); - template const C* FindComp(Entity inEntity) const; - template C& GetComp(Entity inEntity); - template const C& GetComp(Entity inEntity) const; - - template auto View(Exclude = {}); - template auto View(Exclude = {}) const; - // TODO runtime view - - private: - friend class World; - - explicit Commands(World& inWorld); - - World& world; - }; - - // world is fully runtime structure, we use level to perform persist storage - class RUNTIME_API World { - public: - explicit World(std::string inName = ""); + NonCopyable(World) + NonMovable(World) ~World(); - DefaultCopyable(World) - DefaultMovable(World) + private: + friend class Engine; - template void AddSystem(Args&&... inSystemArgs); - void AddBarrier(); + explicit World(const std::string& inName = ""); + void SetSystemGraph(const SystemGraph& inSystemGraph); + void Reset(); + PlayStatus PlayStatus() const; + bool Stopped() const; + bool Playing() const; + bool Paused() const; void Play(); - void Stop(); - void Pause(); void Resume(); - void Tick(float inFrameTimeMs); - bool Started() const; - bool Playing() const; - - private: - friend class Commands; - - using SystemOp = std::function; - void ExecuteSystemGraph(const SystemOp& inOp); + void Pause(); + void Stop(); + void Tick(float inTimeMs); - bool setuped; - bool playing; std::string name; - std::unordered_map states; - std::unordered_map systems; - std::vector> systemsGraph; - std::vector systemsInBarriers; - entt::registry registry; + Runtime::PlayStatus playStatus; + ECRegistry ecRegistry; + SystemGraph systemGraph; + std::optional executor; }; } -namespace Runtime::Internal { - template - const Mirror::Class* GetClassChecked() - { - return &Mirror::Class::Get(); - } -} - -namespace Runtime { - template - CompView::CompView(const entt::basic_view& inView) - : view(inView) - { - } - - template - template - void CompView::Each(F&& inFunc) - { - view.each(std::forward(inFunc)); - } - - template - typename CompView::Iterator CompView::Begin() const - { - return view.begin(); - } - - template - typename CompView::Iterator CompView::End() const - { - return view.end(); - } - - template - typename CompView::Iterator CompView::ReverseBegin() const - { - return view.rbegin(); - } - - template - typename CompView::Iterator CompView::ReverseEnd() const - { - return view.rend(); - } - - template - typename CompView::Iterator CompView::begin() const - { - return Begin(); - } - - template - typename CompView::Iterator CompView::end() const - { - return End(); - } - - template - bool Commands::HasState() const - { - return world.states.contains(Internal::GetClassChecked()); - } - - template - S& Commands::EmplaceState(Args&&... inArgs) - { - world.states.emplace(Internal::GetClassChecked(), Mirror::Any(S(std::forward(inArgs)...))); - return GetState(); - } - - template - S* Commands::FindState() - { - auto* clazz = Internal::GetClassChecked(); - auto iter = world.states.find(clazz); - return iter == world.states.end() ? nullptr : &iter->second.template As(); - } - - template - const S* Commands::FindState() const - { - auto* clazz = Internal::GetClassChecked(); - auto iter = world.states.find(clazz); - return iter == world.states.end() ? nullptr : &iter->second.template As(); - } - - template - S& Commands::GetState() - { - Assert(HasState()); - return world.states.at(Internal::GetClassChecked()).template As(); - } - - template - const S& Commands::GetState() const - { - Assert(HasState()); - return world.states.at(Internal::GetClassChecked()).template As(); - } - - template - bool Commands::HasComp(Entity inEntity) const - { - return world.registry.try_get(inEntity) != nullptr; - } - - template - C& Commands::EmplaceComp(Entity inEntity, Args&&... inArgs) - { - return world.registry.emplace(inEntity, std::forward(inArgs)...); - } - - template - C* Commands::FindComp(Entity inEntity) - { - return world.registry.try_get(inEntity); - } - - template - const C* Commands::FindComp(Entity inEntity) const - { - return world.registry.try_get(inEntity); - } - - template - C& Commands::GetComp(Entity inEntity) - { - auto* result = world.registry.try_get(inEntity); - Assert(result != nullptr); - return *result; - } - - template - const C& Commands::GetComp(Entity inEntity) const - { - auto* result = world.registry.try_get(inEntity); - Assert(result != nullptr); - return *result; - } - - template - auto Commands::View(Exclude) - { - return CompView, C...>(world.registry.view(entt::exclude_t {})); - } - - template - auto Commands::View(Exclude) const - { - return CompView, std::add_const_t...>(world.registry.view(entt::exclude_t {})); - } - - template - void World::AddSystem(Args&&... inSystemArgs) - { - SystemClass clazz = Internal::GetClassChecked(); - systems.emplace(clazz, System(std::forward(inSystemArgs)...)); - systemsInBarriers.emplace_back(clazz); - } -}; diff --git a/Engine/Source/Runtime/Src/Component/Light.cpp b/Engine/Source/Runtime/Src/Component/Light.cpp new file mode 100644 index 00000000..f3a17394 --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/Light.cpp @@ -0,0 +1,13 @@ +// +// Created by johnk on 2024/10/14. +// + +#include + +namespace Runtime { + DirectionalLight::DirectionalLight() = default; + + PointLight::PointLight() = default; + + SpotLight::SpotLight() = default; +} diff --git a/Engine/Source/Runtime/Src/Component/Transform.cpp b/Engine/Source/Runtime/Src/Component/Transform.cpp new file mode 100644 index 00000000..cc9ff5a4 --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/Transform.cpp @@ -0,0 +1,14 @@ +// +// Created by johnk on 2024/10/14. +// + +#include + +namespace Runtime { + Transform::Transform() = default; + + Transform::Transform(const Common::FTransform& inLocalToWorld) + : localToWorld(inLocalToWorld) + { + } +} diff --git a/Engine/Source/Runtime/Src/Component/View.cpp b/Engine/Source/Runtime/Src/Component/View.cpp new file mode 100644 index 00000000..bbb5510a --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/View.cpp @@ -0,0 +1,37 @@ +// +// Created by johnk on 2024/10/14. +// + +#include + +namespace Runtime { + Camera::Camera() + : projection(Common::FReversedZPerspectiveProjection()) + { + } + + Camera::Camera(const Common::FReversedZOrthoProjection& inProjection) + : projection(inProjection) + { + } + + Camera::Camera(const Common::FReversedZPerspectiveProjection& inProjection) + : projection(inProjection) + { + } + + SceneCapture::SceneCapture() + : projection(Common::FReversedZPerspectiveProjection()) + { + } + + SceneCapture::SceneCapture(const Common::FReversedZOrthoProjection& inProjection) + : projection(inProjection) + { + } + + SceneCapture::SceneCapture(const Common::FReversedZPerspectiveProjection& inProjection) + : projection(inProjection) + { + } +} diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp new file mode 100644 index 00000000..58ef5b39 --- /dev/null +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -0,0 +1,1042 @@ +// +// Created by johnk on 2024/10/31. +// + +#include + +#include + +namespace Runtime { + System::System(ECRegistry& inRegistry) + : registry(inRegistry) + { + } + + System::~System() = default; + + void System::Execute(float inDeltaTimeMs) {} +} + +namespace Runtime::Internal { + CompRtti::CompRtti(CompClass inClass) + : clazz(inClass) + , bound(false) + , offset(0) + { + } + + void CompRtti::Bind(size_t inOffset) + { + bound = true; + offset = inOffset; + } + + Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const + { + auto* compBegin = static_cast(inElem) + offset; + return clazz->InplaceNewDyn(compBegin, { inOther }); + } + + Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const + { + auto* compBegin = static_cast(inElem) + offset; + auto compRef = clazz->InplaceGetObject(compBegin); + compRef.MoveAssign(inOther); + return compRef; + } + + void CompRtti::Destruct(ElemPtr inElem) const + { + auto* compBegin = static_cast(inElem) + offset; + clazz->DestructDyn(clazz->InplaceGetObject(compBegin)); + } + + Mirror::Any CompRtti::Get(ElemPtr inElem) const + { + auto* compBegin = static_cast(inElem) + offset; + return clazz->InplaceGetObject(compBegin); + } + + CompClass CompRtti::Class() const + { + return clazz; + } + + size_t CompRtti::Offset() const + { + return offset; + } + + size_t CompRtti::Size() const + { + return clazz->SizeOf(); + } + + Archetype::Archetype(const std::vector& inRttiVec) + : id(0) + , size(0) + , elemSize(0) + , rttiVec(inRttiVec) + { + rttiMap.reserve(rttiVec.size()); + for (auto i = 0; i < rttiVec.size(); i++) { + auto& rtti = rttiVec[i]; + const auto clazz = rtti.Class(); + rttiMap.emplace(clazz, i); + + id += clazz->GetTypeInfo()->id; + rtti.Bind(elemSize); + elemSize += rtti.Size(); + } + } + + bool Archetype::Contains(CompClass inClazz) const + { + for (const auto& rtti : rttiVec) { + if (rtti.Class() == inClazz) { + return true; + } + } + return false; + } + + bool Archetype::ContainsAll(const std::vector& inClasses) const + { + for (const auto& rtti : rttiVec) { + if (!Contains(rtti.Class())) { + return false; + } + } + return true; + } + + bool Archetype::NotContainsAny(const std::vector& inCompClasses) const + { + for (const auto& rtti : rttiVec) { + if (Contains(rtti.Class())) { + return false; + } + } + return true; + } + + ElemPtr Archetype::EmplaceElem(Entity inEntity) + { + ElemPtr result = AllocateNewElemBack(); + auto backElem = size - 1; + entityMap.emplace(inEntity, backElem); + elemMap.emplace(backElem, inEntity); + return result; + } + + ElemPtr Archetype::EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec) + { + ElemPtr newElem = EmplaceElem(inEntity); + for (const auto& srcRtti : inSrcRttiVec) { + const auto* newRtti = FindCompRtti(srcRtti.Class()); + if (newRtti == nullptr) { + continue; + } + newRtti->MoveConstruct(newElem, srcRtti.Get(inSrcElem)); + } + return newElem; + } + + Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef) // NOLINT + { + ElemPtr elem = ElemAt(entityMap.at(inEntity)); + return GetCompRtti(inCompClass).MoveConstruct(elem, inCompRef); + } + + void Archetype::EraseElem(Entity inEntity) + { + const auto elemIndex = entityMap.at(inEntity); + ElemPtr elem = ElemAt(elemIndex); + const auto lastElemIndex = Size() - 1; + const auto entityToLastElem = elemMap.at(lastElemIndex); + ElemPtr lastElem = ElemAt(lastElemIndex); + for (const auto& rtti : rttiVec) { + rtti.MoveAssign(elem, rtti.Get(lastElem)); + } + entityMap.erase(inEntity); + entityMap.at(entityToLastElem) = elemIndex; + elemMap.erase(lastElemIndex); + elemMap.at(elemIndex) = entityToLastElem; + } + + ElemPtr Archetype::GetElem(Entity inEntity) const + { + return ElemAt(entityMap.at(inEntity)); + } + + Mirror::Any Archetype::GetComp(Entity inEntity, CompClass inCompClass) + { + ElemPtr element = GetElem(inEntity); + return GetCompRtti(inCompClass).Get(element); + } + + Mirror::Any Archetype::GetComp(Entity inEntity, CompClass inCompClass) const + { + ElemPtr element = GetElem(inEntity); + return GetCompRtti(inCompClass).Get(element).ConstRef(); + } + + size_t Archetype::Size() const + { + return size; + } + + const std::vector& Archetype::GetRttiVec() const + { + return rttiVec; + } + + ArchetypeId Archetype::Id() const + { + return id; + } + + std::vector Archetype::NewRttiVecByAdd(const CompRtti& inRtti) const + { + auto result = rttiVec; + result.emplace_back(inRtti); + return result; + } + + std::vector Archetype::NewRttiVecByRemove(const CompRtti& inRtti) const + { + auto result = rttiVec; + const auto iter = std::ranges::find_if(result, [&](const CompRtti& rtti) -> bool { return rtti.Class() == inRtti.Class(); }); + Assert(iter != result.end()); + result.erase(iter); + return result; + } + + const CompRtti* Archetype::FindCompRtti(CompClass clazz) const + { + const auto iter = rttiMap.find(clazz); + return iter != rttiMap.end() ? &rttiVec[iter->second] : nullptr; + } + + const CompRtti& Archetype::GetCompRtti(CompClass clazz) const + { + Assert(rttiMap.contains(clazz)); + return rttiVec[rttiMap.at(clazz)]; + } + + ElemPtr Archetype::ElemAt(std::vector& inMemory, size_t inIndex) const // NOLINT + { + return inMemory.data() + (inIndex * elemSize); + } + + ElemPtr Archetype::ElemAt(size_t inIndex) const + { + return ElemAt(const_cast&>(memory), inIndex); + } + + size_t Archetype::Capacity() const + { + return memory.size() / elemSize; + } + + void Archetype::Reserve(float inRatio) + { + Assert(inRatio > 1.0f); + const size_t newCapacity = static_cast(static_cast(Capacity()) * inRatio); + std::vector newMemory(newCapacity * elemSize); + + for (auto i = 0; i < size; i++) { + for (const auto& rtti : rttiVec) { + void* dstElem = ElemAt(newMemory, i); + void* srcElem = ElemAt(i); + rtti.MoveConstruct(dstElem, rtti.Get(srcElem)); + rtti.Destruct(srcElem); + } + } + memory = std::move(newMemory); + } + + void* Archetype::AllocateNewElemBack() + { + if (Size() == Capacity()) { + Reserve(); + } + size++; + return ElemAt(size - 1); + } + + EntityPool::EntityPool() + : counter() + { + } + + size_t EntityPool::Size() const + { + return allocated.size(); + } + + bool EntityPool::Valid(Entity inEntity) const + { + return allocated.contains(inEntity); + } + + Entity EntityPool::Allocate() + { + if (!free.empty()) { + const Entity result = *free.begin(); + free.erase(result); + return result; + } else { + const Entity result = counter++; + allocated.emplace(result); + return result; + } + } + + void EntityPool::Free(Entity inEntity) + { + Assert(Valid(inEntity)); + allocated.erase(inEntity); + free.emplace(inEntity); + } + + void EntityPool::Clear() + { + counter = 0; + free.clear(); + allocated.clear(); + } + + void EntityPool::Each(const EntityTraverseFunc& inFunc) const + { + for (const auto& entity : allocated) { + inFunc(entity); + } + } + + void EntityPool::SetArchetype(Entity inEntity, ArchetypeId inArchetypeId) + { + archetypeMap[inEntity] = inArchetypeId; + } + + ArchetypeId EntityPool::GetArchetype(Entity inEntity) const + { + return archetypeMap.at(inEntity); + } + + EntityPool::ConstIter EntityPool::Begin() const + { + return allocated.begin(); + } + + EntityPool::ConstIter EntityPool::End() const + { + return allocated.end(); + } + + SystemFactory::SystemFactory(SystemClass inClass) + : clazz(inClass) + { + BuildArgumentLists(); + } + + Common::UniqueRef SystemFactory::Build(ECRegistry& inRegistry) const + { + const Mirror::Any system = clazz->New(inRegistry); + const Mirror::Any systemRef = system.Deref(); + for (const auto& [name, argument] : arguments) { + clazz->GetMemberVariable(name).SetDyn(systemRef, argument.ConstRef()); + } + return system.As(); + } + + std::unordered_map SystemFactory::GetArguments() + { + std::unordered_map result; + for (auto& [name, argument] : arguments) { + result.emplace(name, argument.Ref()); + } + return result; + } + + const std::unordered_map& SystemFactory::GetArguments() const + { + return arguments; + } + + void SystemFactory::BuildArgumentLists() + { + const auto& memberVariables = clazz->GetMemberVariables(); + arguments.reserve(memberVariables.size()); + for (const auto& [id, member] : memberVariables) { + arguments.emplace(id.name, member.GetDyn(clazz->GetDefaultObject())); + } + } +} // namespace Runtime::Internal + +namespace Runtime { + ScopedUpdaterDyn::ScopedUpdaterDyn(ECRegistry& inRegistry, CompClass inClass, Entity inEntity, const Mirror::Any& inCompRef) + : registry(inRegistry) + , clazz(inClass) + , entity(inEntity) + , compRef(inCompRef) + { + } + + ScopedUpdaterDyn::~ScopedUpdaterDyn() + { + registry.NotifyUpdatedDyn(clazz, entity); + } + + GScopedUpdaterDyn::GScopedUpdaterDyn(ECRegistry& inRegistry, GCompClass inClass, const Mirror::Any& inGlobalCompRef) + : registry(inRegistry) + , clazz(inClass) + , globalCompRef(inGlobalCompRef) + { + } + + GScopedUpdaterDyn::~GScopedUpdaterDyn() + { + registry.GNotifyUpdatedDyn(clazz); + } + + RuntimeViewRule::RuntimeViewRule() = default; + + RuntimeViewRule& RuntimeViewRule::IncludeDyn(CompClass inClass) + { + includes.emplace(inClass); + return *this; + } + + RuntimeViewRule& RuntimeViewRule::ExcludeDyn(CompClass inClass) + { + excludes.emplace(inClass); + return *this; + } + + RuntimeView::RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) + { + Evaluate(inRegistry, inArgs); + } + + auto RuntimeView::Begin() + { + return resultEntities.begin(); + } + + auto RuntimeView::Begin() const + { + return resultEntities.begin(); + } + + auto RuntimeView::End() + { + return resultEntities.end(); + } + + auto RuntimeView::End() const + { + return resultEntities.end(); + } + + auto RuntimeView::begin() + { + return Begin(); + } + + auto RuntimeView::begin() const + { + return Begin(); + } + + auto RuntimeView::end() + { + return End(); + } + + auto RuntimeView::end() const + { + return End(); + } + + void RuntimeView::Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) + { + const std::vector includes(inArgs.includes.begin(), inArgs.includes.end()); + const std::vector excludes(inArgs.excludes.begin(), inArgs.excludes.end()); + + slotMap.reserve(includes.size()); + for (auto i = 0; i < includes.size(); i++) { + slotMap.emplace(includes[i], i); + } + + for (auto& [_, archetype] : inRegistry.archetypes) { + if (!archetype.ContainsAll(includes) || !archetype.NotContainsAny(excludes)) { + continue; + } + + resultEntities.reserve(result.size() + archetype.Size()); + result.reserve(result.size() + archetype.Size()); + for (const auto entity : archetype.All()) { + std::vector comps; + comps.reserve(includes.size()); + for (const auto clazz : includes) { + comps.emplace_back(archetype.GetComp(entity, clazz)); + } + + resultEntities.emplace_back(entity); + result.emplace_back(entity, std::move(comps)); + } + } + } + + Observer::Observer(ECRegistry& inRegistry) + : registry(inRegistry) + { + } + + Observer::~Observer() + { + Reset(); + } + + void Observer::Each(const EntityTraverseFunc& inFunc) const + { + for (const auto& entity : entities) { + inFunc(entity); + } + } + + void Observer::Clear() + { + entities.clear(); + } + + void Observer::Reset() + { + for (auto& [handle, deleter] : receiverHandles) { + deleter(); + } + receiverHandles.clear(); + } + + Observer::ConstIter Observer::Begin() const + { + return entities.begin(); + } + + Observer::ConstIter Observer::End() const + { + return entities.end(); + } + + Observer::ConstIter Observer::begin() const + { + return Begin(); + } + + Observer::ConstIter Observer::end() const + { + return End(); + } + + void Observer::RecordEntity(ECRegistry& inRegistry, Entity inEntity) + { + entities.emplace_back(inEntity); + } + + void Observer::OnEvent(Common::Event& inEvent) + { + const auto handle = inEvent.BindMember<&Observer::RecordEntity>(*this); + receiverHandles.emplace_back( + handle, + [&]() -> void { + inEvent.Unbind(handle); + }); + } + + ECRegistry::ECRegistry() = default; + + ECRegistry::~ECRegistry() + { + ResetTransients(); + } + + ECRegistry::ECRegistry(const ECRegistry& inOther) + : entities(inOther.entities) + , globalComps(inOther.globalComps) + , archetypes(inOther.archetypes) + { + } + + ECRegistry::ECRegistry(ECRegistry&& inOther) noexcept + : entities(std::move(inOther.entities)) + , globalComps(std::move(inOther.globalComps)) + , archetypes(std::move(inOther.archetypes)) + { + } + + ECRegistry& ECRegistry::operator=(const ECRegistry& inOther) + { + entities = inOther.entities; + globalComps = inOther.globalComps; + archetypes = inOther.archetypes; + return *this; + } + + ECRegistry& ECRegistry::operator=(ECRegistry&& inOther) noexcept + { + entities = std::move(inOther.entities); + globalComps = std::move(inOther.globalComps); + archetypes = std::move(inOther.archetypes); + return *this; + } + + void ECRegistry::ResetTransients() + { + compEvents.clear(); + globalCompEvents.clear(); + } + + Entity ECRegistry::Create() + { + return entities.Allocate(); + } + + void ECRegistry::Destroy(Entity inEntity) + { + entities.Free(inEntity); + } + + bool ECRegistry::Valid(Entity inEntity) const + { + return entities.Valid(inEntity); + } + + size_t ECRegistry::Size() const + { + return entities.Size(); + } + + void ECRegistry::Clear() + { + entities.Clear(); + globalComps.clear(); + archetypes.clear(); + ResetTransients(); + } + + void ECRegistry::Each(const EntityTraverseFunc& inFunc) const + { + return entities.Each(inFunc); + } + + ECRegistry::ConstIter ECRegistry::Begin() const + { + return entities.Begin(); + } + + ECRegistry::ConstIter ECRegistry::End() const + { + return entities.End(); + } + + ECRegistry::ConstIter ECRegistry::begin() const + { + return Begin(); + } + + ECRegistry::ConstIter ECRegistry::end() const + { + return End(); + } + + RuntimeView ECRegistry::RuntimeView(const RuntimeViewRule& inRule) + { + return Runtime::RuntimeView { *this, inRule }; + } + + void ECRegistry::NotifyUpdatedDyn(CompClass inClass, Entity inEntity) + { + const auto iter = compEvents.find(inClass); + if (iter == compEvents.end()) { + return; + } + iter->second.onUpdated.Broadcast(*this, inEntity); + } + + void ECRegistry::NotifyConstructedDyn(CompClass inClass, Entity inEntity) + { + const auto iter = compEvents.find(inClass); + if (iter == compEvents.end()) { + return; + } + iter->second.onConstructed.Broadcast(*this, inEntity); + } + + void ECRegistry::NotifyRemoveDyn(CompClass inClass, Entity inEntity) + { + const auto iter = compEvents.find(inClass); + if (iter == compEvents.end()) { + return; + } + iter->second.onRemove.Broadcast(*this, inEntity); + } + + Observer ECRegistry::Observer() + { + return Runtime::Observer { *this }; + } + + Mirror::Any ECRegistry::EmplaceDyn(CompClass inClass, Entity inEntity, const Mirror::ArgumentList& inArgs) + { + Assert(Valid(inEntity)); + const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); + Internal::Archetype& archetype = archetypes.at(archetypeId); + + const Internal::ArchetypeId newArchetypeId = archetypeId + inClass->GetTypeInfo()->id; + entities.SetArchetype(inEntity, newArchetypeId); + + Internal::Archetype* newArchetype; + if (archetypes.contains(newArchetypeId)) { + newArchetype = &archetypes.at(newArchetypeId); + newArchetype->EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); + } else { + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByAdd(Internal::CompRtti(inClass)))); + newArchetype = &archetypes.at(newArchetypeId); + newArchetype->EmplaceElem(inEntity); + } + + Mirror::Any tempObj = inClass->Construct(inArgs); + Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, inClass, tempObj.Ref()); + NotifyConstructedDyn(inClass, inEntity); + return compRef; + } + + void ECRegistry::RemoveDyn(CompClass inClass, Entity inEntity) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); + Internal::Archetype& archetype = archetypes.at(archetypeId); + + const Internal::ArchetypeId newArchetypeId = archetypeId - inClass->GetTypeInfo()->id; + entities.SetArchetype(inEntity, newArchetypeId); + + if (!archetypes.contains(newArchetypeId)) { + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByRemove(Internal::CompRtti(inClass)))); + } + NotifyRemoveDyn(inClass, inEntity); + Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); + newArchetype.EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); + } + + void ECRegistry::UpdateDyn(CompClass inClass, Entity inEntity, const DynUpdateFunc& inFunc) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + inFunc(GetDyn(inClass, inEntity)); + NotifyUpdatedDyn(inClass, inEntity); + } + + ScopedUpdaterDyn ECRegistry::UpdateDyn(CompClass inClass, Entity inEntity) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + return { *this, inClass, inEntity, GetDyn(inClass, inEntity) }; + } + + bool ECRegistry::HasDyn(CompClass inClass, Entity inEntity) const + { + Assert(Valid(inEntity)); + return archetypes + .at(entities.GetArchetype(inEntity)) + .Contains(inClass); + } + + Mirror::Any ECRegistry::FindDyn(CompClass inClass, Entity inEntity) + { + return HasDyn(inClass, inEntity) ? GetDyn(inClass, inEntity) : Mirror::Any(); + } + + Mirror::Any ECRegistry::FindDyn(CompClass inClass, Entity inEntity) const + { + return HasDyn(inClass, inEntity) ? GetDyn(inClass, inEntity) : Mirror::Any(); + } + + Mirror::Any ECRegistry::GetDyn(CompClass inClass, Entity inEntity) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + Mirror::Any compRef = archetypes + .at(entities.GetArchetype(inEntity)) + .GetComp(inEntity, inClass); + return compRef; + } + + Mirror::Any ECRegistry::GetDyn(CompClass inClass, Entity inEntity) const + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + Mirror::Any compRef = archetypes + .at(entities.GetArchetype(inEntity)) + .GetComp(inEntity, inClass); + return compRef.ConstRef(); + } + + ECRegistry::CompEvents& ECRegistry::EventsDyn(CompClass inClass) + { + return compEvents[inClass]; + } + + void ECRegistry::GNotifyUpdatedDyn(GCompClass inClass) + { + const auto iter = globalCompEvents.find(inClass); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onUpdated.Broadcast(*this); + } + + void ECRegistry::GNotifyConstructedDyn(GCompClass inClass) + { + const auto iter = globalCompEvents.find(inClass); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onConstructed.Broadcast(*this); + } + + void ECRegistry::GNotifyRemoveDyn(CompClass inClass) + { + const auto iter = globalCompEvents.find(inClass); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onRemove.Broadcast(*this); + } + + Mirror::Any ECRegistry::GEmplaceDyn(GCompClass inClass, const Mirror::ArgumentList& inArgs) + { + Assert(!GHasDyn(inClass)); + globalComps.emplace(inClass, inClass->ConstructDyn(inArgs)); + GNotifyConstructedDyn(inClass); + return GGetDyn(inClass); + } + + void ECRegistry::GRemoveDyn(GCompClass inClass) + { + Assert(GHasDyn(inClass)); + GNotifyRemoveDyn(inClass); + globalComps.erase(inClass); + } + + void ECRegistry::GUpdateDyn(GCompClass inClass, const DynUpdateFunc& inFunc) + { + Assert(GHasDyn(inClass)); + inFunc(GGetDyn(inClass)); + GNotifyUpdatedDyn(inClass); + } + + GScopedUpdaterDyn ECRegistry::GUpdateDyn(GCompClass inClass) + { + Assert(GHasDyn(inClass)); + return { *this, inClass, GGetDyn(inClass) }; + } + + bool ECRegistry::GHasDyn(GCompClass inClass) const + { + return globalComps.contains(inClass); + } + + Mirror::Any ECRegistry::GFindDyn(GCompClass inClass) + { + return GHasDyn(inClass) ? GGetDyn(inClass) : Mirror::Any(); + } + + Mirror::Any ECRegistry::GFindDyn(GCompClass inClass) const + { + return GHasDyn(inClass) ? GGetDyn(inClass) : Mirror::Any(); + } + + Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) + { + Assert(GHasDyn(inClass)); + return globalComps.at(inClass); + } + + Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) const + { + Assert(GHasDyn(inClass)); + return globalComps.at(inClass).ConstRef(); + } + + ECRegistry::GCompEvents& ECRegistry::GEventsDyn(GCompClass inClass) + { + return globalCompEvents[inClass]; + } + + SystemGroup::SystemGroup(std::string inName) + : name(std::move(inName)) + { + } + + Internal::SystemFactory& SystemGroup::EmplaceSystem(SystemClass inClass) + { + systems.emplace(inClass, Internal::SystemFactory(inClass)); + return systems.at(inClass); + } + + void SystemGroup::RemoveSystem(SystemClass inClass) + { + systems.erase(inClass); + } + + bool SystemGroup::HasSystem(SystemClass inClass) const + { + return systems.contains(inClass); + } + + Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) + { + return systems.at(inClass); + } + + const Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) const + { + return systems.at(inClass); + } + + auto SystemGroup::GetSystems() + { + return systems | std::views::values; + } + + auto SystemGroup::GetSystems() const + { + return systems | std::views::values; + } + + const std::string& SystemGroup::GetName() const + { + return name; + } + + SystemGraph::SystemGraph() = default; + + SystemGroup& SystemGraph::AddGroup(const std::string& inName) + { + return systemGroups.emplace_back(inName); + } + + void SystemGraph::RemoveGroup(const std::string& inName) + { + const auto iter = std::ranges::find_if(systemGroups, [&](const SystemGroup& group) -> bool { + return group.GetName() == inName; + }); + Assert(iter != systemGroups.end()); + systemGroups.erase(iter); + } + + bool SystemGraph::HasGroup(const std::string& inName) const + { + for (const auto& group : systemGroups) { + if (group.GetName() == inName) { + return true; + } + } + return false; + } + + SystemGroup& SystemGraph::GetGroup(const std::string& inName) + { + for (auto& group : systemGroups) { + if (group.GetName() == inName) { + return group; + } + } + Assert(false); + return systemGroups.back(); + } + + const SystemGroup& SystemGraph::GetGroup(const std::string& inName) const + { + for (const auto& group : systemGroups) { + if (group.GetName() == inName) { + return group; + } + } + Assert(false); + return systemGroups.back(); + } + + const std::vector& SystemGraph::GetGroups() const + { + return systemGroups; + } + + SystemPipeline::SystemPipeline(const SystemGraph& inGraph) + { + const auto& systemGroups = inGraph.GetGroups(); + systemGraph.reserve(systemGroups.size()); + + for (const auto& group : systemGroups) { + auto& contexts = systemGraph.emplace_back(); + const auto& factories = group.GetSystems(); + contexts.reserve(factories.size()); + + for (const auto& factory : group.GetSystems()) { + contexts.emplace_back(factory, nullptr); + } + } + } + + void SystemPipeline::ParallelPerformAction(const ActionFunc& inActionFunc) + { + tf::Taskflow taskFlow; + auto lastBarrier = taskFlow.emplace([]() -> void {}); + + for (auto& contexts : systemGraph) { + std::vector tasks; + tasks.reserve(contexts.size()); + + for (auto& context : contexts) { + tasks.emplace_back(taskFlow.emplace([&]() -> void { + inActionFunc(context); + })); + tasks.back().succeed(lastBarrier); + } + + auto barrier = taskFlow.emplace([]() -> void {}); + for (const auto& task : tasks) { + barrier.succeed(task); + } + lastBarrier = barrier; + } + + tf::Executor executor; + executor + .run(taskFlow) + .wait(); + } + + SystemGraphExecutor::SystemGraphExecutor(ECRegistry& inEcRegistry, const SystemGraph& inSystemGraph) + : ecRegistry(inEcRegistry) + , systemGraph(inSystemGraph) + , pipeline(inSystemGraph) + { + pipeline.ParallelPerformAction([&](SystemPipeline::SystemContext& context) -> void { + context.instance = context.factory.Build(inEcRegistry); + }); + } + + SystemGraphExecutor::~SystemGraphExecutor() + { + pipeline.ParallelPerformAction([](SystemPipeline::SystemContext& context) -> void { + context.instance = nullptr; + }); + } + + void SystemGraphExecutor::Tick(float inDeltaTimeMs) + { + pipeline.ParallelPerformAction([&](const SystemPipeline::SystemContext& context) -> void { + context.instance->Execute(inDeltaTimeMs); + }); + } +} // namespace Runtime diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index 32f4c5ad..c0a077ee 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -3,9 +3,10 @@ // #include -#include #include +#include #include +#include namespace Runtime { Engine::Engine(const EngineInitParams& inParams) @@ -13,9 +14,20 @@ namespace Runtime { if (!inParams.projectFile.empty()) { Core::Paths::SetCurrentProjectFile(inParams.projectFile); } + + renderModule = ::Core::ModuleManager::Get().FindOrLoadTyped("Render"); + Assert(renderModule != nullptr); + + Render::RenderModuleInitParams initParams; + initParams.rhiType = RHI::RHIAbbrStringToRHIType(inParams.rhiType); + renderModule->Initialize(initParams); } - Engine::~Engine() = default; + Engine::~Engine() + { + renderModule->DeInitialize(); + ::Core::ModuleManager::Get().Unload("Render"); + } void Engine::MountWorld(World* inWorld) { @@ -27,6 +39,26 @@ namespace Runtime { worlds.erase(inWorld); } + Render::RenderModule& Engine::GetRenderModule() const + { + return *renderModule; + } + + void Engine::Tick(float inTimeMs) const + { + for (auto* world : worlds) { + if (!world->Playing()) { + continue; + } + world->Tick(inTimeMs); + } + } + + Common::UniqueRef Engine::CreateWorld(const std::string& inName) const // NOLINT + { + return new World(inName); + } + Engine* EngineHolder::engine = nullptr; MinEngine::MinEngine(const EngineInitParams& inParams) diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 07ba4fe7..3c4b0af2 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -1,139 +1,80 @@ // -// Created by johnk on 2024/8/2. +// Created by johnk on 2024/10/31. // #include #include namespace Runtime { - const Mirror::Class* Internal::GetClassChecked(const std::string& inName) - { - return &Mirror::Class::Get(inName); - } - - Component::Component() = default; - - State::State() = default; - - System::System() = default; - - System::~System() = default; - - void System::Setup(Commands& commands) const {} - - void System::Tick(Commands& commands, float inTimeMs) const {} - - Commands::Commands(World& inWorld) - : world(inWorld) + World::World(const std::string& inName) + : name(inName) { + EngineHolder::Get().MountWorld(this); } - Commands::~Commands() = default; - - Entity Commands::CreateEntity() // NOLINT + World::~World() { - return world.registry.create(); + EngineHolder::Get().UnmountWorld(this); } - void Commands::DestroyEntity(Entity inEntity) // NOLINT + void World::SetSystemGraph(const SystemGraph& inSystemGraph) { - world.registry.destroy(inEntity); + systemGraph = inSystemGraph; } - World::World(std::string inName) - : setuped(false) - , playing(false) - , name(std::move(inName)) + void World::Reset() { - EngineHolder::Get().MountWorld(this); + playStatus = PlayStatus::stopped; } - World::~World() + PlayStatus World::PlayStatus() const { - EngineHolder::Get().UnmountWorld(this); + return playStatus; } - void World::AddBarrier() + bool World::Stopped() const { - systemsGraph.emplace_back(systemsInBarriers); - systemsInBarriers.clear(); + return playStatus == PlayStatus::stopped; } - void World::Play() + bool World::Playing() const { - Assert(!setuped && systemsInBarriers.empty()); - setuped = true; - playing = true; - ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(*this); - inSystem.Setup(commands); - }); + return playStatus == PlayStatus::playing; } - void World::Stop() + bool World::Paused() const { - Assert(setuped); - setuped = false; - playing = false; + return playStatus == PlayStatus::paused; } - void World::Pause() + void World::Play() { - Assert(setuped && playing); - playing = false; + Assert(Stopped() && !executor.has_value()); + playStatus = PlayStatus::playing; + executor.emplace(ecRegistry, systemGraph); } void World::Resume() { - Assert(setuped && !playing); - playing = true; + Assert(Paused()); + playStatus = PlayStatus::playing; } - void World::Tick(float inFrameTimeMs) - { - Assert(setuped && playing); - ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(*this); - inSystem.Tick(commands, inFrameTimeMs); - }); - } - - bool World::Started() const + void World::Pause() { - return setuped; + Assert(Playing()); + playStatus = PlayStatus::paused; } - bool World::Playing() const + void World::Stop() { - return playing; + Assert((Playing() || Paused()) && executor.has_value()); + playStatus = PlayStatus::stopped; + executor.reset(); } - void World::ExecuteSystemGraph(const SystemOp& inOp) + void World::Tick(float inTimeMs) { - tf::Taskflow taskFlow; - auto newBarrierTask = [&]() -> decltype(auto) { - return taskFlow.emplace([]() -> void {}); - }; - - tf::Task barrierTask = newBarrierTask(); - for (const auto& systemSet : systemsGraph) { - std::vector tasks; - for (const auto& systemClass : systemSet) { - auto& addedTask = tasks.emplace_back(taskFlow.emplace([&]() -> void { - inOp(systems.at(systemClass).As()); - })); - addedTask.succeed(barrierTask); - } - - barrierTask = newBarrierTask(); - for (const auto& task : tasks) { - barrierTask.succeed(task); - } - } - - tf::Executor executor; - executor - .run(taskFlow) - .wait(); + executor->Tick(inTimeMs); } -} +} // namespace Runtime diff --git a/Engine/Source/Runtime/Test/ECSTest.cpp b/Engine/Source/Runtime/Test/ECSTest.cpp new file mode 100644 index 00000000..44eaeb91 --- /dev/null +++ b/Engine/Source/Runtime/Test/ECSTest.cpp @@ -0,0 +1,47 @@ +// +// Created by johnk on 2024/12/9. +// + +#include + +TEST(ECSTest, EntityTest) +{ + ECRegistry registry; + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + ASSERT_EQ(registry.Size(), 2); + ASSERT_TRUE(registry.Valid(entity0)); + ASSERT_TRUE(registry.Valid(entity1)); + ASSERT_FALSE(registry.Valid(99)); + + std::unordered_set cur = { entity0, entity1 }; + for (const auto e : registry) { + ASSERT_TRUE(cur.contains(e)); + } + + const auto entity2 = registry.Create(); + const auto entity3 = registry.Create(); + registry.Destroy(entity0); + const auto entity4 = registry.Create(); + cur = { entity1, entity2, entity3, entity4 }; + + registry.Each([&](const auto e) -> void { + ASSERT_TRUE(cur.contains(e)); + }); +} + +TEST(ECSTest, ComponentStaticTest) +{ + // ECRegistry registry; + // const auto entity0 = registry.Create(); + // const auto entity1 = registry.Create(); + // + // registry.Emplace(entity0, 1); + // registry.Emplace(entity1, 2); + // ASSERT_TRUE(registry.Has(entity0)); + // ASSERT_TRUE(registry.Has(entity1)); + + // TODO +} + +// TODO diff --git a/Engine/Source/Runtime/Test/ECSTest.h b/Engine/Source/Runtime/Test/ECSTest.h new file mode 100644 index 00000000..3152a077 --- /dev/null +++ b/Engine/Source/Runtime/Test/ECSTest.h @@ -0,0 +1,15 @@ +// +// Created by johnk on 2024/12/9. +// + +#pragma once + +#include +#include +using namespace Runtime; + +struct EClass() CompA { + EClassBody(CompA) + + int value; +}; diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp deleted file mode 100644 index 06dc173a..00000000 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// Created by johnk on 2024/8/20. -// - -#include -#include -#include - -struct WorldTest : testing::Test { - void SetUp() override - { - EngineHolder::Load("RuntimeTest", {}); - } -}; - -GlobalCounter::GlobalCounter() - : tickTime(0) - , value(0) -{ -} - -ParralCountSystemA::ParralCountSystemA() = default; - -ParralCountSystemA::~ParralCountSystemA() = default; - -void ParralCountSystemA::Tick(Commands& commands, float inTimeMs) const -{ - auto& globalCounter = commands.GetState(); - globalCounter.tickTime += 1; - globalCounter.value += 2; -} - -ParralCountSystemB::ParralCountSystemB() = default; - -ParralCountSystemB::~ParralCountSystemB() = default; - -void ParralCountSystemB::Tick(Commands& commands, float inTimeMs) const -{ - commands.GetState().value += 3; -} - -GlobalCounterVerifySystem::GlobalCounterVerifySystem() = default; - -GlobalCounterVerifySystem::~GlobalCounterVerifySystem() = default; - -void GlobalCounterVerifySystem::Setup(Commands& commands) const -{ - commands.EmplaceState(); -} - -void GlobalCounterVerifySystem::Tick(Commands& commands, float inTimeMs) const -{ - const auto& globalCounter = commands.GetState(); - ASSERT_EQ(globalCounter.value, globalCounter.tickTime * 5); -} - -TEST_F(WorldTest, ECSBasic) -{ - World world; - world.AddSystem(); - world.AddSystem(); - world.AddBarrier(); - world.AddSystem(); - world.AddBarrier(); - - world.Play(); - world.Tick(3.0f); - world.Tick(3.0f); - world.Stop(); -} diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h deleted file mode 100644 index db03802e..00000000 --- a/Engine/Source/Runtime/Test/WorldTest.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Created by johnk on 2024/8/20. -// - -#pragma once - -#include -#include - -using namespace Runtime; - -class EClass() GlobalCounter final : public State { - EClassBody(GlobalCounter) - - GlobalCounter(); - - EProperty() uint32_t tickTime; - EProperty() uint32_t value; -}; - -class EClass() ParralCountSystemA final : public System { - EPolyClassBody(ParralCountSystemA) - - ParralCountSystemA(); - ~ParralCountSystemA() override; - - EFunc() void Tick(Commands& commands, float inTimeMs) const override; -}; - -class EClass() ParralCountSystemB final : public System { - EPolyClassBody(ParralCountSystemB) - - ParralCountSystemB(); - ~ParralCountSystemB() override; - - EFunc() void Tick(Commands& commands, float inTimeMs) const override; -}; - -class EClass() GlobalCounterVerifySystem final : public System { - EPolyClassBody(GlobalCounterVerifySystem) - - GlobalCounterVerifySystem(); - ~GlobalCounterVerifySystem() override; - - EFunc() void Setup(Commands& commands) const override; - EFunc() void Tick(Commands& commands, float inTimeMs) const override; -}; diff --git a/README.md b/README.md index e6c8c741..3ebde826 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ We use cmake as build tool, the following table contains supported platform, too macOS - x64 / arm64 + arm64 Apple Clang Unix Makefiles @@ -77,6 +77,25 @@ The parameters' meaning: After build the project, you can get all dist binaries in `/dist`. +## macOS Notice +If you have not installed xcode command line tools, you need install it: + +```shell +xcode-select --install +``` + +If xcode app or xcode command line tools installed on you system, you need check xcode path set to command line tools path, continue with this command: + +```shell +xcode-select -p +``` + +if the command print is not `/Library/Developer/CommandLineTools`, use this command to reset it: + +```shell +sudo xcode-select -s /Library/Developer/CommandLineTools +``` + # Third Party Project Usage Thanks all those following projects: diff --git a/Sample/CMakeLists.txt b/Sample/CMakeLists.txt index a3009873..0d2461da 100644 --- a/Sample/CMakeLists.txt +++ b/Sample/CMakeLists.txt @@ -48,7 +48,7 @@ Addlibrary( NAME Sample-Base SRC ${SOURCES} PUBLIC_INC Base - LIB RHI glfw clipp ${PLATFORM_EXT_LIBS} Render stb assimp-lib Rendering.Static + LIB RHI glfw clipp ${PLATFORM_EXT_LIBS} Render.Static stb assimp-lib ) file(GLOB SOURCES RHI-Triangle/*.cpp) diff --git a/Sample/Rendering-Triangle/Triangle.cpp b/Sample/Rendering-Triangle/Triangle.cpp index 0ed6468a..7ecc2b1f 100644 --- a/Sample/Rendering-Triangle/Triangle.cpp +++ b/Sample/Rendering-Triangle/Triangle.cpp @@ -5,12 +5,11 @@ #include #include #include -#include -#include +#include +#include using namespace Common; using namespace Render; -using namespace Rendering; using namespace RHI; struct Vertex { diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 9183d343..db856480 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -1,12 +1,3 @@ -# EnTT -Add3rdHeaderOnlyPackage( - NAME EnTT - PLATFORM All - VERSION 3.8.1 - HASH abe24e5da599ef9f172c25f68f3b777dd404896b06e500742ecc88bbfef2216c - INCLUDE $/single_include -) - # DirectX 12 Headers Add3rdHeaderOnlyPackage( NAME DirectXHeaders @@ -35,6 +26,7 @@ Add3rdBinaryPackage( Darwin vulkan.1 ) if (NOT ${CI}) + #see https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") execute_process(COMMAND reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers" OUTPUT_VARIABLE LAYERS) string(REGEX MATCH "VkLayer_khronos_validation\.json" MATCH_RESULT ${LAYERS}) @@ -48,8 +40,51 @@ if (NOT ${CI}) string(REPLACE "/" "\\" VALIDATION_LAYER_JSON ${VALIDATION_LAYER_JSON}) execute_process(COMMAND PowerShell -Command "Start-Process reg -ArgumentList 'add HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers /v ${VALIDATION_LAYER_JSON} /t REG_DWORD /d 0' -Verb RunAs") endif () - else () - # TODO check macOS + else (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + # check drivers + set(PLATFORM_VULKAN_SDK_DIR ${CMAKE_SOURCE_DIR}/ThirdParty/Lib/VulkanSDK-Darwin-${VULKAN_SDK_VERSION}/macOS) + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + string(REGEX MATCH "ERROR_INCOMPATIBLE_DRIVER" MATCH_RESULT ${VULKAN_INFO}) + list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) + if (${MATCH_RESULT_LENGTH} GREATER 0) + message("there is no drivers found for vulkan, copy and rewrite driver files to ~/.config/vulkan/icd.d") + get_filename_component(DRIVERS_DIR_ABSOLUTE ~/.config/vulkan/icd.d ABSOLUTE) + if (NOT EXISTS ${DRIVERS_DIR_ABSOLUTE}) + file(MAKE_DIRECTORY ${DRIVERS_DIR_ABSOLUTE}) + endif () + + file(GLOB DRIVER_FILES ${PLATFORM_VULKAN_SDK_DIR}/share/vulkan/icd.d/*.json) + foreach (DRIVER_FILE ${DRIVER_FILES}) + file(READ ${DRIVER_FILE} FILE_CONTENT) + string(REPLACE "../../../lib" "${PLATFORM_VULKAN_SDK_DIR}/lib" FILE_CONTENT ${FILE_CONTENT}) + get_filename_component(FILE_NAME ${DRIVER_FILE} NAME) + file(WRITE ${DRIVERS_DIR_ABSOLUTE}/${FILE_NAME} ${FILE_CONTENT}) + endforeach () + else () + message("found vulkan drivers installed in system, will use it") + endif () + + # check layers + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + string(REGEX MATCH "Layers:\n=======" MATCH_RESULT ${VULKAN_INFO}) + list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) + if (${MATCH_RESULT_LENGTH} GREATER 0) + message("there is no layers found for vulkan, copy and rewrite layer files to ~/.config/vulkan/explicit_layer.d") + get_filename_component(LAYERS_DIR_ABSOLUTE ~/.config/vulkan/explicit_layer.d ABSOLUTE) + if (NOT EXISTS ${LAYERS_DIR_ABSOLUTE}) + file(MAKE_DIRECTORY ${LAYERS_DIR_ABSOLUTE}) + endif () + + file(GLOB LAYER_FILES ${PLATFORM_VULKAN_SDK_DIR}/share/vulkan/explicit_layer.d/*.json) + foreach (LAYER_FILE ${LAYER_FILES}) + file(READ ${LAYER_FILE} FILE_CONTENT) + string(REPLACE "../../../lib" "${PLATFORM_VULKAN_SDK_DIR}/lib" FILE_CONTENT ${FILE_CONTENT}) + get_filename_component(FILE_NAME ${LAYER_FILE} NAME) + file(WRITE ${LAYERS_DIR_ABSOLUTE}/${FILE_NAME} ${FILE_CONTENT}) + endforeach () + else () + message("found vulkan layers installed in system, will use it") + endif () endif () endif () @@ -108,17 +143,14 @@ Add3rdBinaryPackage( ARCH VERSION Windows-AMD64 17.0.4 - Darwin-x86_64 15.0.7 Darwin-arm64 15.0.7 HASH Windows-AMD64 3443a2259d092797521bde0c4b6e402ddeca4beb0abd87274ece91ac44b178ce - Darwin-x86_64 75b45dda76d52fcf7f3253aedea1f7327eb2aca37871b287d89234b55bde5504 Darwin-arm64 99a4884945674163374d99c2220cadbfe20a947b1217193140c6b6638a3b0627 INCLUDE $/include LINK $/lib LIB Windows-AMD64 libclang - Darwin-x86_64 clang Darwin-arm64 clang RUNTIME_DEP Windows $/bin/libclang.dll @@ -165,15 +197,6 @@ Add3rdHeaderOnlyPackage( INCLUDE $ ) -# fmt-lib -Add3rdHeaderOnlyPackage( - NAME fmt-lib - PLATFORM All - VERSION 9.1.0 - HASH 09fb58ad10d1071ca8dbe0dc02b64fac6b2f4d4ba626b6d21a67d5b60ffe9f95 - INCLUDE $/include -) - # spirv-cross Add3rdCMakeProject( NAME spirv-cross @@ -220,7 +243,7 @@ Find3rdPackage( VERSION 6.5.2 HASH Windows e2a573a53b6de88c0ce768868bd5a8258d432ad71c45a407afa55243b051668f - Darwin 4379592e8b3af8eb32f5d030608651da8dc59c30b9bfa7837b7ed17949ff3365 + Darwin 2fadcb1f07e5f11d4345e7d5631f35f8f4a8033c35901fb20a22c2feb7486e57 PREFIX Windows $/6.5.2/msvc2019_64 Darwin $/6.5.2/macos @@ -233,6 +256,7 @@ Find3rdPackage( $/6.5.2/msvc2019_64/bin/Qt6Gui$,d,>.dll $/6.5.2/msvc2019_64/bin/Qt6Widgets$,d,>.dll ) +set(Qt6Core_VERSION_MAJOR 6 CACHE STRING "" FORCE) # rapidjson Add3rdHeaderOnlyPackage( diff --git a/Tool/MirrorTool/Include/MirrorTool/Parser.h b/Tool/MirrorTool/Include/MirrorTool/Parser.h index e81fd34e..ca997078 100644 --- a/Tool/MirrorTool/Include/MirrorTool/Parser.h +++ b/Tool/MirrorTool/Include/MirrorTool/Parser.h @@ -52,9 +52,14 @@ namespace MirrorTool { FieldAccess fieldAccess; }; + struct ClassDestructorInfo : Node { + FieldAccess fieldAccess; + }; + struct ClassInfo : Node { FieldAccess lastFieldAccess; std::string baseClassName; + std::optional destructor; std::vector classes; std::vector constructors; std::vector staticVariables; diff --git a/Tool/MirrorTool/Src/Generator.cpp b/Tool/MirrorTool/Src/Generator.cpp index 96b31be0..c5b245b3 100644 --- a/Tool/MirrorTool/Src/Generator.cpp +++ b/Tool/MirrorTool/Src/Generator.cpp @@ -16,7 +16,7 @@ namespace MirrorTool { { std::string outerName = node.outerName; const std::string name = node.name; - return outerName.empty() ? name : fmt::format("{}::{}", outerName, name); + return outerName.empty() ? name : std::format("{}::{}", outerName, name); } template @@ -24,7 +24,7 @@ namespace MirrorTool { { std::stringstream stream; for (const auto& [key, value] : node.metaDatas) { - stream << Common::newline << Common::tab << fmt::format(R"(.MetaData("{}", "{}"))", key, value); + stream << Common::newline << Common::tab << std::format(R"(.MetaData("{}", "{}"))", key, value); } return stream.str(); } @@ -56,13 +56,13 @@ namespace MirrorTool { std::stringstream stream; stream << Common::newline; - stream << Common::tab<1> << fmt::format("Mirror::Registry::Get()") << Common::newline; - stream << Common::tab<2> << fmt::format(R"(.Enum<{}>("{}"))", fullName, fullName); + stream << Common::tab<1> << std::format("Mirror::Registry::Get()") << Common::newline; + stream << Common::tab<2> << std::format(R"(.Enum<{}>("{}"))", fullName, fullName); stream << GetMetaDataCode<3>(enumInfo); for (const auto& element : enumInfo.elements) { const auto elementFullName = GetFullName(element); stream << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Value<{}>("{}"))", elementFullName, element.name); + stream << Common::tab<3> << std::format(R"(.Value<{}>("{}"))", elementFullName, element.name); stream << GetMetaDataCode<4>(element); } stream << ";" << Common::newline; @@ -85,7 +85,7 @@ namespace MirrorTool { { std::stringstream stream; stream << Common::newline; - stream << fmt::format("int _mirrorEnumRegistry_{} = []() -> int", uniqueId) << Common::newline; + stream << std::format("int _mirrorEnumRegistry_{} = []() -> int", uniqueId) << Common::newline; stream << "{"; stream << GetNamespaceEnumsCode(metaInfo.global); for (const auto& ns : metaInfo.namespaces) { @@ -97,44 +97,70 @@ namespace MirrorTool { return stream.str(); } + static std::string GetFieldAccessStr(FieldAccess access) + { + static const std::unordered_map map = { + { FieldAccess::pri, "Mirror::FieldAccess::faPrivate" }, + { FieldAccess::pro, "Mirror::FieldAccess::faProtected" }, + { FieldAccess::pub, "Mirror::FieldAccess::faPublic" }, + }; + return map.at(access); + } + static std::string GetClassCode(const ClassInfo& clazz) // NOLINT { const std::string fullName = GetFullName(clazz); + auto defaultCtorFieldAccess = FieldAccess::pub; + for (const auto& constructor : clazz.constructors) { + if (constructor.parameters.empty()) { + defaultCtorFieldAccess = constructor.fieldAccess; + } + } + auto detorFieldAccess = clazz.destructor.has_value() ? clazz.destructor->fieldAccess : FieldAccess::pub; + + std::string defaultCtorAndDetorFieldAccessParams = defaultCtorFieldAccess != FieldAccess::pub || detorFieldAccess != FieldAccess::pub + ? std::format(", {}, {}", GetFieldAccessStr(defaultCtorFieldAccess), GetFieldAccessStr(detorFieldAccess)) + : ""; std::stringstream stream; stream << Common::newline; - stream << fmt::format("int {}::_mirrorRegistry = []() -> int ", fullName) << Common::newline; + stream << std::format("int {}::_mirrorRegistry = []() -> int ", fullName) << Common::newline; stream << "{" << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()"; if (clazz.baseClassName.empty()) { - stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}>("{}"))", fullName, fullName); + stream << Common::newline << Common::tab<2> << std::format(R"(.Class<{}, void{}>("{}"))", fullName, defaultCtorAndDetorFieldAccessParams, fullName); } else { - stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}, {}>("{}"))", fullName, clazz.baseClassName, fullName); + stream << Common::newline << Common::tab<2> << std::format(R"(.Class<{}, {}{}>("{}"))", fullName, clazz.baseClassName, defaultCtorAndDetorFieldAccessParams, fullName); } stream << GetMetaDataCode<3>(clazz); for (const auto& constructor : clazz.constructors) { - stream << Common::newline << Common::tab<3> << fmt::format(R"(.Constructor<{}>("{}"))", constructor.name, constructor.name); + const std::string fieldAccessStr = constructor.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(constructor.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.Constructor<{}{}>("{}"))", constructor.name, fieldAccessStr, constructor.name); stream << GetMetaDataCode<4>(constructor); } for (const auto& staticVariable : clazz.staticVariables) { const std::string variableName = GetFullName(staticVariable); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticVariable<&{}>("{}"))", variableName, staticVariable.name); + const std::string fieldAccessStr = staticVariable.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(staticVariable.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.StaticVariable<&{}{}>("{}"))", variableName, fieldAccessStr, staticVariable.name); stream << GetMetaDataCode<4>(staticVariable); } for (const auto& staticFunction : clazz.staticFunctions) { const std::string functionName = GetFullName(staticFunction); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticFunction<&{}>("{}"))", functionName, staticFunction.name); + const std::string fieldAccessStr = staticFunction.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(staticFunction.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.StaticFunction<&{}{}>("{}"))", functionName, fieldAccessStr, staticFunction.name); stream << GetMetaDataCode<4>(staticFunction); } // TODO overload support for (const auto& variable : clazz.variables) { const std::string variableName = GetFullName(variable); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberVariable<&{}>("{}"))", variableName, variable.name); + const std::string fieldAccessStr = variable.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(variable.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.MemberVariable<&{}{}>("{}"))", variableName, fieldAccessStr, variable.name); stream << GetMetaDataCode<4>(variable); } for (const auto& function : clazz.functions) { const std::string functionName = GetFullName(function); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberFunction<&{}>("{}"))", functionName, function.name); + const std::string fieldAccessStr = function.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(function.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.MemberFunction<&{}{}>("{}"))", functionName, fieldAccessStr, function.name); stream << GetMetaDataCode<4>(function); } // TODO overload support @@ -142,14 +168,14 @@ namespace MirrorTool { stream << Common::tab<1> << "return 0;" << Common::newline; stream << "}();" << Common::newline; stream << Common::newline; - stream << fmt::format("const Mirror::Class& {}::GetStaticClass()", fullName) << Common::newline; + stream << std::format("const Mirror::Class& {}::GetStaticClass()", fullName) << Common::newline; stream << "{" << Common::newline; - stream << Common::tab<1> << fmt::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; + stream << Common::tab<1> << std::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; stream << Common::tab<1> << "return clazz;" << Common::newline; stream << "}" << Common::newline; - stream << fmt::format("const Mirror::Class& {}::GetClass()", fullName) << Common::newline; + stream << std::format("const Mirror::Class& {}::GetClass()", fullName) << Common::newline; stream << "{" << Common::newline; - stream << Common::tab<1> << fmt::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; + stream << Common::tab<1> << std::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; stream << Common::tab<1> << "return clazz;" << Common::newline; stream << "}" << Common::newline; stream << Common::newline; @@ -191,7 +217,7 @@ namespace MirrorTool { stream << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()" << Common::newline; stream << Common::tab<2> << ".Global()" << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Variable<&{}>("{}"))", fullName, fullName); + stream << Common::tab<3> << std::format(R"(.Variable<&{}>("{}"))", fullName, fullName); stream << GetMetaDataCode<4>(var); stream << ";" << Common::newline; } @@ -201,7 +227,7 @@ namespace MirrorTool { stream << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()" << Common::newline; stream << Common::tab<2> << ".Global()" << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Function<&{}>("{}"))", fullName, fullName); + stream << Common::tab<3> << std::format(R"(.Function<&{}>("{}"))", fullName, fullName); stream << GetMetaDataCode<4>(func); stream << ";" << Common::newline; } @@ -217,7 +243,7 @@ namespace MirrorTool { { std::stringstream stream; stream << Common::newline; - stream << fmt::format("int _globalRegistry_{} = []() -> int", uniqueId) << Common::newline; + stream << std::format("int _globalRegistry_{} = []() -> int", uniqueId) << Common::newline; stream << "{"; stream << GetNamespaceGlobalCode(metaInfo.global); for (const auto& ns : metaInfo.namespaces) { @@ -271,7 +297,7 @@ namespace MirrorTool { } outFile << GetHeaderNote() << Common::newline; - outFile << fmt::format("#include <{}>", bestMatchHeaderPath) << Common::newline; + outFile << std::format("#include <{}>", bestMatchHeaderPath) << Common::newline; outFile << "#include " << Common::newline; outFile << GetGlobalCode(metaInfo, uniqueId); outFile << GetEnumsCode(metaInfo, uniqueId); diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index 121fac48..942af005 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -3,6 +3,7 @@ // #include +#include #include #include @@ -86,15 +87,20 @@ namespace MirrorTool { return Common::StringUtils::Replace(result, "struct", ""); } + static std::string RemoveStrSpace(const std::string& value) + { + return Common::StringUtils::Replace(value, " ", ""); + } + static void ParseMetaDatas(Node& node, const std::string& metaDataStr) { - for (const auto metaDatas = Common::StringUtils::Split(metaDataStr, ";"); + for (const auto metaDatas = Common::StringUtils::Split(metaDataStr, ","); const auto& metaData : metaDatas) { if (auto keyValue = Common::StringUtils::Split(metaData, "="); keyValue.size() == 1) { - node.metaDatas.emplace(std::make_pair(keyValue[0], "true")); + node.metaDatas.emplace(std::make_pair(RemoveStrSpace(keyValue[0]), "true")); } else if (keyValue.size() == 2) { - node.metaDatas.emplace(std::make_pair(keyValue[0], keyValue[1])); + node.metaDatas.emplace(std::make_pair(RemoveStrSpace(keyValue[0]), RemoveStrSpace(keyValue[1]))); } } } @@ -235,6 +241,11 @@ namespace MirrorTool { context.constructors.emplace_back(std::move(constructorInfo)); VisitChildren(ClassConstructorVisitor, ClassConstructorInfo, cursor, context.constructors.back()); UpdateConstructorName(context.constructors.back()); + } else if (kind == CXCursor_Destructor) { + ClassDestructorInfo destructorInfo; + destructorInfo.outerName = GetOuterName(context.outerName, context.name); + destructorInfo.fieldAccess = context.lastFieldAccess; + context.destructor = std::move(destructorInfo); } else if (kind == CXCursor_StructDecl || kind == CXCursor_ClassDecl) { ClassInfo classInfo; classInfo.outerName = GetOuterName(context.outerName, context.name); @@ -396,19 +407,23 @@ namespace MirrorTool { "-std=c++20", #if BUILD_CONFIG_DEBUG "-DBUILD_CONFIG_DEBUG=1", +#else + "-DBUILD_CONFIG_DEBUG=0", #endif #if BUILD_EDITOR "-DBUILD_EDITOR=1", +#else + "-DBUILD_EDITOR=0", #endif #if PLATFORM_WINDOWS "-DPLATFORM_WINDOWS=1", + "-DNOMINMAX=1", #elif PLATFORM_MACOS "-DPLATFORM_MACOS=1", -// "-I/Library/Developer/CommandLineTools/usr/include/c++/v1", - fmt::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include/c++/v1", MACOS_SDK_VERSION), - fmt::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include", MACOS_SDK_VERSION), - fmt::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), - fmt::format("-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), + "-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1", + std::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}/include", __clang_major__), + "-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include", + "-I/Library/Developer/CommandLineTools/usr/include", #elif DPLATFORM_LINUX "-DPLATFORM_LINUX=1", #endif