From 697fd9c5ca6965c7fa58bdc08abab633b8309f0d Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sat, 21 Sep 2024 14:01:40 +0800 Subject: [PATCH 1/7] feat: support tostring operations for more std container --- Engine/Source/Common/Include/Common/String.h | 116 ++++++++++++++++--- Engine/Source/Common/Test/StringTest.cpp | 17 ++- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/Engine/Source/Common/Include/Common/String.h b/Engine/Source/Common/Include/Common/String.h index 975fa3ba..22d42e0c 100644 --- a/Engine/Source/Common/Include/Common/String.h +++ b/Engine/Source/Common/Include/Common/String.h @@ -4,12 +4,17 @@ #pragma once +#include #include #include #include #include #include #include +#include +#include +#include +#include #define FMT_HEADER_ONLY 1 #include @@ -97,6 +102,23 @@ namespace Common { } }; + template + struct StringConverter> { + static std::string ToString(const std::array& inValue) + { + std::stringstream stream; + stream << "("; + for (auto i = 0; i < N; i++) { + stream << StringConverter::ToString(inValue[i]); + if (i != N - 1) { + stream << ", "; + } + } + stream << ")"; + return stream.str(); + } + }; + template struct StringConverter> { static std::string ToString(const std::vector& inValue) @@ -118,17 +140,30 @@ namespace Common { struct StringConverter> { static std::string ToString(const std::unordered_set& inValue) { - std::vector temp; - temp.reserve(inValue.size()); + std::stringstream stream; + stream << "("; for (auto iter = inValue.begin(); iter != inValue.end(); ++iter) { - temp.emplace_back(&*iter); + stream << StringConverter::ToString(*iter); + auto iter2 = iter; + if (++iter2 != inValue.end()) { + stream << ", "; + } } + stream << ")"; + return stream.str(); + } + }; + template + struct StringConverter> { + static std::string ToString(const std::set& inValue) + { std::stringstream stream; stream << "("; - for (auto i = 0; i < temp.size(); i++) { - stream << StringConverter::ToString(*temp[i]); - if (i != temp.size() - 1) { + for (auto iter = inValue.begin(); iter != inValue.end(); ++iter) { + stream << StringConverter::ToString(*iter); + auto iter2 = iter; + if (++iter2 != inValue.end()) { stream << ", "; } } @@ -141,20 +176,30 @@ namespace Common { struct StringConverter> { static std::string ToString(const std::unordered_map& inValue) { - std::vector> temp; - temp.reserve(inValue.size()); + std::stringstream stream; + stream << "{"; for (auto iter = inValue.begin(); iter != inValue.end(); ++iter) { - temp.emplace_back(std::make_pair(&iter->first, &iter->second)); + stream << StringConverter>::ToString(*iter); + auto iter2 = iter; + if (++iter2 != inValue.end()) { + stream << ", "; + } } + stream << "}"; + return stream.str(); + } + }; + template + struct StringConverter> { + static std::string ToString(const std::map& inValue) + { std::stringstream stream; stream << "{"; - for (auto i = 0; i < temp.size(); i++) { - stream << fmt::format( - "{}: {}", - StringConverter::ToString(*temp[i].first), - StringConverter::ToString(*temp[i].second)); - if (i != temp.size() - 1) { + for (auto iter = inValue.begin(); iter != inValue.end(); ++iter) { + stream << StringConverter>::ToString(*iter); + auto iter2 = iter; + if (++iter2 != inValue.end()) { stream << ", "; } } @@ -162,4 +207,45 @@ namespace Common { return stream.str(); } }; + + template + struct StringConverter> { + template + static void ContactInternal(std::stringstream& stream, const TupleType& tuple, std::index_sequence) + { + std::initializer_list { ([&]() -> void { + stream << StringConverter>::ToString(std::get(tuple)); + if (I != N - 1) { + stream << ", "; + } + }(), 0)... }; + } + + static std::string ToString(const std::tuple& inValue) + { + std::stringstream stream; + stream << "("; + ContactInternal(stream, inValue, std::make_index_sequence {}); + stream << ")"; + return stream.str(); + } + }; + + template + struct StringConverter> { + static std::string ToString(const std::list& inValue) + { + std::stringstream stream; + stream << "("; + for (auto iter = inValue.begin(); iter != inValue.end(); ++iter) { + stream << StringConverter::ToString(*iter); + auto iter2 = iter; + if (++iter2 != inValue.end()) { + stream << ", "; + } + } + stream << ")"; + return stream.str(); + } + }; } diff --git a/Engine/Source/Common/Test/StringTest.cpp b/Engine/Source/Common/Test/StringTest.cpp index 0c48d63e..900b86aa 100644 --- a/Engine/Source/Common/Test/StringTest.cpp +++ b/Engine/Source/Common/Test/StringTest.cpp @@ -122,6 +122,21 @@ TEST(StringUtilsTest, ToStringTest) const std::pair v2 = { 1, false }; // NOLINT ASSERT_EQ(Common::ToString(v2), "1: false"); - const std::vector v3 = { 1, 2, 3 }; + const std::array v3 = { 1, 2, 3 }; ASSERT_EQ(Common::ToString(v3), "(1, 2, 3)"); + + const std::vector v4 = { 1, 2, 3 }; + ASSERT_EQ(Common::ToString(v4), "(1, 2, 3)"); + + const std::tuple v5 = { 1, false, 2 }; + ASSERT_EQ(Common::ToString(v5), "(1, false, 2)"); + + const std::list v6 = { 1, 2, 3 }; + ASSERT_EQ(Common::ToString(v6), "(1, 2, 3)"); + + const std::set v7 = { 1, 2, 3 }; + ASSERT_EQ(Common::ToString(v7), "(1, 2, 3)"); + + const std::unordered_map v8 = { { 1, false }, { 2, true } }; + ASSERT_EQ(Common::ToString(v8), "{1: false, 2: true}"); } From 49ee148019cb7a94ea2ee126a1dd832cfaa1e1f4 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sat, 21 Sep 2024 14:37:55 +0800 Subject: [PATCH 2/7] feat: support serialization for more std container --- CMake/Common.cmake | 1 + Editor/Source/Include/Editor/EditorModule.h | 2 +- Editor/Source/Src/EditorModule.cpp | 4 +- Editor/Source/Src/Resource.cpp | 2 +- .../Source/Common/Include/Common/Concepts.h | 8 +- .../Source/Common/Include/Common/Container.h | 37 ++ .../Source/Common/Include/Common/Math/Box.h | 2 +- .../Common/Include/Common/Serialization.h | 348 +++++++++++++++++- Engine/Source/Common/Test/ContainerTest.cpp | 55 ++- .../Source/Common/Test/SerializationTest.cpp | 26 +- Engine/Source/Common/Test/SerializationTest.h | 24 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 2 +- Engine/Source/Mirror/Test/AnyTest.cpp | 4 +- .../RHI-Vulkan/Src/Platform/Win32Surface.cpp | 1 + Engine/Source/Test/Include/Test/Test.h | 116 +----- 15 files changed, 440 insertions(+), 192 deletions(-) diff --git a/CMake/Common.cmake b/CMake/Common.cmake index 88813b9e..5a9c1ca1 100644 --- a/CMake/Common.cmake +++ b/CMake/Common.cmake @@ -1,4 +1,5 @@ set(CMAKE_CXX_STANDARD 20) +set(CMAKE_UNITY_BUILD ON) option(BUILD_EDITOR "Build Explosion editor" ON) option(CI "Build in CI" OFF) diff --git a/Editor/Source/Include/Editor/EditorModule.h b/Editor/Source/Include/Editor/EditorModule.h index f65fd7f7..a01d8d68 100644 --- a/Editor/Source/Include/Editor/EditorModule.h +++ b/Editor/Source/Include/Editor/EditorModule.h @@ -10,7 +10,7 @@ namespace Editor { class EditorModule final : public Runtime::IGameModule { public: void OnUnload() override; - Core::ModuleType Type() const override; + ::Core::ModuleType Type() const override; Runtime::Engine* CreateEngine(const Runtime::EngineInitParams&) override; private: diff --git a/Editor/Source/Src/EditorModule.cpp b/Editor/Source/Src/EditorModule.cpp index 9f1c976b..dd0737c6 100644 --- a/Editor/Source/Src/EditorModule.cpp +++ b/Editor/Source/Src/EditorModule.cpp @@ -12,9 +12,9 @@ namespace Editor { engine.Reset(); } - Core::ModuleType EditorModule::Type() const + ::Core::ModuleType EditorModule::Type() const { - return Core::ModuleType::mStatic; + return ::Core::ModuleType::mStatic; } Runtime::Engine* EditorModule::CreateEngine(const Runtime::EngineInitParams& inParams) diff --git a/Editor/Source/Src/Resource.cpp b/Editor/Source/Src/Resource.cpp index 731bc19f..2f38d537 100644 --- a/Editor/Source/Src/Resource.cpp +++ b/Editor/Source/Src/Resource.cpp @@ -13,7 +13,7 @@ namespace Editor { std::filesystem::path Resource::Path() const { - return Core::Paths::EngineRes() / file; + return ::Core::Paths::EngineRes() / file; } std::string Resource::String() const diff --git a/Engine/Source/Common/Include/Common/Concepts.h b/Engine/Source/Common/Include/Common/Concepts.h index 72a68ec4..305167d4 100644 --- a/Engine/Source/Common/Include/Common/Concepts.h +++ b/Engine/Source/Common/Include/Common/Concepts.h @@ -14,8 +14,8 @@ #include #include -namespace Common::Internal { - template concept BaseEqualComparable = requires(const T& lhs, const T& rhs) { { lhs == rhs } -> std::same_as; }; +namespace Common { + template concept BaseEqualComparable = requires(const T& lhs, const T& rhs) { { lhs == rhs } -> std::same_as; { lhs != rhs } -> std::same_as; }; template struct EqualComparableTest { static constexpr bool value = BaseEqualComparable; }; } @@ -51,10 +51,10 @@ namespace Common { template concept ArgsNumLessEqual = sizeof...(T) <= N; template concept ArgsNumGreaterEqual = sizeof...(T) >= N; template concept DerivedFrom = std::is_base_of_v; - template concept EqualComparable = Internal::EqualComparableTest::value; + template concept EqualComparable = EqualComparableTest::value; } -namespace Common::Internal { +namespace Common { // some types can perform operator== compare, but it requires element type also support operator== compare, so we test it further template struct EqualComparableTest> { static constexpr bool value = BaseEqualComparable; }; template struct EqualComparableTest> { static constexpr bool value = BaseEqualComparable; }; diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index 406e5454..f062cbc9 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -10,6 +10,7 @@ #include #include +#include namespace Common { class VectorUtils { @@ -109,6 +110,8 @@ namespace Common { T& operator[](size_t inIndex); const T& operator[](size_t inIndex) const; explicit operator bool() const; + template bool operator==(const InplaceVector& inRhs) const; + std::vector ToVector() const; Iter Begin(); ConstIter Begin() const; Iter End(); @@ -141,6 +144,13 @@ namespace Common { }; } +namespace Common { // NOLINT + template + struct EqualComparableTest> { + static constexpr bool value = BaseEqualComparable; + }; +} + namespace Common { template typename std::vector::iterator VectorUtils::SwapWithLastAndDelete(std::vector& vector, const typename std::vector::iterator& iterator) @@ -638,6 +648,33 @@ namespace Common { return !Empty(); } + template + template + bool InplaceVector::operator==(const InplaceVector& inRhs) const + { + if (Size() != inRhs.Size()) { + return false; + } + for (auto i = 0; i < Size(); i++) { + if (At(i) != inRhs.At(i)) { + return false; + } + } + return true; + } + + template + std::vector InplaceVector::ToVector() const + { + std::vector result; + result.reserve(Size()); + + for (auto i = 0; i < Size(); i++) { + result.emplace_back(At(i)); + } + return result; + } + template typename InplaceVector::Iter InplaceVector::Begin() { diff --git a/Engine/Source/Common/Include/Common/Math/Box.h b/Engine/Source/Common/Include/Common/Math/Box.h index 6db7ea39..7a29892b 100644 --- a/Engine/Source/Common/Include/Common/Math/Box.h +++ b/Engine/Source/Common/Include/Common/Math/Box.h @@ -84,7 +84,7 @@ namespace Common { // NOLINT }; template - struct JsonSerializer { + struct JsonSerializer> { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Box& inValue) { rapidjson::Value minJson; diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index 6d34a7df..c18c8045 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -10,8 +10,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -19,6 +22,7 @@ #include #include #include +#include namespace Common { class BinarySerializeStream { @@ -317,6 +321,7 @@ namespace Common { } bytes.resize(newPointer); } + // TODO endian swap memcpy(bytes.data() + pointer, data, size); pointer = newPointer; } @@ -355,6 +360,7 @@ namespace Common { { const auto newPointer = pointer + size; Assert(newPointer <= bytes.size()); + // TODO endian swap memcpy(data, bytes.data() + pointer, size); pointer = newPointer; } @@ -472,7 +478,7 @@ namespace Common { template <> struct Serializer { - static constexpr size_t typeId = HashUtils::StrCrc32("string"); + static constexpr size_t typeId = HashUtils::StrCrc32("std::string"); static size_t Serialize(BinarySerializeStream& stream, const std::string& value) { @@ -500,6 +506,36 @@ namespace Common { } }; + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("std::wstring"); + + 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); + serialized += Serializer::Serialize(stream, size); + + stream.Write(value.data(), size); + serialized += size; + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, std::wstring& value) + { + size_t deserialized = 0; + + uint64_t size; + deserialized += Serializer::Deserialize(stream, size); + + value.resize(size / sizeof(std::wstring::value_type)); + stream.Read(value.data(), size); + deserialized += size; + return deserialized; + } + }; + template struct Serializer> { static constexpr size_t typeId @@ -637,18 +673,48 @@ namespace Common { }; template - struct Serializer> { + struct Serializer> { static constexpr size_t typeId - = HashUtils::StrCrc32("std::unordered_set") + = HashUtils::StrCrc32("std::list") + Serializer::typeId; - static size_t Serialize(BinarySerializeStream& stream, const std::unordered_set& value) + static size_t Serialize(BinarySerializeStream& stream, const std::list& value) { size_t serialized = 0; - const uint64_t size = value.size(); - serialized += Serializer::Serialize(stream, size); + serialized += Serializer::Serialize(stream, value.size()); + for (const auto& element : value) { + serialized += Serializer::Serialize(stream, element); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, std::list& value) + { + size_t deserialized = 0; + + value.clear(); + uint64_t size; + deserialized += Serializer::Deserialize(stream, size); + + for (auto i = 0; i < size; i++) { + T element; + deserialized += Serializer::Deserialize(stream, element); + value.emplace_back(std::move(element)); + } + return deserialized; + } + }; + template + struct Serializer> { + static constexpr size_t typeId + = HashUtils::StrCrc32("std::unordered_set") + + Serializer::typeId; + + static size_t Serialize(BinarySerializeStream& stream, const std::unordered_set& value) + { + size_t serialized = Serializer::Serialize(stream, value.size()); for (const auto& element : value) { serialized += Serializer::Serialize(stream, element); } @@ -673,6 +739,38 @@ namespace Common { } }; + template + struct Serializer> { + static constexpr size_t typeId + = HashUtils::StrCrc32("std::set") + + Serializer::typeId; + + static size_t Serialize(BinarySerializeStream& stream, const std::set& value) + { + size_t serialized = Serializer::Serialize(stream, value.size()); + for (const auto& element : value) { + serialized += Serializer::Serialize(stream, element); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, std::set& value) + { + size_t deserialized = 0; + + value.clear(); + uint64_t size; + deserialized += Serializer::Deserialize(stream, size); + + for (auto i = 0; i < size; i++) { + T temp; + deserialized += Serializer::Deserialize(stream, temp); + value.emplace(std::move(temp)); + } + return deserialized; + } + }; + template struct Serializer> { static constexpr size_t typeId @@ -711,6 +809,89 @@ namespace Common { } }; + template + struct Serializer> { + static constexpr size_t typeId + = HashUtils::StrCrc32("std::map") + + Serializer::typeId + + Serializer::typeId; + + static size_t Serialize(BinarySerializeStream& stream, const std::map& value) + { + size_t serialized = 0; + + serialized += Serializer::Serialize(stream, value.size()); + for (const auto& pair : value) { + serialized += Serializer>::Serialize(stream, pair); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, std::map& value) + { + size_t deserialized = 0; + + value.clear(); + uint64_t size; + deserialized += Serializer::Deserialize(stream, size); + + for (auto i = 0; i < size; i++) { + std::pair pair; + deserialized += Serializer>::Deserialize(stream, pair); + value.emplace(std::move(pair)); + } + return deserialized; + } + }; + + template struct TupleTypeId {}; + template struct TupleTypeId { static constexpr size_t value = HashUtils::StrCrc32("std::tuple"); }; + template struct TupleTypeId { static constexpr size_t value = Serializer::typeId + TupleTypeId::value; }; + + template + struct Serializer> { + static constexpr size_t typeId = TupleTypeId::value; + + template + static size_t SerializeInternal(BinarySerializeStream& stream, const std::tuple& value, std::index_sequence) + { + size_t result = 0; + std::initializer_list { ([&]() -> void { + result += Serializer::Serialize(stream, std::get(value)); + }(), 0)... }; + return result; + } + + template + static size_t DeserializeInternal(BinaryDeserializeStream& stream, std::tuple& value, std::index_sequence) + { + size_t result = 0; + std::initializer_list { ([&]() -> void { + result += Serializer::Deserialize(stream, std::get(value)); + }(), 0)... }; + return result; + } + + static size_t Serialize(BinarySerializeStream& stream, const std::tuple& value) + { + size_t serialized = 0; + serialized += Serializer::Serialize(stream, sizeof...(T)); + serialized += SerializeInternal(stream, value, std::make_index_sequence {}); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, std::tuple& value) + { + size_t deserialized = 0; + + value = {}; + uint64_t size; + deserialized += Serializer::Deserialize(stream, size); + deserialized += DeserializeInternal(stream, value, std::make_index_sequence {}); + return deserialized; + } + }; + template <> struct JsonSerializer { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const bool& inValue) @@ -903,6 +1084,25 @@ namespace Common { } }; + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::wstring& inValue) + { + const auto str = StringUtils::ToByteString(inValue); + auto* memory = static_cast(inAllocator.Malloc(str.length())); + memcpy(memory, str.c_str(), str.length()); + outJsonValue.SetString(memory, str.length()); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::wstring& outValue) + { + if (!inJsonValue.IsString()) { + return; + } + outValue = StringUtils::ToWideString(std::string(inJsonValue.GetString(), inJsonValue.GetStringLength())); + } + }; + template struct JsonSerializer> { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::optional& inValue) @@ -1015,6 +1215,34 @@ namespace Common { } }; + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::list& inValue) + { + outJsonValue.SetArray(); + outJsonValue.Reserve(inValue.size(), inAllocator); + for (const auto& element : inValue) { + rapidjson::Value jsonElement; + JsonSerializer::JsonSerialize(jsonElement, inAllocator, element); + outJsonValue.PushBack(jsonElement, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::list& outValue) + { + outValue.clear(); + + if (!inJsonValue.IsArray()) { + return; + } + for (auto i = 0; i < inJsonValue.Size(); i++) { + T element; + JsonSerializer::JsonDeserialize(inJsonValue[i], element); + outValue.emplace_back(std::move(element)); + } + } + }; + template struct JsonSerializer> { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::unordered_set& inValue) @@ -1044,6 +1272,34 @@ namespace Common { } }; + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::set& inValue) + { + outJsonValue.SetArray(); + outJsonValue.Reserve(inValue.size(), inAllocator); + for (const auto& element : inValue) { + rapidjson::Value jsonElement; + JsonSerializer::JsonSerialize(jsonElement, inAllocator, element); + outJsonValue.PushBack(jsonElement, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::set& outValue) + { + outValue.clear(); + + if (!inJsonValue.IsArray()) { + return; + } + for (auto i = 0; i < inJsonValue.Size(); i++) { + T element; + JsonSerializer::JsonDeserialize(inJsonValue[i], element); + outValue.emplace(std::move(element)); + } + } + }; + template struct JsonSerializer> { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::unordered_map& inValue) @@ -1073,11 +1329,77 @@ namespace Common { } }; - // TODO std::wstring - // TODO std::set - // TODO std::map - // TODO std::tuple - // TODO std::queue - // TODO std::stack - // TODO std::list + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::map& inValue) + { + outJsonValue.SetArray(); + outJsonValue.Reserve(inValue.size(), inAllocator); + for (const auto& pair : inValue) { + rapidjson::Value jsonElement; + JsonSerializer>::JsonSerialize(jsonElement, inAllocator, pair); + outJsonValue.PushBack(jsonElement, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::map& outValue) + { + outValue.clear(); + + if (!inJsonValue.IsArray()) { + return; + } + for (auto i = 0; i < inJsonValue.Size(); i++) { + std::pair pair; + JsonSerializer>::JsonDeserialize(inJsonValue[i], pair); + outValue.emplace(std::move(pair)); + } + } + }; + + template + struct JsonSerializer> { + template + static void JsonSerializeInternal(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::tuple& inValue, std::index_sequence) + { + std::initializer_list { ([&]() -> void { + const auto key = std::to_string(I); + auto* keyMemory = static_cast(inAllocator.Malloc(key.length())); + memcpy(keyMemory, key.data(), key.length()); + + rapidjson::Value jsonElement; + JsonSerializer::JsonSerialize(jsonElement, inAllocator, std::get(inValue)); + + outJsonValue.AddMember(rapidjson::StringRef(keyMemory, key.length()), jsonElement, inAllocator); + }(), 0)... }; + } + + template + static void JsonDeserializeInternal(const rapidjson::Value& inJsonValue, std::tuple& outValue, std::index_sequence) + { + std::initializer_list { ([&]() -> void { + const auto key = std::to_string(I); + if (!inJsonValue.HasMember(key.c_str())) { + return; + } + JsonSerializer::JsonDeserialize(inJsonValue[key.c_str()], std::get(outValue)); + }(), 0)... }; + } + + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::tuple& inValue) + { + outJsonValue.SetObject(); + JsonSerializeInternal(outJsonValue, inAllocator, inValue, std::make_index_sequence()); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::tuple& outValue) + { + outValue = {}; + + if (!inJsonValue.IsObject()) { + return; + } + JsonDeserializeInternal(inJsonValue, outValue, std::make_index_sequence()); + } + }; } diff --git a/Engine/Source/Common/Test/ContainerTest.cpp b/Engine/Source/Common/Test/ContainerTest.cpp index a8eb03d7..eba61b06 100644 --- a/Engine/Source/Common/Test/ContainerTest.cpp +++ b/Engine/Source/Common/Test/ContainerTest.cpp @@ -4,7 +4,6 @@ #include #include -using namespace Test; using namespace Common; TEST(ContainerTest, VectorSwapDeleteTest) @@ -12,7 +11,7 @@ TEST(ContainerTest, VectorSwapDeleteTest) std::vector vec0 = { 1, 2, 3, 4, 5 }; const auto index = VectorUtils::SwapWithLastAndDelete(vec0, 2); ASSERT_EQ(index, 2); - AssertVecEq(vec0, std::vector { 1, 2, 5, 4 }); + ASSERT_EQ(vec0, (std::vector { 1, 2, 5, 4 })); std::vector vec1 = { 1, 1, 2, 2, 3, 4, 4, 4 }; for (size_t i = 0; i < vec1.size();) { @@ -22,7 +21,7 @@ TEST(ContainerTest, VectorSwapDeleteTest) i++; } } - AssertVecEq(vec1, std::vector { 1, 1, 4, 4, 3, 4 }); + ASSERT_EQ(vec1, (std::vector { 1, 1, 4, 4, 3, 4 })); std::vector vec2 = { 2, 2, 3, 3, 4, 4, 5 }; auto iter = vec2.begin(); @@ -33,7 +32,7 @@ TEST(ContainerTest, VectorSwapDeleteTest) ++iter; } } - AssertVecEq(vec2, std::vector { 2, 2, 5, 4, 4 }); + ASSERT_EQ(vec2, (std::vector { 2, 2, 5, 4, 4 })); } TEST(ContainerTest, VectorGetIntersection) @@ -42,7 +41,7 @@ TEST(ContainerTest, VectorGetIntersection) const std::vector b = { 3, 4, 5, 6, 7 }; const auto result = VectorUtils::GetIntersection(a, b); - AssertVecEq(result, std::vector { 3, 4, 5 }); + ASSERT_EQ(result, (std::vector { 3, 4, 5 })); } TEST(ContainerTest, SetGetIntersection) @@ -54,7 +53,7 @@ TEST(ContainerTest, SetGetIntersection) ASSERT_EQ(result.size(), 3); } -TEST(ContainerTest, HeapVectorBasic) +TEST(ContainerTest, InplaceVectorBasic) { InplaceVector t0(4, 0); ASSERT_EQ(t0.Capacity(), 10); @@ -63,43 +62,43 @@ TEST(ContainerTest, HeapVectorBasic) for (auto i = 0; i < t0.Size(); i++) { t0[i] = i + 1; } - AssertVecEq(t0, std::vector { 1, 2, 3, 4 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 1, 2, 3, 4 })); t0.EmplaceBack(5); - AssertVecEq(t0, std::vector { 1, 2, 3, 4, 5 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 1, 2, 3, 4, 5 })); t0.PushBack(6); - AssertVecEq(t0, std::vector { 1, 2, 3, 4, 5, 6 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 1, 2, 3, 4, 5, 6 })); t0.PopBack(); - AssertVecEq(t0, std::vector { 1, 2, 3, 4, 5 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 1, 2, 3, 4, 5 })); t0.Insert(0, 0); - AssertVecEq(t0, std::vector { 0, 1, 2, 3, 4, 5 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 0, 1, 2, 3, 4, 5 })); t0.Insert(3, 6); - AssertVecEq(t0, std::vector { 0, 1, 2, 6, 3, 4, 5 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 0, 1, 2, 6, 3, 4, 5 })); t0.Insert(7, 7); - AssertVecEq(t0, std::vector { 0, 1, 2, 6, 3, 4, 5, 7 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 0, 1, 2, 6, 3, 4, 5, 7 })); t0.Erase(3); - AssertVecEq(t0, std::vector { 0, 1, 2, 3, 4, 5, 7 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 0, 1, 2, 3, 4, 5, 7 })); t0.Erase(0); - AssertVecEq(t0, std::vector { 1, 2, 3, 4, 5, 7 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 1, 2, 3, 4, 5, 7 })); t0.Erase(5); - AssertVecEq(t0, std::vector { 1, 2, 3, 4, 5 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 1, 2, 3, 4, 5 })); t0.EraseSwapLast(0); - AssertVecEq(t0, std::vector { 5, 2, 3, 4 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 5, 2, 3, 4 })); t0.EraseSwapLast(3); - AssertVecEq(t0, std::vector { 5, 2, 3 }); + ASSERT_EQ(t0.ToVector(), (std::vector { 5, 2, 3 })); } -TEST(ContainerTest, HeapVectorIter) +TEST(ContainerTest, InplaceVectorIter) { struct S0 { int32_t a; @@ -133,7 +132,7 @@ TEST(ContainerTest, HeapVectorIter) t0.At(2) = { 3, 4 }; t0.At(3) = { 4, 5 }; t0.At(4) = { 5, 6 }; - AssertVecEq(t0, std::vector { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 6 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 6 } })); auto i = 0; for (const auto& element : t0) { @@ -142,28 +141,28 @@ TEST(ContainerTest, HeapVectorIter) } t0.Erase(t0.Begin()); - AssertVecEq(t0, std::vector { { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 6 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 6 } })); t0.Erase(t0.Begin() + 2); - AssertVecEq(t0, std::vector { { 2, 3 }, { 3, 4 }, { 5, 6 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 2, 3 }, { 3, 4 }, { 5, 6 } })); t0.Erase(t0.End()); - AssertVecEq(t0, std::vector { { 2, 3 }, { 3, 4 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 2, 3 }, { 3, 4 } })); t0.EmplaceBack(7, 8); - AssertVecEq(t0, std::vector { { 2, 3 }, { 3, 4 }, { 7, 8 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 2, 3 }, { 3, 4 }, { 7, 8 } })); t0.EmplaceBack(8, 9); - AssertVecEq(t0, std::vector { { 2, 3 }, { 3, 4 }, { 7, 8 }, { 8, 9 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 2, 3 }, { 3, 4 }, { 7, 8 }, { 8, 9 } })); t0.EraseSwapLast(t0.Begin()); - AssertVecEq(t0, std::vector { { 8, 9 }, { 3, 4 }, { 7, 8 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 8, 9 }, { 3, 4 }, { 7, 8 } })); t0.EraseSwapLast(t0.End() - 1); - AssertVecEq(t0, std::vector { { 8, 9 }, { 3, 4 } }); + ASSERT_EQ(t0.ToVector(), (std::vector { { 8, 9 }, { 3, 4 } })); } -TEST(ContainerTest, HeapVectorCopyAndMove) +TEST(ContainerTest, InplaceVectorCopyAndMove) { enum class ConstructType : uint8_t { cDefault, diff --git a/Engine/Source/Common/Test/SerializationTest.cpp b/Engine/Source/Common/Test/SerializationTest.cpp index 03f91eb6..0dde1e09 100644 --- a/Engine/Source/Common/Test/SerializationTest.cpp +++ b/Engine/Source/Common/Test/SerializationTest.cpp @@ -69,13 +69,18 @@ TEST(SerializationTest, TypedSerializationTest) PerformTypedSerializationTest(5.0f); PerformTypedSerializationTest(6.0); PerformTypedSerializationTest("hello"); + PerformTypedSerializationTest(L"hello"); PerformTypedSerializationTest>({}); PerformTypedSerializationTest>(15); PerformTypedSerializationTest>({ 1, false }); - PerformTypedSerializationTest>({ 1, 2, 3 }, ::Test::CompareArray); - PerformTypedSerializationTest>({ 1, 2, 3 }, ::Test::CompareVec); - PerformTypedSerializationTest>({ 1, 2, 3 }, ::Test::CompareUnorderedSet); - PerformTypedSerializationTest>({ { 1, false }, { 2, true } }, ::Test::CompareUnorderedMap); + PerformTypedSerializationTest>({ 1, 2, 3 }); + PerformTypedSerializationTest>({ 1, 2, 3 }); + PerformTypedSerializationTest>({ 1, 2, 3 }); + PerformTypedSerializationTest>({ 1, 2, 3 }); + PerformTypedSerializationTest>({ 1, 2, 3 }); + PerformTypedSerializationTest>({ { 1, false }, { 2, true } }); + PerformTypedSerializationTest>({ { 1, false }, { 2, true } }); + PerformTypedSerializationTest>({ 1, true, 2 }); } TEST(SerializationTest, JsonSerializeTest) @@ -93,11 +98,16 @@ TEST(SerializationTest, JsonSerializeTest) PerformJsonSerializationTest(5.0f, "5.0"); PerformJsonSerializationTest(6.0, "6.0"); PerformJsonSerializationTest("hello", R"("hello")"); + PerformJsonSerializationTest(L"hello", R"("hello")"); PerformJsonSerializationTest>({}, "null"); PerformJsonSerializationTest>(15, "15"); PerformJsonSerializationTest>({ 1, false }, R"({"key":1,"value":false})"); - PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]", ::Test::CompareArray); - PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]", ::Test::CompareVec); - PerformJsonSerializationTest>({ 1, 2, 3 }, "", ::Test::CompareUnorderedSet); - PerformJsonSerializationTest>({ { 1, false }, { 2, true } }, "", ::Test::CompareUnorderedMap); + PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]"); + PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]"); + PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]"); + PerformJsonSerializationTest>({ 1, 2, 3 }, ""); + PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]"); + PerformJsonSerializationTest>({ { 1, false }, { 2, true } }, ""); + PerformJsonSerializationTest>({ { 1, false }, { 2, true } }, R"([{"key":1,"value":false},{"key":2,"value":true}])"); + PerformJsonSerializationTest>({ 1, true, 2 }, R"({"0":1,"1":true,"2":2})"); } diff --git a/Engine/Source/Common/Test/SerializationTest.h b/Engine/Source/Common/Test/SerializationTest.h index 737924fd..e1b3780b 100644 --- a/Engine/Source/Common/Test/SerializationTest.h +++ b/Engine/Source/Common/Test/SerializationTest.h @@ -12,7 +12,7 @@ #include template -void PerformTypedSerializationTestWithEndian(const T& inValue, const Test::CustomComparer& inCustomCompareFunc = {}) +void PerformTypedSerializationTestWithEndian(const T& inValue) { static std::filesystem::path fileName = "../Test/Generated/Common/SerializationTest.TypedSerializationTest"; std::filesystem::create_directories(fileName.parent_path()); @@ -27,24 +27,20 @@ void PerformTypedSerializationTestWithEndian(const T& inValue, const Test::Custo Common::BinaryFileDeserializeStream stream(fileName.string()); Common::Deserialize(stream, value); - if (inCustomCompareFunc) { - ASSERT_TRUE(inCustomCompareFunc(inValue, value)); - } else { - ASSERT_EQ(inValue, value); - } + ASSERT_EQ(inValue, value); } } template -void PerformTypedSerializationTest(const T& inValue, const Test::CustomComparer& inCustomCompareFunc = {}) +void PerformTypedSerializationTest(const T& inValue) { - PerformTypedSerializationTestWithEndian(inValue, inCustomCompareFunc); - PerformTypedSerializationTestWithEndian(inValue, inCustomCompareFunc); - PerformTypedSerializationTestWithEndian(inValue, inCustomCompareFunc); + PerformTypedSerializationTestWithEndian(inValue); + PerformTypedSerializationTestWithEndian(inValue); + PerformTypedSerializationTestWithEndian(inValue); } template -void PerformJsonSerializationTest(const T& inValue, const std::string& inExceptJson, const Test::CustomComparer& inCustomCompareFunc = {}) +void PerformJsonSerializationTest(const T& inValue, const std::string& inExceptJson) { std::string json; { @@ -73,10 +69,6 @@ void PerformJsonSerializationTest(const T& inValue, const std::string& inExceptJ T value; Common::JsonDeserialize(jsonValue, value); - if (inCustomCompareFunc) { - ASSERT_TRUE(inCustomCompareFunc(inValue, value)); - } else { - ASSERT_EQ(inValue, value); - } + ASSERT_EQ(inValue, value); } } diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 04aeb2c6..72c2cbe3 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -230,7 +230,7 @@ namespace Mirror { void JsonDeserialize(const rapidjson::Value& inJsonValue) const; std::string ToString() const; - // always return original ptr and size, even policy is ref + // always return original ptr and size, even policy is a reference void* Data() const; size_t Size() const; diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index a518b93c..b106e536 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -171,7 +171,7 @@ TEST(AnyTest, ValueCtorTest) ASSERT_EQ(a1.As(), 2.0f); Any a2 = std::vector { 1, 2, 3 }; - ::Test::AssertVecEq(a2.As>(), std::vector { 1, 2, 3 }); + ASSERT_EQ(a2.As>(), (std::vector { 1, 2, 3 })); const Any a3 = AnyBasicTest { 1, 2.0f }; ASSERT_EQ(a3.As(), (AnyBasicTest { 1, 2 })); @@ -199,7 +199,7 @@ TEST(AnyTest, RefCtorTest) std::vector v2 = { 1, 2, 3 }; const Any a2 = std::ref(v2); ASSERT_EQ(a2.Policy(), AnyPolicy::nonConstRef); - ::Test::AssertVecEq(a2.As(), std::vector { 1, 2, 3 }); + ASSERT_EQ(a2.As(), (std::vector { 1, 2, 3 })); const AnyBasicTest v3 { 1, 2.0f }; // NOLINT const auto r1 = std::ref(v3); diff --git a/Engine/Source/RHI-Vulkan/Src/Platform/Win32Surface.cpp b/Engine/Source/RHI-Vulkan/Src/Platform/Win32Surface.cpp index dcbde7ca..b67fa94b 100644 --- a/Engine/Source/RHI-Vulkan/Src/Platform/Win32Surface.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Platform/Win32Surface.cpp @@ -9,6 +9,7 @@ #define VK_USE_PLATFORM_WIN32_KHR #include +#include #include namespace RHI::Vulkan { diff --git a/Engine/Source/Test/Include/Test/Test.h b/Engine/Source/Test/Include/Test/Test.h index e8bf14d7..3fde79c2 100644 --- a/Engine/Source/Test/Include/Test/Test.h +++ b/Engine/Source/Test/Include/Test/Test.h @@ -6,118 +6,4 @@ #include -#include - -namespace Test { - template - concept StdVec = requires (T container) - { - container.size(); - container[0]; - }; - - template - concept ExpVec = requires (T container) - { - container.Size(); - container[0]; - }; - - template void AssertVecEq(A&& inLhs, B&& inRhs); - template void AssertVecEq(A&& inLhs, B&& inRhs); - template void AssertVecEq(A&& inLhs, B&& inRhs); - - template using CustomComparer = std::function; - template bool CompareArray(const std::array& inLhs, const std::array& inRhs); - template bool CompareVec(const std::vector& inLhs, const std::vector& inRhs); - template bool CompareUnorderedSet(const std::unordered_set& inLhs, const std::unordered_set& inRhs); - template bool CompareUnorderedMap(const std::unordered_map& inLhs, const std::unordered_map& inRhs); -} - -namespace Test { - template - void AssertVecEq(A&& inLhs, B&& inRhs) - { - ASSERT_EQ(inLhs.size(), inRhs.size()); - for (auto i = 0; i < inLhs.size(); i++) { - ASSERT_EQ(inLhs[i], inRhs[i]); - } - } - - template - void AssertVecEq(A&& inLhs, B&& inRhs) - { - ASSERT_EQ(inLhs.Size(), inRhs.size()); - for (auto i = 0; i < inLhs.Size(); i++) { - ASSERT_EQ(inLhs[i], inRhs[i]); - } - } - - template - void AssertVecEq(A&& inLhs, B&& inRhs) - { - ASSERT_EQ(inLhs.size(), inRhs.Size()); - for (auto i = 0; i < inLhs.size(); i++) { - ASSERT_EQ(inLhs[i], inRhs[i]); - } - } - - template - bool CompareArray(const std::array& inLhs, const std::array& inRhs) - { - if (inLhs.size() != N || inRhs.size() != N) { - return false; - } - for (auto i = 0; i < N; i++) { - if (inLhs[i] != inRhs[i]) { - return false; - } - } - return true; - } - - template - bool CompareVec(const std::vector& inLhs, const std::vector& inRhs) - { - if (inLhs.size() != inRhs.size()) { - return false; - } - for (auto i = 0; i < inLhs.size(); i++) { - if (inLhs[i] != inRhs[i]) { - return false; - } - } - return true; - } - - template - bool CompareUnorderedSet(const std::unordered_set& inLhs, const std::unordered_set& inRhs) - { - if (inLhs.size() != inRhs.size()) { - return false; - } - for (const auto& element : inLhs) { - if (!inRhs.contains(element)) { - return false; - } - } - return true; - } - - template - bool CompareUnorderedMap(const std::unordered_map& inLhs, const std::unordered_map& inRhs) - { - if (inLhs.size() != inRhs.size()) { - return false; - } - for (const auto& [key, value] : inLhs) { - if (!inRhs.contains(key)) { - return false; - } - if (inRhs.at(key) != value) { - return false; - } - } - return true; - } -} +namespace Test {} From 6535d0ddf7d93dc5f2985ec5069bf8c229f2ebf0 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Wed, 25 Sep 2024 19:43:01 +0800 Subject: [PATCH 3/7] feat: add serialization test for math lib fix: error math serialization issue --- Editor/Source/Src/Theme.cpp | 1 - .../Source/Common/Include/Common/Concepts.h | 4 +- .../Source/Common/Include/Common/Math/Box.h | 6 +- .../Source/Common/Include/Common/Math/Half.h | 4 +- .../Common/Include/Common/Math/Matrix.h | 17 +- .../Common/Include/Common/Math/Projection.h | 62 +++++- .../Common/Include/Common/Math/Quaternion.h | 46 ++-- .../Source/Common/Include/Common/Math/Rect.h | 6 +- .../Common/Include/Common/Math/Sphere.h | 10 +- .../Common/Include/Common/Math/Transform.h | 8 +- .../Common/Include/Common/Math/Vector.h | 2 +- .../Common/Include/Common/Serialization.h | 29 ++- Engine/Source/Common/Test/MathTest.cpp | 206 +++++++++++++++++- .../Source/Common/Test/SerializationTest.cpp | 1 + Engine/Source/Common/Test/SerializationTest.h | 46 +++- Engine/Source/Core/Src/Module.cpp | 4 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 139 +++++++++--- Engine/Source/Mirror/Src/Mirror.cpp | 120 ++-------- 18 files changed, 520 insertions(+), 191 deletions(-) diff --git a/Editor/Source/Src/Theme.cpp b/Editor/Source/Src/Theme.cpp index 8f7ee4e3..68c5d336 100644 --- a/Editor/Source/Src/Theme.cpp +++ b/Editor/Source/Src/Theme.cpp @@ -6,7 +6,6 @@ namespace Editor { Theme::Theme() - // TODO : colorPrimary() , colorSecondary() , colorBackground(0x24, 0x29, 0x2f) diff --git a/Engine/Source/Common/Include/Common/Concepts.h b/Engine/Source/Common/Include/Common/Concepts.h index 305167d4..77b8e718 100644 --- a/Engine/Source/Common/Include/Common/Concepts.h +++ b/Engine/Source/Common/Include/Common/Concepts.h @@ -35,11 +35,13 @@ namespace Common { template concept CppEnum = std::is_enum_v; template concept CppFunction = std::is_function_v; template concept CppInvocable = std::is_invocable_v; + template concept CppConst = std::is_const_v; template concept CppPointer = std::is_pointer_v; + template concept CppConstPointer = CppPointer && CppConst>; template concept CppRef = std::is_reference_v; template concept CppLValueRef = std::is_lvalue_reference_v; + template concept CppLValueConstRef = CppLValueRef && CppConst>; template concept CppRValueRef = std::is_rvalue_reference_v; - template concept CppConst = std::is_const_v; template concept CppVolatile = std::is_volatile_v; template concept CppCopyConstructible = std::is_copy_constructible_v; template concept CppMoveConstructible = std::is_move_constructible_v; diff --git a/Engine/Source/Common/Include/Common/Math/Box.h b/Engine/Source/Common/Include/Common/Math/Box.h index 7a29892b..72540c80 100644 --- a/Engine/Source/Common/Include/Common/Math/Box.h +++ b/Engine/Source/Common/Include/Common/Math/Box.h @@ -77,9 +77,11 @@ namespace Common { // NOLINT static std::string ToString(const Box& inValue) { return fmt::format( - "{min={}, max={}}", + "{}min={}, max={}{}", + "{", StringConverter>::ToString(inValue.min), - StringConverter>::ToString(inValue.max)); + StringConverter>::ToString(inValue.max), + "}"); } }; diff --git a/Engine/Source/Common/Include/Common/Math/Half.h b/Engine/Source/Common/Include/Common/Math/Half.h index d097c3f1..dd386343 100644 --- a/Engine/Source/Common/Include/Common/Math/Half.h +++ b/Engine/Source/Common/Include/Common/Math/Half.h @@ -135,7 +135,7 @@ namespace Common { JsonSerializer::JsonSerialize(outJsonValue, inAllocator, inValue.value); } - static void JsonDeserialize(rapidjson::Value& inJsonValue, Internal::FullFloat& outValue) + static void JsonDeserialize(const rapidjson::Value& inJsonValue, Internal::FullFloat& outValue) { JsonSerializer::JsonDeserialize(inJsonValue, outValue.value); } @@ -148,7 +148,7 @@ namespace Common { JsonSerializer::JsonSerialize(outJsonValue, inAllocator, inValue.AsFloat()); } - static void JsonDeserialize(rapidjson::Value& inJsonValue, HalfFloat& outValue) + static void JsonDeserialize(const rapidjson::Value& inJsonValue, HalfFloat& outValue) { float fltValue; JsonSerializer::JsonDeserialize(inJsonValue, fltValue); diff --git a/Engine/Source/Common/Include/Common/Math/Matrix.h b/Engine/Source/Common/Include/Common/Math/Matrix.h index 3add3ed7..acc49e2f 100644 --- a/Engine/Source/Common/Include/Common/Math/Matrix.h +++ b/Engine/Source/Common/Include/Common/Math/Matrix.h @@ -331,11 +331,18 @@ namespace Common { // NOLINT struct StringConverter> { static std::string ToString(const Mat& inValue) { - return fmt::format("{row0={}, row1={}, row2={}, row3={}}", - StringConverter>::ToString(inValue.Row(0)), - StringConverter>::ToString(inValue.Row(1)), - StringConverter>::ToString(inValue.Row(2)), - StringConverter>::ToString(inValue.Row(3))); + std::stringstream stream; + stream << "("; + for (auto i = 0; i < R; i++) { + for (auto j = 0; j < C; j++) { + stream << StringConverter::ToString(inValue.At(i, j)); + if (i * C + j != R * C - 1) { + stream << ", "; + } + } + } + stream << ")"; + return stream.str(); } }; diff --git a/Engine/Source/Common/Include/Common/Math/Projection.h b/Engine/Source/Common/Include/Common/Math/Projection.h index ed973e37..553481a8 100644 --- a/Engine/Source/Common/Include/Common/Math/Projection.h +++ b/Engine/Source/Common/Include/Common/Math/Projection.h @@ -112,11 +112,13 @@ namespace Common { static std::string ToString(const ReversedZOrthogonalProjection& inValue) { return fmt::format( - "{width={}, height={}, near={}, far={}}", + "{}width={}, height={}, near={}, far={}{}", + "{", StringConverter::ToString(inValue.width), StringConverter::ToString(inValue.height), StringConverter::ToString(inValue.nearPlane), - StringConverter>::ToString(inValue.farPlane)); + StringConverter>::ToString(inValue.farPlane), + "}"); } }; @@ -125,12 +127,14 @@ namespace Common { static std::string ToString(const ReversedZPerspectiveProjection& inValue) { return fmt::format( - "{fov={}, width={}, height={}, near={}, far={}}", + "{}fov={}, width={}, height={}, near={}, far={}{}", + "{", StringConverter::ToString(inValue.fov), StringConverter::ToString(inValue.width), StringConverter::ToString(inValue.height), StringConverter::ToString(inValue.nearPlane), - StringConverter>::ToString(inValue.farPlane)); + StringConverter>::ToString(inValue.farPlane), + "}"); } }; @@ -176,6 +180,56 @@ namespace Common { } } }; + + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const ReversedZPerspectiveProjection& inValue) + { + rapidjson::Value fovJson; + JsonSerializer::JsonSerialize(fovJson, inAllocator, inValue.fov); + + rapidjson::Value widthJson; + JsonSerializer::JsonSerialize(widthJson, inAllocator, inValue.width); + + rapidjson::Value heightJson; + JsonSerializer::JsonSerialize(heightJson, inAllocator, inValue.height); + + rapidjson::Value nearJson; + JsonSerializer::JsonSerialize(nearJson, inAllocator, inValue.nearPlane); + + rapidjson::Value farJson; + JsonSerializer>::JsonSerialize(farJson, inAllocator, inValue.farPlane); + + outJsonValue.SetObject(); + outJsonValue.AddMember("fov", fovJson, inAllocator); + outJsonValue.AddMember("width", widthJson, inAllocator); + outJsonValue.AddMember("height", heightJson, inAllocator); + outJsonValue.AddMember("near", nearJson, inAllocator); + outJsonValue.AddMember("far", farJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, ReversedZPerspectiveProjection& outValue) + { + if (!inJsonValue.IsObject()) { + return; + } + if (inJsonValue.HasMember("fov")) { + JsonSerializer::JsonDeserialize(inJsonValue["fov"], outValue.fov); + } + if (inJsonValue.HasMember("width")) { + JsonSerializer::JsonDeserialize(inJsonValue["width"], outValue.width); + } + if (inJsonValue.HasMember("height")) { + JsonSerializer::JsonDeserialize(inJsonValue["height"], outValue.height); + } + if (inJsonValue.HasMember("near")) { + JsonSerializer::JsonDeserialize(inJsonValue["near"], outValue.nearPlane); + } + if (inJsonValue.HasMember("far")) { + JsonSerializer>::JsonDeserialize(inJsonValue["far"], outValue.farPlane); + } + } + }; } namespace Common { diff --git a/Engine/Source/Common/Include/Common/Math/Quaternion.h b/Engine/Source/Common/Include/Common/Math/Quaternion.h index 336271ee..9def2483 100644 --- a/Engine/Source/Common/Include/Common/Math/Quaternion.h +++ b/Engine/Source/Common/Include/Common/Math/Quaternion.h @@ -40,6 +40,7 @@ namespace Common { Angle(Angle&& inValue) noexcept; Angle& operator=(const Angle& inValue); Angle& operator=(const Radian& inValue); + bool operator==(const Angle& inRhs) const; T ToRadian() const; }; @@ -52,6 +53,7 @@ namespace Common { Radian(Radian&& inValue) noexcept; Radian& operator=(const Radian& inValue); Radian& operator=(const Angle& inValue); + bool operator==(const Radian& inRhs) const; T ToAngle() const; }; @@ -163,18 +165,18 @@ namespace Common { static size_t Serialize(BinarySerializeStream& stream, const Quaternion& value) { - return Serializer::Serialize(stream, value.x) + return Serializer::Serialize(stream, value.w) + + Serializer::Serialize(stream, value.x) + Serializer::Serialize(stream, value.y) - + Serializer::Serialize(stream, value.z) - + Serializer::Serialize(stream, value.w); + + Serializer::Serialize(stream, value.z); } static size_t Deserialize(BinaryDeserializeStream& stream, Quaternion& value) { - return Serializer::Deserialize(stream, value.x) + return Serializer::Deserialize(stream, value.w) + + Serializer::Deserialize(stream, value.x) + Serializer::Deserialize(stream, value.y) - + Serializer::Deserialize(stream, value.z) - + Serializer::Deserialize(stream, value.w); + + Serializer::Deserialize(stream, value.z); } }; @@ -200,10 +202,10 @@ namespace Common { { return fmt::format( "({}, {}, {}, {})", + StringConverter::ToString(inValue.w), StringConverter::ToString(inValue.x), StringConverter::ToString(inValue.y), - StringConverter::ToString(inValue.z), - StringConverter::ToString(inValue.w)); + StringConverter::ToString(inValue.z)); } }; @@ -238,16 +240,16 @@ namespace Common { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Quaternion& inValue) { rapidjson::Value xJson; - JsonSerializer::JsonSerialize(xJson, inAllocator, inValue.x); + JsonSerializer::JsonSerialize(xJson, inAllocator, inValue.w); rapidjson::Value yJson; - JsonSerializer::JsonSerialize(yJson, inAllocator, inValue.y); + JsonSerializer::JsonSerialize(yJson, inAllocator, inValue.x); rapidjson::Value zJson; - JsonSerializer::JsonSerialize(zJson, inAllocator, inValue.z); + JsonSerializer::JsonSerialize(zJson, inAllocator, inValue.y); rapidjson::Value wJson; - JsonSerializer::JsonSerialize(wJson, inAllocator, inValue.w); + JsonSerializer::JsonSerialize(wJson, inAllocator, inValue.z); outJsonValue.SetArray(); outJsonValue.PushBack(xJson, inAllocator); @@ -261,10 +263,10 @@ namespace Common { if (!inJsonValue.IsArray() || inJsonValue.Size() != 4) { return; } - JsonSerializer::JsonDeserialize(inJsonValue[0], outValue.x); - JsonSerializer::JsonDeserialize(inJsonValue[1], outValue.y); - JsonSerializer::JsonDeserialize(inJsonValue[2], outValue.z); - JsonSerializer::JsonDeserialize(inJsonValue[3], outValue.w); + JsonSerializer::JsonDeserialize(inJsonValue[0], outValue.w); + JsonSerializer::JsonDeserialize(inJsonValue[1], outValue.x); + JsonSerializer::JsonDeserialize(inJsonValue[2], outValue.y); + JsonSerializer::JsonDeserialize(inJsonValue[3], outValue.z); } }; } @@ -305,6 +307,12 @@ namespace Common { return *this; } + template + bool Angle::operator==(const Angle& inRhs) const + { + return CompareNumber(this->value, inRhs.value); + } + template T Angle::ToRadian() const { @@ -346,6 +354,12 @@ namespace Common { return *this; } + template + bool Radian::operator==(const Radian& inRhs) const + { + return CompareNumber(this->value, inRhs.value); + } + template T Radian::ToAngle() const { diff --git a/Engine/Source/Common/Include/Common/Math/Rect.h b/Engine/Source/Common/Include/Common/Math/Rect.h index cf5575dd..723859b5 100644 --- a/Engine/Source/Common/Include/Common/Math/Rect.h +++ b/Engine/Source/Common/Include/Common/Math/Rect.h @@ -75,9 +75,11 @@ namespace Common { static std::string ToString(const Rect& inValue) { return fmt::format( - "{min={}, max={}}", + "{}min={}, max={}{}", + "{", StringConverter>::ToString(inValue.min), - StringConverter>::ToString(inValue.max)); + StringConverter>::ToString(inValue.max), + "}"); } }; diff --git a/Engine/Source/Common/Include/Common/Math/Sphere.h b/Engine/Source/Common/Include/Common/Math/Sphere.h index 3f83f6ce..bdf106ed 100644 --- a/Engine/Source/Common/Include/Common/Math/Sphere.h +++ b/Engine/Source/Common/Include/Common/Math/Sphere.h @@ -63,9 +63,11 @@ namespace Common { static std::string ToString(const Sphere& inValue) { return fmt::format( - "{center={}, radius={}}", - StringConverter>::Convert(inValue.center), - StringConverter::Convert(inValue.radius)); + "{}center={}, radius={}{}", + "{", + StringConverter>::ToString(inValue.center), + StringConverter::ToString(inValue.radius), + "}"); } }; @@ -93,7 +95,7 @@ namespace Common { JsonSerializer>::JsonDeserialize(inJsonValue["center"], outValue.center); } if (inJsonValue.HasMember("radius")) { - JsonSerializer::JsonDeserialize(inJsonValue["radius", outValue.radius]); + JsonSerializer::JsonDeserialize(inJsonValue["radius"], outValue.radius); } } }; diff --git a/Engine/Source/Common/Include/Common/Math/Transform.h b/Engine/Source/Common/Include/Common/Math/Transform.h index ccdfc216..315095dd 100644 --- a/Engine/Source/Common/Include/Common/Math/Transform.h +++ b/Engine/Source/Common/Include/Common/Math/Transform.h @@ -93,10 +93,12 @@ namespace Common { static std::string ToString(const Transform& inValue) { return fmt::format( - "{scale={}, rotation={}, translation={}}", + "{}scale={}, rotation={}, translation={}{}", + "{", StringConverter>::ToString(inValue.scale), StringConverter>::ToString(inValue.rotation), - StringConverter>::ToString(inValue.translation)); + StringConverter>::ToString(inValue.translation), + "}"); } }; @@ -131,7 +133,7 @@ namespace Common { JsonSerializer>::JsonDeserialize(inJsonValue["rotation"], outValue.rotation); } if (inJsonValue.HasMember("translation")) { - JsonSerializer>::JsonDeserialize(inJsonValue["translation"], outValue.scale); + JsonSerializer>::JsonDeserialize(inJsonValue["translation"], outValue.translation); } } }; diff --git a/Engine/Source/Common/Include/Common/Math/Vector.h b/Engine/Source/Common/Include/Common/Math/Vector.h index 972a90f7..60f94a58 100644 --- a/Engine/Source/Common/Include/Common/Math/Vector.h +++ b/Engine/Source/Common/Include/Common/Math/Vector.h @@ -247,7 +247,7 @@ namespace Common { std::stringstream stream; stream << "("; for (auto i = 0; i < L; i++) { - stream << inValue.data[i]; + stream << StringConverter::ToString(inValue.data[i]); if (i != L - 1) { stream << ", "; } diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index c18c8045..746259ba 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -321,8 +321,12 @@ namespace Common { } bytes.resize(newPointer); } - // TODO endian swap - memcpy(bytes.data() + pointer, data, size); + 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()); + } pointer = newPointer; } @@ -360,8 +364,10 @@ namespace Common { { const auto newPointer = pointer + size; Assert(newPointer <= bytes.size()); - // TODO endian swap memcpy(data, bytes.data() + pointer, size); + if (std::endian::native != E) { + Internal::SwapEndianInplace(data, size); + } pointer = newPointer; } @@ -1072,7 +1078,7 @@ namespace Common { struct JsonSerializer { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::string& inValue) { - outJsonValue.SetString(inValue.c_str(), inValue.length()); + outJsonValue.SetString(inValue.c_str(), inValue.length(), inAllocator); } static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::string& outValue) @@ -1089,9 +1095,7 @@ namespace Common { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::wstring& inValue) { const auto str = StringUtils::ToByteString(inValue); - auto* memory = static_cast(inAllocator.Malloc(str.length())); - memcpy(memory, str.c_str(), str.length()); - outJsonValue.SetString(memory, str.length()); + outJsonValue.SetString(str.c_str(), str.length(), inAllocator); } static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::wstring& outValue) @@ -1364,13 +1368,14 @@ namespace Common { { std::initializer_list { ([&]() -> void { const auto key = std::to_string(I); - auto* keyMemory = static_cast(inAllocator.Malloc(key.length())); - memcpy(keyMemory, key.data(), key.length()); - rapidjson::Value jsonElement; - JsonSerializer::JsonSerialize(jsonElement, inAllocator, std::get(inValue)); + rapidjson::Value jsonKey; + JsonSerializer::JsonSerialize(jsonKey, inAllocator, key); + + rapidjson::Value jsonValue; + JsonSerializer::JsonSerialize(jsonValue, inAllocator, std::get(inValue)); - outJsonValue.AddMember(rapidjson::StringRef(keyMemory, key.length()), jsonElement, inAllocator); + outJsonValue.AddMember(jsonKey, jsonValue, inAllocator); }(), 0)... }; } diff --git a/Engine/Source/Common/Test/MathTest.cpp b/Engine/Source/Common/Test/MathTest.cpp index 1551bbfa..bc571298 100644 --- a/Engine/Source/Common/Test/MathTest.cpp +++ b/Engine/Source/Common/Test/MathTest.cpp @@ -626,10 +626,14 @@ TEST(MathTest, SerializationTest) // mat PerformTypedSerializationTest(FMat1x1(1.0f)); - PerformTypedSerializationTest(HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 5.0f, 7.0f)); + PerformTypedSerializationTest(HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f)); PerformTypedSerializationTest(IMat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); PerformTypedSerializationTest(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)); + // angle/radian + PerformTypedSerializationTest(FAngle(67.0f)); + PerformTypedSerializationTest(FRadian(1.5f * pi)); + // quaternion PerformTypedSerializationTest(FQuat(1.0f, 0.1f, 0.2f, 0.5f)); PerformTypedSerializationTest(DQuat(1.0f, 0.1f, 0.2f, 0.5f)); @@ -656,15 +660,209 @@ TEST(MathTest, SerializationTest) // projection PerformTypedSerializationTest(FReversedZOrthoProjection(512.0f, 1024.0f, 1.0f)); - PerformTypedSerializationTest(FReversedZPerspectiveProjection(512.0f, 1024.0f, 1.0f, 500.0f)); + PerformTypedSerializationTest(FReversedZPerspectiveProjection(90.0f, 512.0f, 1024.0f, 1.0f, 500.0f)); } TEST(MathTest, ToStringTest) { - // TODO + // half + ASSERT_EQ(ToString(HFloat(1.0f)), std::to_string(1.0f)); + + // vec + ASSERT_EQ(ToString(UVec4(1, 2, 3, 4)), "(1, 2, 3, 4)"); + + // mat + ASSERT_EQ( + ToString(HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f)), + fmt::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(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::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, "}")); + ASSERT_EQ( + ToString(LinearColor(1.0f, 0.5f, 0.2f, 1.0f)), + fmt::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), + "}")); + + // react + ASSERT_EQ( + ToString(FRect(1.0f, 2.0f, 3.0f, 4.0f)), + fmt::format("{}min=({}, {}), max=({}, {}){}", + "{", + std::to_string(1.0f), std::to_string(2.0f), + std::to_string(3.0f), std::to_string(4.0f), + "}")); + + // box + ASSERT_EQ( + ToString(FBox(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f)), + fmt::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), + "}")); + + // sphere + ASSERT_EQ( + ToString(FSphere(1.0f, 2.0f, 3.0f, 1.0f)), + fmt::format("{}center=({}, {}, {}), radius={}{}", + "{", + std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(1.0f), + "}")); + + // 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::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), + std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), + "}")); + + // 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::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), + std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), + "}")); + + // projection + ASSERT_EQ( + ToString(FReversedZOrthoProjection(1024.0f, 768.0f, 1.0f, 500.0f)), + fmt::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::to_string(90.0f), std::to_string(1024.0f), std::to_string(768.0f), std::to_string(1.0f), std::to_string(500.0f), + "}")); } TEST(MathTest, JsonSerializationTest) { - // TODO + // half + 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(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( + 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))); + 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("[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]", + 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), + FltToJson(13.0f), FltToJson(14.0f), FltToJson(15.0f), FltToJson(16.0f))); + + // angle/radian + PerformJsonSerializationTest(FAngle(67.0f), FltToJson(67.0f)); + 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))); + + // 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":{}{})", + "{", + FltToJson(1.0f), FltToJson(0.5f), FltToJson(0.2f), FltToJson(1.0f), + "}")); + + // rect + PerformJsonSerializationTest( + FRect(1.0f, 2.0f, 3.0f, 4.0f), + fmt::format(R"({}"min":[{},{}],"max":[{},{}]{})", + "{", + FltToJson(1.0f), FltToJson(2.0f), + FltToJson(3.0f), FltToJson(4.0f), + "}")); + + // box + PerformJsonSerializationTest( + FBox(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f), + fmt::format(R"({}"min":[{},{},{}],"max":[{},{},{}]{})", + "{", + FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), + FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), + "}")); + + // sphere + PerformJsonSerializationTest( + FSphere(1.0f, 2.0f, 3.0f, 1.0f), + fmt::format(R"({}"center":[{},{},{}],"radius":{}{})", + "{", + FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), + FltToJson(1.0f), + "}")); + + // transform + 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":[{},{},{}]{})", + "{", + FltToJson(2.0f), FltToJson(2.0f), FltToJson(2.0f), + FltToJson(1.0f), FltToJson(0.2f), FltToJson(0.3f), FltToJson(0.4f), + FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), + "}")); + + // view transform + PerformJsonSerializationTest( + FViewTransform(transform), + fmt::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), + FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), + "}")); + + // projection + PerformJsonSerializationTest( + FReversedZOrthoProjection(512.0f, 1024.0f, 1.0f), + fmt::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":{}{})", + "{", + 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 0dde1e09..55f9d019 100644 --- a/Engine/Source/Common/Test/SerializationTest.cpp +++ b/Engine/Source/Common/Test/SerializationTest.cpp @@ -109,5 +109,6 @@ TEST(SerializationTest, JsonSerializeTest) PerformJsonSerializationTest>({ 1, 2, 3 }, "[1,2,3]"); PerformJsonSerializationTest>({ { 1, false }, { 2, true } }, ""); PerformJsonSerializationTest>({ { 1, false }, { 2, true } }, R"([{"key":1,"value":false},{"key":2,"value":true}])"); + PerformJsonSerializationTest>({ { "1", 1 }, { "2", 2 } }, R"([{"key":"1","value":1},{"key":"2","value":2}])"); PerformJsonSerializationTest>({ 1, true, 2 }, R"({"0":1,"1":true,"2":2})"); } diff --git a/Engine/Source/Common/Test/SerializationTest.h b/Engine/Source/Common/Test/SerializationTest.h index e1b3780b..b0eca051 100644 --- a/Engine/Source/Common/Test/SerializationTest.h +++ b/Engine/Source/Common/Test/SerializationTest.h @@ -10,27 +10,57 @@ #include #include +#include -template -void PerformTypedSerializationTestWithEndian(const T& inValue) +inline std::string FltToJson(float value) { - static std::filesystem::path fileName = "../Test/Generated/Common/SerializationTest.TypedSerializationTest"; - std::filesystem::create_directories(fileName.parent_path()); + rapidjson::Document document; + document.SetFloat(value); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + return std::string(buffer.GetString(), buffer.GetSize()); // NOLINT +} + +template +void PerformTypedSerializationTestWithStream( + const std::function()>& createSerializeStream, + const std::function()>& createDeserializeStream, + const T& inValue) +{ { - Common::BinaryFileSerializeStream stream(fileName.string()); - Common::Serialize(stream, inValue); + const auto stream = createSerializeStream(); + Common::Serialize(*stream, inValue); } { T value; - Common::BinaryFileDeserializeStream stream(fileName.string()); - Common::Deserialize(stream, value); + const auto stream = createDeserializeStream(); + Common::Deserialize(*stream, value); ASSERT_EQ(inValue, value); } } +template +void PerformTypedSerializationTestWithEndian(const T& inValue) +{ + static std::filesystem::path fileName = "../Test/Generated/Common/SerializationTest.TypedSerializationTest"; + std::filesystem::create_directories(fileName.parent_path()); + + PerformTypedSerializationTestWithStream( + []() -> Common::UniqueRef { return { new BinaryFileSerializeStream(fileName.string()) }; }, + []() -> Common::UniqueRef { return { new BinaryFileDeserializeStream(fileName.string()) }; }, + inValue); + + std::vector buffer; + PerformTypedSerializationTestWithStream( + [&]() -> Common::UniqueRef { return { new MemorySerializeStream(buffer) }; }, + [&]() -> Common::UniqueRef { return { new MemoryDeserializeStream(buffer) }; }, + inValue); +} + template void PerformTypedSerializationTest(const T& inValue) { diff --git a/Engine/Source/Core/Src/Module.cpp b/Engine/Source/Core/Src/Module.cpp index 4bd0d545..dee1a5e1 100644 --- a/Engine/Source/Core/Src/Module.cpp +++ b/Engine/Source/Core/Src/Module.cpp @@ -156,9 +156,7 @@ namespace Core { return path.string(); } } - } catch (const std::exception&) { // NOLINT - // TODO maybe output log here - } + } catch (const std::exception&) {} // NOLINT } return {}; } diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 72c2cbe3..2309a8c5 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ namespace Mirror { const uint32_t copyAssignable : 1; const uint32_t moveConstructible : 1; const uint32_t moveAssignable : 1; + const uint32_t equalComparable : 1; }; template const TypeInfo* GetTypeInfo(); @@ -306,6 +308,8 @@ namespace Mirror { const TypeInfo* RemovePointerType() const; private: + template decltype(auto) Delegate(F&& inFunc) const; + std::variant any; }; @@ -843,8 +847,10 @@ namespace Common { // NOLINT stream.Seek(static_cast(sizeof(uint64_t) * (memberVariableCount + 1))); uint64_t memberVariableContentSize = 0; - for (const auto& [id, memberVariable] : memberVariables) { - const bool sameAsDefaultObject = defaultObject.Empty() ? false : memberVariable.GetDyn(obj) == memberVariable.GetDyn(defaultObject); + for (const auto& memberVariable : memberVariables | std::views::values) { + const bool sameAsDefaultObject = defaultObject.Empty() || !memberVariable.GetTypeInfo()->equalComparable + ? false + : memberVariable.GetDyn(obj) == memberVariable.GetDyn(defaultObject); memberVariableContentSize += Serializer::Serialize(stream, memberVariable.GetName()); memberVariableContentSize += Serializer::Serialize(stream, sameAsDefaultObject); @@ -867,11 +873,13 @@ namespace Common { // NOLINT { const auto& className = clazz.GetName(); const auto* baseClass = clazz.GetBaseClass(); - const auto& memberVariables = clazz.GetMemberVariables(); const auto defaultObject = clazz.GetDefaultObject(); std::string name; const auto nameSize = Serializer::Deserialize(stream, name); + if (name != className) { + return nameSize; + } uint64_t aspectBaseClassContentSize = 0; Serializer::Deserialize(stream, aspectBaseClassContentSize); @@ -905,7 +913,7 @@ namespace Common { // NOLINT memberVariableContentCur += Serializer::Deserialize(stream, sameAsDefaultObject); if (sameAsDefaultObject) { if (!defaultObject.Empty()) { - memberVariable.SetDyn(obj, memberVariable.GetDyn(obj)); + memberVariable.SetDyn(obj, memberVariable.GetDyn(defaultObject)); } continue; } @@ -928,6 +936,76 @@ namespace Common { // NOLINT } }; + template + 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); + + rapidjson::Value baseClassJson; + if (baseClass != nullptr) { + JsonSerializeDyn(baseClassJson, inAllocator, *baseClass, inObj); + } else { + baseClassJson.SetNull(); + } + + rapidjson::Value membersJson; + membersJson.SetArray(); + membersJson.Reserve(memberVariables.size(), inAllocator); + for (const auto& member : memberVariables | std::views::values) { + rapidjson::Value memberNameJson; + JsonSerializer::JsonSerialize(memberNameJson, inAllocator, member.GetName()); + + bool sameAsDefault = defaultObject.Empty() || !member.GetTypeInfo()->equalComparable + ? false + : member.GetDyn(inObj) == member.GetDyn(defaultObject); + + rapidjson::Value memberSameAsDefaultJson; + JsonSerializer::JsonSerialize(memberSameAsDefaultJson, inAllocator, sameAsDefault); + + rapidjson::Value memberContentJson; + if (sameAsDefault) { + memberContentJson.SetNull(); + } else { + member.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); + } + + rapidjson::Value memberJson; + memberJson.SetObject(); + memberJson.AddMember("memberName", memberNameJson, inAllocator); + memberJson.AddMember("sameAsDefault", memberSameAsDefaultJson, inAllocator); + memberJson.AddMember("content", memberContentJson, inAllocator); + membersJson.PushBack(memberJson, 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& outValue) + { + // TODO + } + + static void JsonSerialize(rapidjson::Value& outValue, rapidjson::Document::AllocatorType& inAllocator, const T& inValue) + { + JsonSerializeDyn(outValue, inAllocator, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(inValue)); + } + + static void JsonDeserialize(const rapidjson::Value& inValue, T& outValue) + { + JsonDeserializeDyn(inValue, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(outValue)); + } + }; + template struct StringConverter { static std::string ToStringDyn(const Mirror::Class& clazz, const Mirror::Argument& argument) @@ -953,9 +1031,7 @@ namespace Common { // NOLINT } }; - // TODO meta object to json - - // TODO Mirror::Any serialization serialization/tostring/tojson + // TODO meta enum serialization/tostring/tojson // TODO Type class serialization/tostring/tojson } @@ -970,22 +1046,23 @@ namespace Mirror { typeid(T).name(), typeid(T).hash_code(), typeid(std::remove_pointer_t).hash_code(), - std::is_const_v, - std::is_lvalue_reference_v, - std::is_lvalue_reference_v ? std::is_const_v> : false, - std::is_rvalue_reference_v, - std::is_pointer_v, - std::is_pointer_v ? std::is_const_v> : false, - std::is_class_v, - std::is_enum_v, - std::is_array_v, - std::is_arithmetic_v, - std::is_integral_v, - std::is_floating_point_v, - std::is_copy_constructible_v, - std::is_copy_assignable_v, - std::is_move_constructible_v, - std::is_move_assignable_v, + Common::CppConst, + Common::CppLValueRef, + Common::CppLValueConstRef, + Common::CppRValueRef, + Common::CppPointer, + Common::CppConstPointer, + Common::CppClass, + Common::CppEnum, + Common::CppArray, + Common::CppArithmetic, + Common::CppIntegral, + Common::CppFloatingPoint, + Common::CppCopyConstructible, + Common::CppCopyAssignable, + Common::CppMoveConstructible, + Common::CppMoveAssignable, + Common::EqualComparable }; return &typeInfo; } @@ -1261,19 +1338,27 @@ namespace Mirror { template T Argument::As() const // NOLINT + { + return Delegate([](auto&& value) -> decltype(auto) { + return value.template As(); + }); + } + + template + decltype(auto) Argument::Delegate(F&& inFunc) const { const auto index = any.index(); if (index == 1) { - return std::get(any)->As(); + return inFunc(*std::get(any)); } if (index == 2) { - return std::get(any)->As(); + return inFunc(*std::get(any)); } if (index == 3) { - return const_cast(std::get(any)).As(); + return inFunc(const_cast(std::get(any))); } QuickFailWithReason("Argument is empty"); - return std::get(any)->As(); + return inFunc(Any {}); } template diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 029284af..8bc166f2 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -551,130 +551,58 @@ namespace Mirror { bool Argument::IsMemoryHolder() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->IsMemoryHolder(); - } - if (index == 2) { - return std::get(any)->IsMemoryHolder(); - } - if (index == 3) { - return const_cast(std::get(any)).IsMemoryHolder(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->IsMemoryHolder(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.IsMemoryHolder(); + }); } bool Argument::IsRef() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->IsRef(); - } - if (index == 2) { - return std::get(any)->IsRef(); - } - if (index == 3) { - return const_cast(std::get(any)).IsRef(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->IsRef(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.IsRef(); + }); } bool Argument::IsNonConstRef() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->IsNonConstRef(); - } - if (index == 2) { - return std::get(any)->IsNonConstRef(); - } - if (index == 3) { - return const_cast(std::get(any)).IsNonConstRef(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->IsNonConstRef(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.IsNonConstRef(); + }); } bool Argument::IsConstRef() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->IsConstRef(); - } - if (index == 2) { - return std::get(any)->IsConstRef(); - } - if (index == 3) { - return const_cast(std::get(any)).IsConstRef(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->IsConstRef(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.IsConstRef(); + }); } const TypeInfo* Argument::Type() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->Type(); - } - if (index == 2) { - return std::get(any)->Type(); - } - if (index == 3) { - return const_cast(std::get(any)).Type(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->Type(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.Type(); + }); } const TypeInfo* Argument::RemoveRefType() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->RemoveRefType(); - } - if (index == 2) { - return std::get(any)->RemoveRefType(); - } - if (index == 3) { - return const_cast(std::get(any)).RemoveRefType(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->RemoveRefType(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.RemoveRefType(); + }); } const TypeInfo* Argument::AddPointerType() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->AddPointerType(); - } - if (index == 2) { - return std::get(any)->AddPointerType(); - } - if (index == 3) { - return const_cast(std::get(any)).AddPointerType(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->AddPointerType(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.AddPointerType(); + }); } const TypeInfo* Argument::RemovePointerType() const { - const auto index = any.index(); - if (index == 1) { - return std::get(any)->RemovePointerType(); - } - if (index == 2) { - return std::get(any)->RemovePointerType(); - } - if (index == 3) { - return const_cast(std::get(any)).RemovePointerType(); - } - QuickFailWithReason("Argument is empty"); - return std::get(any)->RemovePointerType(); + return Delegate([](auto&& value) -> decltype(auto) { + return value.RemovePointerType(); + }); } Id::Id() From f6f3621852cc929168f0cb3e8acd44888137011e Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Fri, 27 Sep 2024 18:53:42 +0800 Subject: [PATCH 4/7] feat: support poly as and array in Mirror::Any --- .../Source/Common/Include/Common/Concepts.h | 4 + Engine/Source/Mirror/Include/Mirror/Mirror.h | 453 ++++++++++++++++-- .../Source/Mirror/Include/Mirror/Registry.h | 16 +- Engine/Source/Mirror/Src/Mirror.cpp | 249 ++++++++-- Engine/Source/Mirror/Test/AnyTest.cpp | 102 +++- Engine/Source/Mirror/Test/AnyTest.h | 30 ++ Engine/Source/Mirror/Test/RegistryTest.cpp | 28 +- .../Source/Mirror/Test/SerializationTest.cpp | 120 ++--- Engine/Source/Mirror/Test/SerializationTest.h | 21 +- Tool/MirrorTool/Src/Generator.cpp | 2 +- 10 files changed, 846 insertions(+), 179 deletions(-) diff --git a/Engine/Source/Common/Include/Common/Concepts.h b/Engine/Source/Common/Include/Common/Concepts.h index 77b8e718..688065c2 100644 --- a/Engine/Source/Common/Include/Common/Concepts.h +++ b/Engine/Source/Common/Include/Common/Concepts.h @@ -28,6 +28,7 @@ namespace Common { template concept CppUnsigned = std::is_unsigned_v; template concept CppArithmetic = std::is_arithmetic_v; template concept CppArithmeticNonBool = CppArithmetic && !CppBool; + template concept CppFundamental = std::is_fundamental_v; template concept CppClass = std::is_class_v; template concept CppVoid = std::is_void_v; template concept CppUnion = std::is_union_v; @@ -39,10 +40,13 @@ namespace Common { template concept CppPointer = std::is_pointer_v; template concept CppConstPointer = CppPointer && CppConst>; template concept CppRef = std::is_reference_v; + template concept CppNotRef = !std::is_reference_v; template concept CppLValueRef = std::is_lvalue_reference_v; template concept CppLValueConstRef = CppLValueRef && CppConst>; template concept CppRValueRef = std::is_rvalue_reference_v; + template concept CppLValueRefOrPtr = CppLValueRef || CppPointer; template concept CppVolatile = std::is_volatile_v; + template concept CppPolymorphic = std::is_polymorphic_v; template concept CppCopyConstructible = std::is_copy_constructible_v; template concept CppMoveConstructible = std::is_move_constructible_v; template concept CppCopyAssignable = std::is_copy_assignable_v; diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 2309a8c5..386ac5b2 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -140,7 +140,7 @@ namespace Mirror { ToStringFunc* toString; }; - template + template static constexpr AnyRtti anyRttiImpl = { &AnyRtti::Detor, &AnyRtti::CopyConstruct, @@ -170,12 +170,18 @@ namespace Mirror { Any(Any& inOther); Any(const Any& inOther); Any(const Any& inOther, AnyPolicy inPolicy); + Any(const Any& inOther, AnyPolicy inPolicy, uint32_t inIndex); Any(Any&& inOther) noexcept; template Any(T&& inValue); // NOLINT template Any(std::reference_wrapper& inRef); // NOLINT template Any(std::reference_wrapper&& inRef); // NOLINT template Any(const std::reference_wrapper& inRef); // NOLINT + template Any(T (&inArray)[N]); // NOLINT + template Any(T (&&inArray)[N]); // NOLINT + template Any(std::reference_wrapper& inArrayRef); // NOLINT + template Any(std::reference_wrapper&& inArrayRef); // NOLINT + template Any(const std::reference_wrapper& inArrayRef); // NOLINT Any& operator=(const Any& inOther); Any& operator=(Any&& inOther) noexcept; @@ -184,29 +190,36 @@ namespace Mirror { template Any& operator=(std::reference_wrapper& inRef); template Any& operator=(std::reference_wrapper&& inRef); template Any& operator=(const std::reference_wrapper& inRef); + template Any& operator=(T (&inArray)[N]); // NOLINT + template Any& operator=(T (&&inArray)[N]); // NOLINT + template Any& operator=(std::reference_wrapper& inArrayRef); // NOLINT + template Any& operator=(std::reference_wrapper&& inArrayRef); // NOLINT + template Any& operator=(const std::reference_wrapper& inArrayRef); // NOLINT template bool Convertible(); template bool Convertible() const; template T As(); template T As() const; - template T* TryAs(); - template T* TryAs() const; - - // TODO - // template T PolyAs() const; + template T* TryAs(); + template T* TryAs() const; + template T PolyAs(); + template T PolyAs() const; - // TODO array support + bool IsArray() const; + Any At(uint32_t inIndex); + Any At(uint32_t inIndex) const; + size_t ElementSize() const; + uint32_t ArrayLength() const; Any Ref(); Any Ref() const; Any ConstRef() const; - Any AsValue() const; + Any Value() const; Any Ptr(); Any Ptr() const; Any ConstPtr() const; Any Deref() const; - AnyPolicy Policy() const; bool IsMemoryHolder() const; bool IsRef() const; @@ -231,13 +244,13 @@ namespace Mirror { void JsonDeserialize(const rapidjson::Value& inJsonValue); void JsonDeserialize(const rapidjson::Value& inJsonValue) const; std::string ToString() const; - - // always return original ptr and size, even policy is a reference - void* Data() const; - size_t Size() const; - + void* Data(uint32_t inIndex = 0) const; + size_t MemorySize() const; explicit operator bool() const; + Any operator[](uint32_t inIndex); + Any operator[](uint32_t inIndex) const; bool operator==(const Any& inAny) const; + bool operator!=(const Any& inAny) const; private: class MIRROR_API HolderInfo { @@ -273,11 +286,17 @@ namespace Mirror { template void ConstructFromValue(T&& inValue); template void ConstructFromRef(std::reference_wrapper inRef); + 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); + uint32_t ElementNum() const; + uint32_t arrayLength; AnyPolicy policy; const AnyRtti* rtti; std::variant info; @@ -698,9 +717,21 @@ namespace Mirror { std::unordered_map memberFunctions; }; - class MIRROR_API EnumElement final : public Type { + class MIRROR_API EnumValue final : public Type { public: - ~EnumElement() override; + using IntegralValue = int64_t; + + ~EnumValue() override; + + Any Get() const; + IntegralValue GetIntegral() const; + template void Set(E& value) const; + template bool Compare(const E& value) const; + + Any GetDyn() const; + IntegralValue GetIntegralDyn() const; + void SetDyn(const Argument& arg) const; + bool CompareDyn(const Argument& arg) const; private: friend class Registry; @@ -709,40 +740,51 @@ namespace Mirror { friend class Enum; - Any Get() const; - bool Compare(const Argument& argument) const; - using Getter = std::function; + using IntegralGetter = std::function; + using Setter = std::function; using Comparer = std::function; struct ConstructParams { std::string name; Getter getter; + IntegralGetter integralGetter; + Setter setter; Comparer comparer; }; - explicit EnumElement(ConstructParams&& inParams); + explicit EnumValue(ConstructParams&& inParams); Getter getter; + IntegralGetter integralGetter; + Setter setter; Comparer comparer; }; class MIRROR_API Enum final : public Type { public: - template - static const Enum* Find(); - - template - static const Enum& Get(); - + template static const Enum* Find(); + template static const Enum& Get(); static const Enum* Find(const Id& inId); static const Enum& Get(const Id& inId); ~Enum() override; const TypeInfo* GetTypeInfo() const; - Any GetElement(const Id& inId) const; - std::string GetElementName(const Argument& argument) const; + bool HasValue(const Id& inId) const; + const EnumValue* FindValue(const Id& inId) const; + const EnumValue& GetValue(const Id& inId) const; + bool HasValue(EnumValue::IntegralValue inValue) const; + const EnumValue* FindValue(EnumValue::IntegralValue inValue) const; + const EnumValue& GetValue(EnumValue::IntegralValue inValue) const; + template bool HasValue(E inValue) const; + template const EnumValue* FindValue(E inValue) const; + template const EnumValue& GetValue(E inValue) const; + bool HasValue(const Argument& inArg) const; + const EnumValue* FindValue(const Argument& inArg) const; + const EnumValue& GetValue(const Argument& inArg) const; + const std::unordered_map& GetValues() const; + std::vector GetSortedValues() const; private: static std::unordered_map typeToIdMap; @@ -757,10 +799,10 @@ namespace Mirror { explicit Enum(ConstructParams&& params); - EnumElement& EmplaceElement(const Id& inId, EnumElement::ConstructParams&& inParams); + EnumValue& EmplaceElement(const Id& inId, EnumValue::ConstructParams&& inParams); const TypeInfo* typeInfo; - std::unordered_map elements; + std::unordered_map values; }; template concept MetaClass = requires(T inValue) { { T::GetClass() } -> std::same_as; }; @@ -936,6 +978,58 @@ namespace Common { // NOLINT } }; + template + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("_MetaEnum"); + + static size_t Serialize(BinarySerializeStream& stream, const E& value) + { + size_t serialized = 0; + const Mirror::Enum* metaEnum = Mirror::Enum::Find(); + serialized += Serializer::Serialize(stream, metaEnum != nullptr); + + if (metaEnum == nullptr) { + serialized += Serializer>::Serialize(stream, static_cast>(value)); + } else { + const Mirror::EnumValue& metaEnumValue = metaEnum->GetValue(value); + serialized += Serializer::Serialize(stream, metaEnum->GetName()); + serialized += Serializer::Serialize(stream, metaEnumValue.GetName()); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, E& value) + { + size_t deserialized = 0; + bool isMetaEnum = false; + deserialized += Serializer::Deserialize(stream, isMetaEnum); + + if (isMetaEnum) { + std::string metaEnumName; + std::string metaEnumValueName; + deserialized += Serializer::Deserialize(stream, metaEnumName); + deserialized += Serializer::Deserialize(stream, metaEnumValueName); + + const Mirror::Enum* aspectMetaEnum = Mirror::Enum::Find(metaEnumName); + const Mirror::Enum* metaEnum = Mirror::Enum::Find(); + if (aspectMetaEnum != metaEnum || metaEnum == nullptr) { + return deserialized; + } + + const auto* metaEnumValue = metaEnum->FindValue(metaEnumValueName); + if (metaEnumValue == nullptr) { + return deserialized; + } + metaEnumValue->Set(value); + } else { + std::underlying_type_t unlderlyingValue; + deserialized += Serializer>::Deserialize(stream, unlderlyingValue); + value = static_cast(unlderlyingValue); + } + return deserialized; + } + }; + template struct JsonSerializer { static void JsonSerializeDyn(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Class& clazz, const Mirror::Argument& inObj) @@ -990,9 +1084,67 @@ namespace Common { // NOLINT outJsonValue.AddMember("members", membersJson, inAllocator); } - static void JsonDeserializeDyn(const rapidjson::Value& inJsonValue, const Mirror::Class& clazz, const Mirror::Argument& outValue) + static void JsonDeserializeDyn(const rapidjson::Value& inJsonValue, const Mirror::Class& clazz, const Mirror::Argument& outObj) { - // TODO + const auto& className = clazz.GetName(); + const auto* baseClass = clazz.GetBaseClass(); + const auto defaultObject = clazz.GetDefaultObject(); + + if (!inJsonValue.IsObject()) { + 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.IsArray()) { + return; + } + + for (rapidjson::SizeType i = 0; i < membersJson.Size(); i++) { + const auto& memberJson = membersJson[i]; + if (!memberJson.HasMember("memberName")) { + continue; + } + + std::string memberName; + JsonSerializer::JsonDeserialize(memberJson["memberName"], memberName); + if (!clazz.HasMemberVariable(memberName)) { + continue; + } + const auto& memberVariable = clazz.GetMemberVariable(memberName); + + bool sameAsDefault = false; + if (memberJson.HasMember("sameAsDefault")) { + JsonSerializer::JsonDeserialize(memberJson["sameAsDefault"], sameAsDefault); + } + if (sameAsDefault) { + if (!defaultObject.Empty()) { + memberVariable.SetDyn(outObj, memberVariable.GetDyn(defaultObject)); + } + continue; + } + + if (!memberJson.HasMember("content")) { + continue; + } + memberVariable.GetDyn(outObj).JsonDeserialize(memberJson["content"]); + } } static void JsonSerialize(rapidjson::Value& outValue, rapidjson::Document::AllocatorType& inAllocator, const T& inValue) @@ -1006,6 +1158,59 @@ namespace Common { // NOLINT } }; + template + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outValue, rapidjson::Document::AllocatorType& inAllocator, const E& inValue) + { + if (const Mirror::Enum* metaEnum = Mirror::Enum::Find(); + metaEnum == nullptr) { + JsonSerializer>::JsonSerialize(outValue, inAllocator, static_cast>(inValue)); + } else { + const Mirror::EnumValue& metaEnumValue = metaEnum->GetValue(inValue); + + rapidjson::Value enumNameJson; + JsonSerializer::JsonSerialize(enumNameJson, inAllocator, metaEnum->GetName()); + + rapidjson::Value valueNameJson; + JsonSerializer::JsonSerialize(valueNameJson, inAllocator, metaEnumValue.GetName()); + + outValue.SetArray(); + outValue.PushBack(enumNameJson, inAllocator); + outValue.PushBack(valueNameJson, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inValue, E& outValue) + { + if (inValue.IsArray()) { + if (inValue.Size() != 2) { + return; + } + + std::string metaEnumName; + std::string metaEnumValueName; + JsonSerializer::JsonDeserialize(inValue[0], metaEnumName); + JsonSerializer::JsonDeserialize(inValue[1], metaEnumValueName); + + const Mirror::Enum* aspectMetaEnum = Mirror::Enum::Find(metaEnumName); + const Mirror::Enum* metaEnum = Mirror::Enum::Find(); + if (aspectMetaEnum != metaEnum || metaEnum == nullptr) { + return; + } + + const auto* metaEnumValue = metaEnum->FindValue(metaEnumValueName); + if (metaEnumValue == nullptr) { + return; + } + metaEnumValue->Set(outValue); + } else { + std::underlying_type_t unlderlyingValue; + JsonSerializer>::JsonDeserialize(inValue, unlderlyingValue); + outValue = static_cast(unlderlyingValue); + } + } + }; + template struct StringConverter { static std::string ToStringDyn(const Mirror::Class& clazz, const Mirror::Argument& argument) @@ -1031,7 +1236,22 @@ namespace Common { // NOLINT } }; - // TODO meta enum serialization/tostring/tojson + template + struct StringConverter { + static std::string ToString(const E& inValue) + { + if (const Mirror::Enum* metaEnum = Mirror::Enum::Find(); + metaEnum != nullptr) { + return fmt::format( + "{}::{}", + StringConverter::ToString(metaEnum->GetName()), + StringConverter::ToString(metaEnum->GetValue(inValue).GetName())); + } else { + return StringConverter>::ToString(static_cast>(inValue)); + } + } + }; + // TODO Type class serialization/tostring/tojson } @@ -1233,6 +1453,36 @@ namespace Mirror { ConstructFromRef(inRef); } + template + Any::Any(T(& inArray)[N]) + { + ConstructFromArrayValue(inArray); + } + + template + Any::Any(T(&& inArray)[N]) + { + ConstructFromArrayValue(std::move(inArray)); + } + + template + Any::Any(std::reference_wrapper& inArrayRef) + { + ConstructFromArrayRef(inArrayRef); + } + + template + Any::Any(std::reference_wrapper&& inArrayRef) + { + ConstructFromArrayRef(inArrayRef); + } + + template + Any::Any(const std::reference_wrapper& inArrayRef) + { + ConstructFromArrayRef(inArrayRef); + } + template Any& Any::operator=(T&& inValue) { @@ -1265,9 +1515,50 @@ namespace Mirror { return *this; } + template + Any& Any::operator=(T(& inArray)[N]) + { + Reset(); + ConstructFromArrayValue(inArray); + return *this; + } + + template + Any& Any::operator=(T(&& inArray)[N]) + { + Reset(); + ConstructFromArrayValue(std::move(inArray)); + return *this; + } + + template + Any& Any::operator=(std::reference_wrapper& inArrayRef) + { + Reset(); + ConstructFromArrayRef(inArrayRef); + return *this; + } + + template + Any& Any::operator=(std::reference_wrapper&& inArrayRef) + { + Reset(); + ConstructFromArrayRef(inArrayRef); + return *this; + } + + template + Any& Any::operator=(const std::reference_wrapper& inArrayRef) + { + Reset(); + ConstructFromArrayRef(inArrayRef); + return *this; + } + template bool Any::Convertible() { + Assert(!IsArray()); return Mirror::Convertible( { Type(), RemoveRefType(), RemovePointerType() }, { GetTypeInfo(), GetTypeInfo>(), GetTypeInfo>() }); @@ -1276,6 +1567,7 @@ namespace Mirror { template bool Any::Convertible() const { + Assert(!IsArray()); return Mirror::Convertible( { Type(), RemoveRefType(), RemovePointerType() }, { GetTypeInfo(), GetTypeInfo>(), GetTypeInfo>() }); @@ -1295,31 +1587,46 @@ namespace Mirror { return *static_cast*>(Data()); } - template + template T* Any::TryAs() { - Assert(!std::is_reference_v); + Assert(!IsArray()); const bool convertible = Mirror::Convertible( { AddPointerType(), AddPointerType(), RemoveRefType() }, { GetTypeInfo(), GetTypeInfo(), GetTypeInfo() }); return convertible ? static_cast*>(Data()) : nullptr; } - template + template T* Any::TryAs() const { - Assert(!std::is_reference_v); + Assert(!IsArray()); const bool convertible = Mirror::Convertible( { AddPointerType(), AddPointerType(), RemoveRefType() }, { GetTypeInfo(), GetTypeInfo(), GetTypeInfo() }); return convertible ? static_cast*>(Data()) : nullptr; } + template + T Any::PolyAs() + { + Assert(!IsArray()); + return dynamic_cast(As()); + } + + template + T Any::PolyAs() const + { + Assert(!IsArray()); + return dynamic_cast(As()); + } + template void Any::ConstructFromValue(T&& inValue) { using RawType = std::remove_cvref_t; + arrayLength = 0; policy = AnyPolicy::memoryHolder; rtti = &anyRttiImpl; info = HolderInfo(sizeof(RawType)); @@ -1329,13 +1636,53 @@ namespace Mirror { template void Any::ConstructFromRef(std::reference_wrapper inRef) { - using RawType = std::remove_const_t; + using RawType = std::remove_cv_t; + arrayLength = 0; policy = std::is_const_v ? AnyPolicy::constRef : AnyPolicy::nonConstRef; rtti = &anyRttiImpl; info = RefInfo(const_cast(&inRef.get()), sizeof(RawType)); } + template + void Any::ConstructFromArrayValue(T(& inValue)[N]) + { + using RawType = std::remove_cv_t; + + arrayLength = N; + policy = AnyPolicy::memoryHolder; + rtti = &anyRttiImpl; + info = HolderInfo(sizeof(RawType) * N); + for (auto i = 0; i < N; i++) { + new(Data(i)) RawType(inValue[i]); + } + } + + template + void Any::ConstructFromArrayValue(T(&& inValue)[N]) + { + using RawType = std::remove_cv_t; + + arrayLength = N; + policy = AnyPolicy::memoryHolder; + rtti = &anyRttiImpl; + info = HolderInfo(sizeof(RawType) * N); + for (auto i = 0; i < N; i++) { + new(Data(i)) RawType(std::move(inValue[i])); + } + } + + template + void Any::ConstructFromArrayRef(std::reference_wrapper inRef) + { + using RawType = std::remove_cv_t; + + arrayLength = N; + policy = std::is_const_v ? AnyPolicy::constRef : AnyPolicy::nonConstRef; + rtti = &anyRttiImpl; + info = RefInfo(const_cast(&inRef.get()[0]), sizeof(RawType) * N); + } + template T Argument::As() const // NOLINT { @@ -1469,4 +1816,34 @@ namespace Mirror { Assert(iter != typeToIdMap.end()); return Get(iter->second); } + + template + void EnumValue::Set(E& value) const + { + SetDyn(Internal::ForwardAsArgument(value)); + } + + template + bool EnumValue::Compare(const E& value) const + { + return Compare(Internal::ForwardAsArgument(value)); + } + + template + bool Enum::HasValue(E inValue) const + { + return HasValue(Internal::ForwardAsArgument(inValue)); + } + + template + const EnumValue* Enum::FindValue(E inValue) const + { + return FindValue(Internal::ForwardAsArgument(inValue)); + } + + template + const EnumValue& Enum::GetValue(E inValue) const + { + return GetValue(Internal::ForwardAsArgument(inValue)); + } } diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 68414e21..34948afa 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -82,7 +82,7 @@ namespace Mirror { public: ~EnumRegistry() override; - template EnumRegistry& Element(const Id& inId); + template EnumRegistry& Value(const Id& inId); private: friend class Registry; @@ -442,16 +442,22 @@ namespace Mirror { template template - EnumRegistry& EnumRegistry::Element(const Id& inId) + EnumRegistry& EnumRegistry::Value(const Id& inId) { - const auto iter = enumInfo.elements.find(inId); - Assert(iter == enumInfo.elements.end()); + const auto iter = enumInfo.values.find(inId); + Assert(iter == enumInfo.values.end()); - EnumElement::ConstructParams params; + EnumValue::ConstructParams params; params.name = inId.name; params.getter = []() -> Any { return { Value }; }; + params.integralGetter = []() -> EnumValue::IntegralValue { + return static_cast(Value); + }; + params.setter = [](const Argument& value) -> void { + value.As() = Value; + }; params.comparer = [](const Argument& value) -> bool { return value.As() == Value; }; diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 8bc166f2..0d48d022 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -85,7 +85,9 @@ namespace Mirror { Any::~Any() { if (IsMemoryHolder() && rtti != nullptr) { - rtti->detor(Data()); + for (auto i = 0; i < ElementNum(); i++) { + rtti->detor(Data(i)); + } } } @@ -104,6 +106,11 @@ namespace Mirror { PerformCopyConstructWithPolicy(inOther, inPolicy); } + Any::Any(const Any& inOther, AnyPolicy inPolicy, uint32_t inIndex) + { + PerformCopyConstructForElementWithPolicy(inOther, inPolicy, inIndex); + } + Any::Any(Any&& inOther) noexcept { PerformMoveConstruct(std::move(inOther)); @@ -129,6 +136,7 @@ namespace Mirror { void Any::PerformCopyConstruct(const Any& inOther) { + arrayLength = inOther.arrayLength; policy = inOther.policy; rtti = inOther.rtti; info = inOther.info; @@ -139,12 +147,36 @@ namespace Mirror { } if (IsMemoryHolder()) { - rtti->copyConstruct(Data(), inOther.Data()); + for (auto i = 0; i < ElementNum(); i++) { + rtti->copyConstruct(Data(i), inOther.Data(i)); + } } } void Any::PerformCopyConstructWithPolicy(const Any& inOther, const AnyPolicy inPolicy) { + arrayLength = inOther.arrayLength; + policy = inPolicy; + rtti = inOther.rtti; + + if (Empty()) { + Reset(); + return; + } + + if (IsRef()) { + info = RefInfo(inOther.Data(), inOther.MemorySize()); + } else { + info = HolderInfo(inOther.MemorySize()); + for (auto i = 0; i < ElementNum(); i++) { + rtti->copyConstruct(Data(i), inOther.Data(i)); + } + } + } + + void Any::PerformCopyConstructForElementWithPolicy(const Any& inOther, AnyPolicy inPolicy, uint32_t inIndex) + { + arrayLength = 0; policy = inPolicy; rtti = inOther.rtti; @@ -154,15 +186,16 @@ namespace Mirror { } if (IsRef()) { - info = RefInfo(inOther.Data(), inOther.Size()); + info = RefInfo(inOther.Data(inIndex), inOther.ElementSize()); } else { - info = HolderInfo(inOther.Size()); - rtti->copyConstruct(Data(), inOther.Data()); + info = HolderInfo(inOther.ElementSize()); + rtti->copyConstruct(Data(), inOther.Data(inIndex)); } } void Any::PerformMoveConstruct(Any&& inOther) { + arrayLength = inOther.arrayLength; policy = inOther.policy; rtti = inOther.rtti; @@ -172,35 +205,75 @@ namespace Mirror { } if (IsRef()) { - info = RefInfo(inOther.Data(), inOther.Size()); + info = RefInfo(inOther.Data(), inOther.MemorySize()); } else { - info = HolderInfo(inOther.Size()); - rtti->moveConstruct(Data(), inOther.Data()); + info = HolderInfo(inOther.MemorySize()); + for (auto i = 0; i < ElementNum(); i++) { + rtti->moveConstruct(Data(i), inOther.Data(i)); + } } } + uint32_t Any::ElementNum() const + { + return std::max(1u, arrayLength); + } + + bool Any::IsArray() const + { + return arrayLength > 0; + } + + Any Any::At(uint32_t inIndex) + { + Assert(IsArray()); + return { *this, AnyPolicy::nonConstRef, inIndex }; + } + + Any Any::At(uint32_t inIndex) const + { + Assert(IsArray()); + return { *this, AnyPolicy::constRef, inIndex }; + } + + size_t Any::ElementSize() const + { + return MemorySize() / ElementNum(); + } + + uint32_t Any::ArrayLength() const + { + Assert(IsArray()); + return arrayLength; + } + Any Any::Ref() { + Assert(!IsArray()); return { *this, IsMemoryHolder() ? AnyPolicy::nonConstRef : policy }; } Any Any::Ref() const { + Assert(!IsArray()); return { *this, IsMemoryHolder() ? AnyPolicy::constRef : policy }; } Any Any::ConstRef() const { + Assert(!IsArray()); return { *this, AnyPolicy::constRef }; } - Any Any::AsValue() const + Any Any::Value() const { + Assert(!IsArray()); return { *this, AnyPolicy::memoryHolder }; } Any Any::Ptr() { + Assert(!IsArray()); if (policy == AnyPolicy::memoryHolder) { return rtti->getPtr(Data()); } @@ -216,6 +289,7 @@ namespace Mirror { Any Any::Ptr() const { + Assert(!IsArray()); if (policy == AnyPolicy::memoryHolder) { return rtti->getConstPtr(Data()); } @@ -231,11 +305,13 @@ namespace Mirror { Any Any::ConstPtr() const { + Assert(!IsArray()); return rtti->getConstPtr(Data()); } Any Any::Deref() const { + Assert(!IsArray()); return rtti->deref(Data()); } @@ -384,6 +460,7 @@ namespace Mirror { void Any::Reset() { + arrayLength = 0; policy = AnyPolicy::max; rtti = nullptr; info = {}; @@ -396,51 +473,53 @@ namespace Mirror { size_t Any::Serialize(Common::BinarySerializeStream& inStream) const { - Assert(rtti != nullptr); + Assert(!IsArray() && rtti != nullptr); return rtti->serialize(Data(), inStream); } std::pair Any::Deserialize(Common::BinaryDeserializeStream& inStream) { - Assert(rtti != nullptr && !IsConstRef()); + Assert(!IsArray() && rtti != nullptr && !IsConstRef()); return rtti->deserialize(Data(), inStream); } std::pair Any::Deserialize(Common::BinaryDeserializeStream& inStream) const { - Assert(rtti != nullptr && IsNonConstRef()); + Assert(!IsArray() && rtti != nullptr && IsNonConstRef()); return rtti->deserialize(Data(), inStream); } void Any::JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator) const { - Assert(rtti != nullptr); + Assert(!IsArray() && rtti != nullptr); rtti->jsonSerialize(Data(), outJsonValue, inAllocator); } void Any::JsonDeserialize(const rapidjson::Value& inJsonValue) { - Assert(rtti != nullptr && !IsConstRef()); + Assert(!IsArray() && rtti != nullptr && !IsConstRef()); rtti->jsonDeserialize(Data(), inJsonValue); } void Any::JsonDeserialize(const rapidjson::Value& inJsonValue) const { - Assert(rtti != nullptr && IsNonConstRef()); + Assert(!IsArray() && rtti != nullptr && IsNonConstRef()); return rtti->jsonDeserialize(Data(), inJsonValue); } std::string Any::ToString() const { + Assert(!IsArray()); return Empty() ? "" : rtti->toString(Data()); } - void* Any::Data() const + void* Any::Data(uint32_t inIndex) const { - return IsRef() ? std::get(info).Ptr() : std::get(info).Ptr(); + void* ptr = IsRef() ? std::get(info).Ptr() : std::get(info).Ptr(); + return static_cast(ptr) + ElementSize() * inIndex; } - size_t Any::Size() const + size_t Any::MemorySize() const { return IsRef() ? std::get(info).Size() : std::get(info).Size(); } @@ -450,14 +529,31 @@ namespace Mirror { return !Empty(); } + Any Any::operator[](uint32_t inIndex) + { + return At(inIndex); + } + + Any Any::operator[](uint32_t inIndex) const + { + return At(inIndex); + } + bool Any::operator==(const Any& inAny) const { + Assert(!IsArray()); if (TypeId() != inAny.TypeId()) { return false; } return rtti->equal(Data(), inAny.Data()); } + bool Any::operator!=(const Any& inAny) const + { + Assert(!IsArray()); + return !operator==(inAny); + } + Any::HolderInfo::HolderInfo() = default; Any::HolderInfo::HolderInfo(size_t inMemorySize) @@ -1364,23 +1460,45 @@ namespace Mirror { return {}; } - EnumElement::EnumElement(ConstructParams&& inParams) + EnumValue::EnumValue(ConstructParams&& inParams) : Type(std::move(inParams.name)) , getter(std::move(inParams.getter)) + , integralGetter(std::move(inParams.integralGetter)) + , setter(std::move(inParams.setter)) , comparer(std::move(inParams.comparer)) { } - EnumElement::~EnumElement() = default; + EnumValue::~EnumValue() = default; - Any EnumElement::Get() const + Any EnumValue::Get() const { return getter(); } - bool EnumElement::Compare(const Argument& argument) const + EnumValue::IntegralValue EnumValue::GetIntegral() const { - return comparer(argument); + return GetIntegralDyn(); + } + + Any EnumValue::GetDyn() const + { + return getter(); + } + + EnumValue::IntegralValue EnumValue::GetIntegralDyn() const + { + return integralGetter(); + } + + void EnumValue::SetDyn(const Argument& arg) const + { + setter(arg); + } + + bool EnumValue::CompareDyn(const Argument& arg) const + { + return comparer(arg); } const Enum* Enum::Find(const Id& inId) @@ -1413,28 +1531,85 @@ namespace Mirror { return typeInfo; } - Any Enum::GetElement(const Id& inId) const + bool Enum::HasValue(const Id& inId) const + { + return values.contains(inId); + } + + const EnumValue* Enum::FindValue(const Id& inId) const + { + const auto iter = values.find(inId); + return iter == values.end() ? nullptr : &iter->second; + } + + const EnumValue& Enum::GetValue(const Id& inId) const + { + return values.at(inId); + } + + bool Enum::HasValue(EnumValue::IntegralValue inValue) const { - const auto iter = elements.find(inId); - Assert(iter != elements.end()); - return iter->second.Get(); + return FindValue(inValue) != nullptr; } - std::string Enum::GetElementName(const Argument& argument) const + const EnumValue* Enum::FindValue(EnumValue::IntegralValue inValue) const { - for (const auto& [id, element] : elements) { - if (element.Compare(argument)) { - return id.name; + for (const auto& value : values | std::views::values) { + if (value.GetIntegralDyn() == inValue) { + return &value; } } - QuickFail(); - return ""; + return nullptr; + } + + const EnumValue& Enum::GetValue(EnumValue::IntegralValue inValue) const + { + const auto* value = FindValue(inValue); + Assert(value != nullptr); + return *value; + } + + bool Enum::HasValue(const Argument& inArg) const + { + return FindValue(inArg) != nullptr; + } + + const EnumValue* Enum::FindValue(const Argument& inArg) const + { + for (const auto& value : values | std::views::values) { + if (value.CompareDyn(inArg)) { + return &value; + } + } + return nullptr; + } + + const EnumValue& Enum::GetValue(const Argument& inArg) const + { + const auto* value = FindValue(inArg); + Assert(value != nullptr); + return *value; + } + + const std::unordered_map& Enum::GetValues() const + { + return values; + } + + std::vector Enum::GetSortedValues() const + { + std::vector result; + for (const auto& value : values | std::views::values) { + result.emplace_back(&value); + } + std::ranges::sort(result, [](const EnumValue* lhs, const EnumValue* rhs) { return lhs->GetIntegralDyn() < rhs->GetIntegralDyn(); }); + return result; } - EnumElement& Enum::EmplaceElement(const Id& inId, EnumElement::ConstructParams&& inParams) + EnumValue& Enum::EmplaceElement(const Id& inId, EnumValue::ConstructParams&& inParams) { - Assert(!elements.contains(inId)); - elements.emplace(inId, EnumElement(std::move(inParams))); - return elements.at(inId); + Assert(!values.contains(inId)); + values.emplace(inId, EnumValue(std::move(inParams))); + return values.at(inId); } } diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index b106e536..31a489d9 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace Mirror; @@ -133,19 +134,19 @@ TEST(AnyTest, CopyCtorWithPolicyTest) Any a1 { a0, AnyPolicy::nonConstRef }; ASSERT_FALSE(called); ASSERT_EQ(a1.Policy(), AnyPolicy::nonConstRef); - ASSERT_EQ(a1.Size(), a0.Size()); + ASSERT_EQ(a1.MemorySize(), a0.MemorySize()); ASSERT_EQ(a1.Data(), a0.Data()); Any a2 { a0, AnyPolicy::constRef }; ASSERT_FALSE(called); ASSERT_EQ(a2.Policy(), AnyPolicy::constRef); - ASSERT_EQ(a2.Size(), a0.Size()); + ASSERT_EQ(a2.MemorySize(), a0.MemorySize()); ASSERT_EQ(a2.Data(), a0.Data()); Any a3 { a0, AnyPolicy::memoryHolder }; ASSERT_TRUE(called); ASSERT_EQ(a3.Policy(), AnyPolicy::memoryHolder); - ASSERT_EQ(a3.Size(), a0.Size()); + ASSERT_EQ(a3.MemorySize(), a0.MemorySize()); ASSERT_NE(a3.Data(), a0.Data()); } @@ -303,7 +304,7 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a1.Convertible()); ASSERT_FALSE(a1.Convertible()); - a1 = a1.AsValue(); + a1 = a1.Value(); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); @@ -388,7 +389,7 @@ TEST(AnyTest, ConstConvertibleTest) ASSERT_FALSE(a6.Convertible()); ASSERT_TRUE(a6.Convertible()); - const Any a7 = a6.AsValue(); + const Any a7 = a6.Value(); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_FALSE(a1.Convertible()); @@ -604,6 +605,40 @@ TEST(AnyTest, ConstTryAsTest) ASSERT_EQ(a3.TryAs(), nullptr); } +TEST(AnyTest, PolyAsTest) +{ + const Common::UniqueRef v0 = new AnyDerivedClassTest2(1, 2.0f, "3"); + + Any a0 = std::ref(*v0); + const auto& r0 = a0.PolyAs(); + ASSERT_EQ(r0.a, 1); + ASSERT_EQ(r0.b, 2.0f); + ASSERT_EQ(r0.c, "3"); + + Any a1 = v0.Get(); + const auto* p0 = a1.PolyAs(); + ASSERT_EQ(p0->a, 1); + ASSERT_EQ(p0->b, 2.0f); + ASSERT_EQ(p0->c, "3"); +} + +TEST(AnyTest, ConstPolyAsTest) +{ + const Common::UniqueRef v0 = new AnyDerivedClassTest2(1, 2.0f, "3"); + + const Any a0 = std::ref(*v0); + const auto& r0 = a0.PolyAs(); + ASSERT_EQ(r0.a, 1); + ASSERT_EQ(r0.b, 2.0f); + ASSERT_EQ(r0.c, "3"); + + const Any a1 = v0.Get(); + const auto* p0 = a1.PolyAs(); + ASSERT_EQ(p0->a, 1); + ASSERT_EQ(p0->b, 2.0f); + ASSERT_EQ(p0->c, "3"); +} + TEST(AnyTest, GetRefTest) { Any a0 = 1; @@ -653,23 +688,23 @@ TEST(AnyTest, ConstGetRefTest) ASSERT_EQ(a9.Policy(), AnyPolicy::constRef); } -TEST(AnyTest, AsValueTest) +TEST(AnyTest, ValueTest) { const Any a0 = 1; - const Any a1 = a0.AsValue(); + const Any a1 = a0.Value(); ASSERT_NE(a0.Data(), a1.Data()); ASSERT_EQ(a1.Policy(), AnyPolicy::memoryHolder); int v0 = 2; const Any a2 = std::ref(v0); - const Any a3 = a2.AsValue(); + const Any a3 = a2.Value(); ASSERT_EQ(&v0, a2.Data()); ASSERT_NE(a2.Data(), a3.Data()); ASSERT_EQ(a3.Policy(), AnyPolicy::memoryHolder); const int v1 = 2; // NOLINT const Any a4 = std::ref(v1); - const Any a5 = a4.AsValue(); + const Any a5 = a4.Value(); ASSERT_EQ(&v1, a4.Data()); ASSERT_NE(a4.Data(), a5.Data()); ASSERT_EQ(a5.Policy(), AnyPolicy::memoryHolder); @@ -1100,15 +1135,15 @@ TEST(AnyTest, DataTest) TEST(AnyTest, SizeTest) { const Any a0 = 1; - ASSERT_EQ(a0.Size(), sizeof(int)); + ASSERT_EQ(a0.MemorySize(), sizeof(int)); int v0 = 1; const Any a1 = std::ref(v0); - ASSERT_EQ(a1.Size(), sizeof(int)); + ASSERT_EQ(a1.MemorySize(), sizeof(int)); const int v1 = 1; // NOLINT const Any a2 = std::ref(v1); - ASSERT_EQ(a2.Size(), sizeof(int)); + ASSERT_EQ(a2.MemorySize(), sizeof(int)); } TEST(AnyTest, OperatorBoolTest) @@ -1152,5 +1187,46 @@ TEST(AnyTest, OperatorEqualTest) TEST(AnyTest, ToStringTest) { - // TODO + const Any a0 = 1; + ASSERT_EQ(a0.ToString(), "1"); +} + +TEST(AnyTest, ArrayTest) +{ + int v0[] = { 1, 2, 3 }; + Any a0 = v0; + ASSERT_TRUE(a0.IsMemoryHolder()); + ASSERT_EQ(a0.ElementSize(), sizeof(int)); + ASSERT_EQ(a0.MemorySize(), sizeof(v0)); + ASSERT_EQ(a0.ArrayLength(), sizeof(v0) / sizeof(int)); + + const Any a1 = a0.At(0); + ASSERT_TRUE(a1.IsNonConstRef()); + ASSERT_EQ(a1.As(), 1); + + const Any a2 = v0; + ASSERT_TRUE(a2.IsMemoryHolder()); + ASSERT_EQ(a2.ElementSize(), sizeof(int)); + ASSERT_EQ(a2.MemorySize(), sizeof(v0)); + ASSERT_EQ(a2.ArrayLength(), sizeof(v0) / sizeof(int)); + + const Any a3 = a2[1]; + ASSERT_EQ(a3.As(), 2); + + Any a4 = std::move(v0); + ASSERT_TRUE(a4.IsMemoryHolder()); + ASSERT_EQ(a4.ElementSize(), sizeof(int)); + ASSERT_EQ(a4.MemorySize(), sizeof(v0)); + ASSERT_EQ(a4.ArrayLength(), sizeof(v0) / sizeof(int)); + + const Any a5 = a4.At(2); + ASSERT_EQ(a5.As(), 3); + + const int v1[] = { 1, 2, 3 }; // NOLINT + Any a6 = std::ref(v1); + ASSERT_TRUE(a6.IsConstRef()); + ASSERT_EQ(a6.ElementSize(), sizeof(int)); + ASSERT_EQ(a6.MemorySize(), sizeof(v0)); + ASSERT_EQ(a6.ArrayLength(), sizeof(v0) / sizeof(int)); + ASSERT_EQ(a6[1].As(), 2); } diff --git a/Engine/Source/Mirror/Test/AnyTest.h b/Engine/Source/Mirror/Test/AnyTest.h index 90314e13..cfd0d1d4 100644 --- a/Engine/Source/Mirror/Test/AnyTest.h +++ b/Engine/Source/Mirror/Test/AnyTest.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include @@ -47,3 +48,32 @@ struct EClass() AnyBaseClassTest { struct EClass() AnyDerivedClassTest : AnyBaseClassTest { EClassBody(AnyDerivedClassTest) }; + +struct EClass() AnyBaseClassTest2 { + EClassBody(AnyBaseClassTest2) + + AnyBaseClassTest2(int inA, float inB) + : a(inA) + , b(inB) + { + } + + virtual ~AnyBaseClassTest2() = default; + + int a; + float b; +}; + +struct EClass() AnyDerivedClassTest2 final : AnyBaseClassTest2 { + EClassBody(AnyDerivedClassTest2) + + AnyDerivedClassTest2(int inA, float inB, std::string inC) + : AnyBaseClassTest2(inA, inB) + , c(std::move(inC)) + { + } + + ~AnyDerivedClassTest2() override = default; + + std::string c; +}; diff --git a/Engine/Source/Mirror/Test/RegistryTest.cpp b/Engine/Source/Mirror/Test/RegistryTest.cpp index 87ab665b..b0fc2b4b 100644 --- a/Engine/Source/Mirror/Test/RegistryTest.cpp +++ b/Engine/Source/Mirror/Test/RegistryTest.cpp @@ -166,18 +166,18 @@ TEST(RegistryTest, ClassTest) TEST(RegistryTest, EnumTest) { const auto& enumInfo = Mirror::Enum::Get(); - auto a = enumInfo.GetElement("a"); - auto b = enumInfo.GetElement("b"); - auto c = enumInfo.GetElement("c"); - auto max = enumInfo.GetElement("max"); - - ASSERT_EQ(a.As(), E0::a); - ASSERT_EQ(b.As(), E0::b); - ASSERT_EQ(c.As(), E0::c); - ASSERT_EQ(max.As(), E0::max); - - ASSERT_EQ(enumInfo.GetElementName(a), "a"); - ASSERT_EQ(enumInfo.GetElementName(b), "b"); - ASSERT_EQ(enumInfo.GetElementName(c), "c"); - ASSERT_EQ(enumInfo.GetElementName(max), "max"); + auto a = enumInfo.GetValue("a"); + auto b = enumInfo.GetValue("b"); + auto c = enumInfo.GetValue("c"); + auto max = enumInfo.GetValue("max"); + + ASSERT_EQ(a.GetDyn().As(), E0::a); + ASSERT_EQ(b.GetDyn().As(), E0::b); + ASSERT_EQ(c.GetDyn().As(), E0::c); + ASSERT_EQ(max.GetDyn().As(), E0::max); + + ASSERT_EQ(a.GetName(), "a"); + ASSERT_EQ(b.GetName(), "b"); + ASSERT_EQ(c.GetName(), "c"); + ASSERT_EQ(max.GetName(), "max"); } diff --git a/Engine/Source/Mirror/Test/SerializationTest.cpp b/Engine/Source/Mirror/Test/SerializationTest.cpp index 1c2e24e0..28a09923 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.cpp +++ b/Engine/Source/Mirror/Test/SerializationTest.cpp @@ -13,10 +13,29 @@ int ga = 0; float gb = 0.0f; std::string gc; +template +void PerformMetaObjectSerializationTest(const std::filesystem::path& fileName, const T& object) +{ + std::filesystem::create_directories(fileName.parent_path()); + { + Common::BinaryFileSerializeStream stream(fileName.string()); + Serialize(stream, object); + } + + { + Common::BinaryFileDeserializeStream stream(fileName.string()); + + T restored; + Deserialize(stream, restored); + ASSERT_EQ(restored, object); + } +} + TEST(SerializationTest, VariableFileTest) { static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.VariableFileSerializationTest.bin"; std::filesystem::create_directories(fileName.parent_path()); + { Common::BinaryFileSerializeStream stream(fileName.string()); @@ -50,101 +69,66 @@ TEST(SerializationTest, VariableFileTest) TEST(SerializationTest, ClassFileTest) { - static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.ClassFileSerializationTest.bin"; - std::filesystem::create_directories(fileName.parent_path()); - { - Common::BinaryFileSerializeStream stream(fileName.string()); - - SerializationTestStruct0 obj; - obj.a = 1; - obj.b = 2.0f; - obj.c = "3"; - Serialize(stream, obj); - } - - { - Common::BinaryFileDeserializeStream stream(fileName.string()); + PerformMetaObjectSerializationTest( + "../Test/Generated/Mirror/SerializationTest.ClassFileSerializationTest.bin", + SerializationTestStruct0 { 1, 2, "3.0" }); +} - SerializationTestStruct0 obj; - Deserialize(stream, obj); +TEST(SerializationTest, ContainerFileTest) +{ + SerializationTestStruct1 obj; + obj.a = { 1, 2 }; + obj.b = { "3", "4" }; + obj.c = { { 5, "6" }, { 7, "8" } }; + obj.d = { { false, true }, { true, false } }; + obj.e = { { 1, 2.0f, "3" } }; + + PerformMetaObjectSerializationTest( + "../Test/Generated/Mirror/SerializationTest.ContainerFileSerializationTest.bin", + obj); +} - const auto& [a, b, c] = obj; - ASSERT_EQ(a, 1); - ASSERT_EQ(b, 2.0f); - ASSERT_EQ(c, "3"); - } +TEST(SerializationTest, MetaObjectWithBaseClassTest) +{ + PerformMetaObjectSerializationTest( + "../Test/Generated/Mirror/SerializationTest.MetaObjectWithBaseClassTest.bin", + SerializationTestStruct2 { { 1, 2, "3.0" }, 4.0 }); } -TEST(SerializationTest, ContainerFileTest) +TEST(SerializationTest, EnumSerializationTest) { - static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.ContainerFileSerializationTest.bin"; + static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.EnumSerializationTest.bin"; std::filesystem::create_directories(fileName.parent_path()); - const auto& clazz = Mirror::Class::Get("SerializationTestStruct1"); + { Common::BinaryFileSerializeStream stream(fileName.string()); - - SerializationTestStruct1 obj; - obj.a = { 1, 2 }; - obj.b = { "3", "4" }; - obj.c = { { 5, "6" }, { 7, "8" } }; - obj.d = { { false, true }, { true, false } }; - obj.e = { { 1, 2.0f, "3" } }; - - Mirror::Any(std::ref(obj)) - .Serialize(stream); + Serialize(stream, SerializationTestEnum::b); } { Common::BinaryFileDeserializeStream stream(fileName.string()); - - Mirror::Any ref = clazz.GetDefaultConstructor().Construct(); - ref.Deserialize(stream); - - const auto& [a, b, c, d, e] = ref.As(); - ASSERT_EQ(a.size(), 2); - ASSERT_EQ(a[0], 1); - ASSERT_EQ(a[1], 2); - ASSERT_EQ(b.size(), 2); - ASSERT_EQ(b.contains("3"), true); - ASSERT_EQ(b.contains("4"), true); - ASSERT_EQ(c.size(), 2); - ASSERT_EQ(c.at(5), "6"); - ASSERT_EQ(c.at(7), "8"); - ASSERT_EQ(d.size(), 2); - ASSERT_EQ(d[0].size(), 2); - ASSERT_EQ(d[0][0], false); - ASSERT_EQ(d[0][1], true); - ASSERT_EQ(d[1].size(), 2); - ASSERT_EQ(d[1][0], true); - ASSERT_EQ(d[1][1], false); - ASSERT_EQ(e.size(), 1); - ASSERT_EQ(e[0].a, 1); - ASSERT_EQ(e[0].b, 2.0f); - ASSERT_EQ(e[0].c, "3"); + SerializationTestEnum metaEnum; + Deserialize(stream, metaEnum); + ASSERT_EQ(metaEnum, SerializationTestEnum::b); } } -TEST(SerializationTest, MetaObjectTypeTest) -{ - // TODO -} - -TEST(SerializationTest, MetaObjectSameAsDefaultObjectTest) +TEST(SerializationTest, MetaTypeSerializationTest) { // TODO } -TEST(SerializationTest, MetaObjectWithBaseClassTest) +TEST(SerializationTest, MetaObjectJsonSerializationTest) { // TODO } -TEST(SerializationTest, MetaObjectUpgradeTest) +TEST(SerializationTest, EnumJsonSerializationTest) { // TODO } -TEST(SerializationTest, EnumSerializationTest) +TEST(SerializationTest, MetaTypeJsonSerializationTest) { // TODO } diff --git a/Engine/Source/Mirror/Test/SerializationTest.h b/Engine/Source/Mirror/Test/SerializationTest.h index 434d5ddb..0ccd8d06 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.h +++ b/Engine/Source/Mirror/Test/SerializationTest.h @@ -12,9 +12,9 @@ #include enum class EEnum(test=true) SerializationTestEnum { - a EMeta(test=true), - b, - max + a EMeta(test=a), + b EMeta(test=b), + max EMeta(test=c) }; EProperty() extern int ga; @@ -44,4 +44,19 @@ struct EClass() SerializationTestStruct1 { EProperty() std::unordered_map c; EProperty() std::vector> d; EProperty() std::vector e; + + bool operator==(const SerializationTestStruct1& rhs) const + { + return a == rhs.a + && b == rhs.b + && c == rhs.c + && d == rhs.d + && e == rhs.e; + } +}; + +struct EClass() SerializationTestStruct2 : SerializationTestStruct0 { + EClassBody(SerializationTestStruct2); + + EProperty() double d; }; diff --git a/Tool/MirrorTool/Src/Generator.cpp b/Tool/MirrorTool/Src/Generator.cpp index c0e81bb8..ba559718 100644 --- a/Tool/MirrorTool/Src/Generator.cpp +++ b/Tool/MirrorTool/Src/Generator.cpp @@ -62,7 +62,7 @@ namespace MirrorTool { for (const auto& element : enumInfo.elements) { const auto elementFullName = GetFullName(element); stream << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Element<{}>("{}"))", elementFullName, element.name); + stream << Common::tab<3> << fmt::format(R"(.Value<{}>("{}"))", elementFullName, element.name); stream << GetMetaDataCode<4>(element); } stream << ";" << Common::newline; From b80d02c66a54d24271a9a05703eaeb9ceb8c02a1 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Tue, 8 Oct 2024 21:13:36 +0800 Subject: [PATCH 5/7] feat: support get owner in mirror reflect nodes --- Engine/Source/Mirror/Include/Mirror/Mirror.h | 70 ++++++++---- .../Source/Mirror/Include/Mirror/Registry.h | 41 ++++--- Engine/Source/Mirror/Src/Mirror.cpp | 104 +++++++++++++----- 3 files changed, 148 insertions(+), 67 deletions(-) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 386ac5b2..450c6208 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -304,6 +304,8 @@ namespace Mirror { class Variable; class MemberVariable; + class Class; + class Enum; class MIRROR_API Argument { public: @@ -335,10 +337,13 @@ namespace Mirror { using ArgumentList = std::vector; struct MIRROR_API Id { + static Id null; + Id(); template Id(const char (&inName)[N]); // NOLINT Id(std::string inName); // NOLINT + bool IsNull() const; bool operator==(const Id& inRhs) const; size_t hash; @@ -349,16 +354,17 @@ namespace Mirror { size_t operator()(const Id& inId) const noexcept; }; - struct MIRROR_API NamePresets { + struct MIRROR_API IdPresets { static const Id globalScope; static const Id detor; static const Id defaultCtor; }; - class MIRROR_API Type { + class MIRROR_API ReflNode { public: - virtual ~Type(); + virtual ~ReflNode(); + const Id& GetId() const; const std::string& GetName() const; const std::string& GetMeta(const std::string& key) const; std::string GetAllMeta() const; @@ -369,22 +375,23 @@ namespace Mirror { float GetMetaFloat(const std::string& key) const; protected: - explicit Type(std::string inName); + explicit ReflNode(Id inId); private: template friend class MetaDataRegistry; - std::string name; + Id id; std::unordered_map metas; }; - class MIRROR_API Variable final : public Type { + class MIRROR_API Variable final : public ReflNode { public: ~Variable() override; template void Set(T&& value) const; Any Get() const; + const Class* GetOwner() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& inArgument) const; Any GetDyn() const; @@ -399,7 +406,8 @@ namespace Mirror { using Getter = std::function; struct ConstructParams { - std::string name; + Id id; + Id owner; size_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -408,16 +416,18 @@ namespace Mirror { explicit Variable(ConstructParams&& params); + Id owner; size_t memorySize; const TypeInfo* typeInfo; Setter setter; Getter getter; }; - class MIRROR_API Function final : public Type { + class MIRROR_API Function final : public ReflNode { public: ~Function() override; + const Class* GetOwner() const; template Any Invoke(Args&&... args) const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; @@ -434,7 +444,8 @@ namespace Mirror { using Invoker = std::function; struct ConstructParams { - std::string name; + Id id; + Id owner; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -443,19 +454,21 @@ namespace Mirror { explicit Function(ConstructParams&& params); + Id owner; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; Invoker invoker; }; - class MIRROR_API Constructor final : public Type { + class MIRROR_API Constructor final : public ReflNode { public: ~Constructor() override; template Any Construct(Args&&... args) const; template Any New(Args&&... args) const; + const Class* GetOwner() const; uint8_t GetArgsNum() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; const std::vector& GetArgTypeInfos() const; @@ -475,7 +488,8 @@ namespace Mirror { using Invoker = std::function; struct ConstructParams { - std::string name; + Id id; + Id owner; uint8_t argsNum; std::vector argTypeInfos; std::vector argRemoveRefTypeInfos; @@ -486,6 +500,7 @@ namespace Mirror { explicit Constructor(ConstructParams&& params); + Id owner; uint8_t argsNum; std::vector argTypeInfos; std::vector argRemoveRefTypeInfos; @@ -494,7 +509,7 @@ namespace Mirror { Invoker heapConstructor; }; - class MIRROR_API Destructor final : public Type { + class MIRROR_API Destructor final : public ReflNode { public: ~Destructor() override; @@ -517,13 +532,14 @@ namespace Mirror { Invoker destructor; }; - class MIRROR_API MemberVariable final : public Type { + class MIRROR_API MemberVariable final : public ReflNode { public: ~MemberVariable() override; template void Set(C&& object, T&& value) const; template Any Get(C&& object) const; + const Class* GetOwner() const; uint32_t SizeOf() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& object, const Argument& value) const; @@ -538,7 +554,8 @@ namespace Mirror { using Getter = std::function; struct ConstructParams { - std::string name; + Id id; + Id owner; uint32_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -547,18 +564,20 @@ namespace Mirror { explicit MemberVariable(ConstructParams&& params); + Id owner; uint32_t memorySize; const TypeInfo* typeInfo; Setter setter; Getter getter; }; - class MIRROR_API MemberFunction final : public Type { + class MIRROR_API MemberFunction final : public ReflNode { public: ~MemberFunction() override; template Any Invoke(C&& object, Args&&... args) const; + const Class* GetOwner() const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; @@ -572,7 +591,8 @@ namespace Mirror { using Invoker = std::function; struct ConstructParams { - std::string name; + Id id; + Id owner; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -581,6 +601,7 @@ namespace Mirror { explicit MemberFunction(ConstructParams&& params); + Id owner; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -592,7 +613,7 @@ namespace Mirror { using MemberVariableTraverser = std::function; using MemberFunctionTraverser = std::function; - class MIRROR_API GlobalScope final : public Type { + class MIRROR_API GlobalScope final : public ReflNode { public: ~GlobalScope() override; @@ -620,7 +641,7 @@ namespace Mirror { std::unordered_map functions; }; - class MIRROR_API Class final : public Type { + class MIRROR_API Class final : public ReflNode { public: template static bool Has(); template static const Class* Find(); @@ -688,7 +709,7 @@ namespace Mirror { using BaseClassGetter = std::function; struct ConstructParams { - std::string name; + Id id; const TypeInfo* typeInfo; BaseClassGetter baseClassGetter; std::function defaultObjectCreator; @@ -717,7 +738,7 @@ namespace Mirror { std::unordered_map memberFunctions; }; - class MIRROR_API EnumValue final : public Type { + class MIRROR_API EnumValue final : public ReflNode { public: using IntegralValue = int64_t; @@ -728,6 +749,7 @@ namespace Mirror { template void Set(E& value) const; template bool Compare(const E& value) const; + const Enum* GetOwner() const; Any GetDyn() const; IntegralValue GetIntegralDyn() const; void SetDyn(const Argument& arg) const; @@ -746,7 +768,8 @@ namespace Mirror { using Comparer = std::function; struct ConstructParams { - std::string name; + Id id; + Id owner; Getter getter; IntegralGetter integralGetter; Setter setter; @@ -755,13 +778,14 @@ namespace Mirror { explicit EnumValue(ConstructParams&& inParams); + Id owner; Getter getter; IntegralGetter integralGetter; Setter setter; Comparer comparer; }; - class MIRROR_API Enum final : public Type { + class MIRROR_API Enum final : public ReflNode { public: template static const Enum* Find(); template static const Enum& Get(); @@ -793,7 +817,7 @@ namespace Mirror { template friend class EnumRegistry; struct ConstructParams { - std::string name; + Id id; const TypeInfo* typeInfo; }; diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 34948afa..6bf991c8 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -33,12 +33,12 @@ namespace Mirror { Derived& MetaData(const Id& inKey, const std::string& inValue); protected: - explicit MetaDataRegistry(Type* inContext); + explicit MetaDataRegistry(ReflNode* inContext); - Derived& SetContext(Type* inContext); + Derived& SetContext(ReflNode* inContext); private: - Type* context; + ReflNode* context; }; template @@ -192,7 +192,7 @@ namespace Mirror::Internal { namespace Mirror { template - MetaDataRegistry::MetaDataRegistry(Type* inContext) + MetaDataRegistry::MetaDataRegistry(ReflNode* inContext) : context(inContext) { Assert(context); @@ -209,7 +209,7 @@ namespace Mirror { } template - Derived& MetaDataRegistry::SetContext(Type* inContext) + Derived& MetaDataRegistry::SetContext(ReflNode* inContext) { Assert(inContext); context = inContext; @@ -236,7 +236,8 @@ namespace Mirror { Assert(iter == clazz.constructors.end()); Constructor::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = clazz.GetId(); params.argsNum = sizeof...(Args); params.argTypeInfos = { GetTypeInfo()... }; params.argRemoveRefTypeInfos = { GetTypeInfo>()... }; @@ -265,7 +266,8 @@ namespace Mirror { Assert(iter == clazz.staticVariables.end()); Variable::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = clazz.GetId(); params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& value) -> void { @@ -295,7 +297,8 @@ namespace Mirror { constexpr size_t argsTupleSize = std::tuple_size_v; Function::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = clazz.GetId(); params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); @@ -325,7 +328,8 @@ namespace Mirror { Assert(iter == clazz.memberVariables.end()); MemberVariable::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = clazz.GetId(); params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& object, const Argument& value) -> void { @@ -356,7 +360,8 @@ namespace Mirror { constexpr size_t argsTupleSize = std::tuple_size_v; MemberFunction::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = clazz.GetId(); params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); @@ -384,7 +389,8 @@ namespace Mirror { Assert(iter == globalScope.variables.end()); Variable::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = Id::null; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& argument) -> void { @@ -412,7 +418,8 @@ namespace Mirror { constexpr size_t argsTupleSize = std::tuple_size_v; Function::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = Id::null; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); @@ -448,7 +455,8 @@ namespace Mirror { Assert(iter == enumInfo.values.end()); EnumValue::ConstructParams params; - params.name = inId.name; + params.id = inId; + params.owner = enumInfo.GetId(); params.getter = []() -> Any { return { Value }; }; @@ -473,7 +481,7 @@ namespace Mirror { Assert(!classes.contains(inId)); Class::ConstructParams params; - params.name = inId.name; + params.id = inId; params.typeInfo = GetTypeInfo(); params.baseClassGetter = []() -> const Mirror::Class* { if constexpr (std::is_void_v) { @@ -497,7 +505,8 @@ namespace Mirror { } if constexpr (std::is_default_constructible_v) { Constructor::ConstructParams ctorParams; - ctorParams.name = NamePresets::defaultCtor.name; + ctorParams.id = IdPresets::defaultCtor.name; + ctorParams.owner = inId; ctorParams.argsNum = 0; ctorParams.argTypeInfos = {}; ctorParams.stackConstructor = [](const ArgumentList& args) -> Any { @@ -523,7 +532,7 @@ namespace Mirror { Assert(!enums.contains(inId)); Enum::ConstructParams params; - params.name = inId.name; + params.id = inId; Enum::typeToIdMap[typeId] = inId; return EnumRegistry(EmplaceEnum(inId, std::move(params))); diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 0d48d022..5e25ccca 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -701,6 +701,8 @@ namespace Mirror { }); } + Id Id::null = Id(); + Id::Id() : hash(0) { @@ -712,6 +714,11 @@ namespace Mirror { { } + bool Id::IsNull() const + { + return hash == null.hash; + } + bool Id::operator==(const Id& inRhs) const { return hash == inRhs.hash; @@ -722,27 +729,32 @@ namespace Mirror { return inId.hash; } - const Id NamePresets::globalScope = Id("_globalScope"); - const Id NamePresets::detor = Id("_detor"); - const Id NamePresets::defaultCtor = Id("_defaultCtor"); + const Id IdPresets::globalScope = Id("_globalScope"); + const Id IdPresets::detor = Id("_detor"); + const Id IdPresets::defaultCtor = Id("_defaultCtor"); - Type::Type(std::string inName) : name(std::move(inName)) {} + ReflNode::ReflNode(Id inId) : id(std::move(inId)) {} - Type::~Type() = default; + ReflNode::~ReflNode() = default; + + const Id& ReflNode::GetId() const + { + return id; + } - const std::string& Type::GetName() const + const std::string& ReflNode::GetName() const { - return name; + return id.name; } - const std::string& Type::GetMeta(const std::string& key) const + const std::string& ReflNode::GetMeta(const std::string& key) const { const auto iter = metas.find(key); Assert(iter != metas.end()); return iter->second; } - std::string Type::GetAllMeta() const + std::string ReflNode::GetAllMeta() const { std::stringstream stream; uint32_t count = 0; @@ -757,12 +769,12 @@ namespace Mirror { return stream.str(); } - bool Type::HasMeta(const std::string& key) const + bool ReflNode::HasMeta(const std::string& key) const { return metas.contains(key); } - bool Type::GetMetaBool(const std::string& key) const + bool ReflNode::GetMetaBool(const std::string& key) const { const auto& value = GetMeta(key); if (value == "true") { @@ -774,23 +786,24 @@ namespace Mirror { return Assert(false), false; } - int32_t Type::GetMetaInt32(const std::string& key) const + int32_t ReflNode::GetMetaInt32(const std::string& key) const { return std::atoi(GetMeta(key).c_str()); } - int64_t Type::GetMetaInt64(const std::string& key) const + int64_t ReflNode::GetMetaInt64(const std::string& key) const { return std::atoll(GetMeta(key).c_str()); } - float Type::GetMetaFloat(const std::string& key) const + float ReflNode::GetMetaFloat(const std::string& key) const { return std::atof(GetMeta(key).c_str()); } Variable::Variable(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) + , owner(std::move(params.owner)) , memorySize(params.memorySize) , typeInfo(params.typeInfo) , setter(std::move(params.setter)) @@ -805,6 +818,11 @@ namespace Mirror { return GetDyn(); } + const Class* Variable::GetOwner() const + { + return owner.IsNull() ? nullptr : Class::Find(owner); + } + const TypeInfo* Variable::GetTypeInfo() const { return typeInfo; @@ -821,7 +839,8 @@ namespace Mirror { } Function::Function(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) + , owner(std::move(params.owner)) , argsNum(params.argsNum) , retTypeInfo(params.retTypeInfo) , argTypeInfos(std::move(params.argTypeInfos)) @@ -831,6 +850,11 @@ namespace Mirror { Function::~Function() = default; + const Class* Function::GetOwner() const + { + return owner.IsNull() ? nullptr : Class::Find(owner); + } + uint8_t Function::GetArgsNum() const { return argsNum; @@ -857,7 +881,8 @@ namespace Mirror { } Constructor::Constructor(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) + , owner(std::move(params.owner)) , argsNum(params.argsNum) , argTypeInfos(std::move(params.argTypeInfos)) , argRemoveRefTypeInfos(std::move(params.argRemoveRefTypeInfos)) @@ -869,6 +894,11 @@ namespace Mirror { Constructor::~Constructor() = default; + const Class* Constructor::GetOwner() const + { + return owner.IsNull() ? nullptr : Class::Find(owner); + } + uint8_t Constructor::GetArgsNum() const { return argsNum; @@ -915,7 +945,7 @@ namespace Mirror { } Destructor::Destructor(ConstructParams&& params) - : Type(std::string(NamePresets::detor.name)) + : ReflNode(std::string(IdPresets::detor.name)) , destructor(std::move(params.destructor)) { } @@ -928,7 +958,8 @@ namespace Mirror { } MemberVariable::MemberVariable(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) + , owner(std::move(params.owner)) , memorySize(params.memorySize) , typeInfo(params.typeInfo) , setter(std::move(params.setter)) @@ -938,6 +969,11 @@ namespace Mirror { MemberVariable::~MemberVariable() = default; + const Class* MemberVariable::GetOwner() const + { + return owner.IsNull() ? nullptr : Class::Find(owner); + } + uint32_t MemberVariable::SizeOf() const { return memorySize; @@ -964,7 +1000,8 @@ namespace Mirror { } MemberFunction::MemberFunction(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) + , owner(std::move(params.owner)) , argsNum(params.argsNum) , retTypeInfo(params.retTypeInfo) , argTypeInfos(std::move(params.argTypeInfos)) @@ -974,6 +1011,11 @@ namespace Mirror { MemberFunction::~MemberFunction() = default; + const Class* MemberFunction::GetOwner() const + { + return owner.IsNull() ? nullptr : Class::Find(owner); + } + uint8_t MemberFunction::GetArgsNum() const { return argsNum; @@ -999,7 +1041,7 @@ namespace Mirror { return invoker(object, arguments); } - GlobalScope::GlobalScope() : Type(std::string(NamePresets::globalScope.name)) {} + GlobalScope::GlobalScope() : ReflNode(std::string(IdPresets::globalScope.name)) {} GlobalScope::~GlobalScope() = default; @@ -1075,7 +1117,7 @@ namespace Mirror { std::unordered_map Class::typeToIdMap = {}; Class::Class(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) , typeInfo(params.typeInfo) , baseClassGetter(std::move(params.baseClassGetter)) { @@ -1084,7 +1126,7 @@ namespace Mirror { destructor = Destructor(std::move(params.destructorParams.value())); } if (params.defaultConstructorParams.has_value()) { - EmplaceConstructor(NamePresets::defaultCtor, std::move(params.defaultConstructorParams.value())); + EmplaceConstructor(IdPresets::defaultCtor, std::move(params.defaultConstructorParams.value())); } } @@ -1262,7 +1304,7 @@ namespace Mirror { bool Class::HasDefaultConstructor() const { - return HasConstructor(NamePresets::defaultCtor); + return HasConstructor(IdPresets::defaultCtor); } const Class* Class::GetBaseClass() const @@ -1289,12 +1331,12 @@ namespace Mirror { const Constructor* Class::FindDefaultConstructor() const { - return FindConstructor(NamePresets::defaultCtor); + return FindConstructor(IdPresets::defaultCtor); } const Constructor& Class::GetDefaultConstructor() const { - return GetConstructor(NamePresets::defaultCtor); + return GetConstructor(IdPresets::defaultCtor); } bool Class::HasDestructor() const @@ -1461,7 +1503,8 @@ namespace Mirror { } EnumValue::EnumValue(ConstructParams&& inParams) - : Type(std::move(inParams.name)) + : ReflNode(std::move(inParams.id)) + , owner(std::move(inParams.owner)) , getter(std::move(inParams.getter)) , integralGetter(std::move(inParams.integralGetter)) , setter(std::move(inParams.setter)) @@ -1481,6 +1524,11 @@ namespace Mirror { return GetIntegralDyn(); } + const Enum* EnumValue::GetOwner() const + { + return owner.IsNull() ? nullptr : Enum::Find(owner); + } + Any EnumValue::GetDyn() const { return getter(); @@ -1519,7 +1567,7 @@ namespace Mirror { std::unordered_map Enum::typeToIdMap = {}; Enum::Enum(ConstructParams&& params) - : Type(std::move(params.name)) + : ReflNode(std::move(params.id)) , typeInfo(params.typeInfo) { } From 1377b368c2968b856936458834ff08c7857c24ce Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Thu, 10 Oct 2024 21:13:40 +0800 Subject: [PATCH 6/7] feat: support serialization for mirror reflect node --- Engine/Source/Mirror/Include/Mirror/Mirror.h | 728 +++++++++++++++++- .../Source/Mirror/Include/Mirror/Registry.h | 1 + Engine/Source/Mirror/Src/Mirror.cpp | 76 ++ .../Source/Mirror/Test/SerializationTest.cpp | 164 +++- Engine/Source/Mirror/Test/SerializationTest.h | 12 + Tool/MirrorTool/Src/Generator.cpp | 2 +- 6 files changed, 928 insertions(+), 55 deletions(-) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 450c6208..08e25a7e 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -391,6 +391,8 @@ namespace Mirror { template void Set(T&& value) const; Any Get() const; + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; const Class* GetOwner() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& inArgument) const; @@ -427,6 +429,8 @@ namespace Mirror { public: ~Function() override; + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; const Class* GetOwner() const; template Any Invoke(Args&&... args) const; uint8_t GetArgsNum() const; @@ -468,6 +472,8 @@ namespace Mirror { template Any Construct(Args&&... args) const; template Any New(Args&&... args) const; + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; const Class* GetOwner() const; uint8_t GetArgsNum() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; @@ -514,6 +520,10 @@ namespace Mirror { ~Destructor() override; template void Invoke(C&& object) const; + + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; + const Class* GetOwner() const; void InvokeDyn(const Argument& argument) const; private: @@ -524,11 +534,13 @@ namespace Mirror { using Invoker = std::function; struct ConstructParams { + Id owner; Invoker destructor; }; explicit Destructor(ConstructParams&& params); + Id owner; Invoker destructor; }; @@ -539,6 +551,8 @@ namespace Mirror { template void Set(C&& object, T&& value) const; template Any Get(C&& object) const; + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; const Class* GetOwner() const; uint32_t SizeOf() const; const TypeInfo* GetTypeInfo() const; @@ -577,6 +591,8 @@ namespace Mirror { template Any Invoke(C&& object, Args&&... args) const; + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; const Class* GetOwner() const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; @@ -749,6 +765,8 @@ namespace Mirror { template void Set(E& value) const; template bool Compare(const E& value) const; + const std::string& GetOwnerName() const; + const Id& GetOwnerId() const; const Enum* GetOwner() const; Any GetDyn() const; IntegralValue GetIntegralDyn() const; @@ -914,6 +932,10 @@ namespace Common { // NOLINT stream.Seek(static_cast(sizeof(uint64_t) * (memberVariableCount + 1))); uint64_t memberVariableContentSize = 0; for (const auto& memberVariable : memberVariables | std::views::values) { + if (memberVariable.IsTransient()) { + continue; + } + const bool sameAsDefaultObject = defaultObject.Empty() || !memberVariable.GetTypeInfo()->equalComparable ? false : memberVariable.GetDyn(obj) == memberVariable.GetDyn(defaultObject); @@ -1054,6 +1076,282 @@ namespace Common { // NOLINT } }; + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::Variable*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::Variable* value) + { + std::string ownerName; + std::string name; + + if (value != nullptr) { + ownerName = value->GetOwnerName(); + name = value->GetName(); + } + + size_t serialized = 0; + serialized += Serializer::Serialize(stream, ownerName); + serialized += Serializer::Serialize(stream, name); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::Variable*& value) + { + std::string ownerName; + std::string name; + + size_t deserialized = 0; + deserialized += Serializer::Deserialize(stream, ownerName); + deserialized += Serializer::Deserialize(stream, name); + + if (const Mirror::Class* owner = Mirror::Class::Find(ownerName); + owner != nullptr) { + value = owner->FindStaticVariable(name); + } else { + value = Mirror::GlobalScope::Get().FindVariable(name); + } + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::Function*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::Function* value) + { + std::string ownerName; + std::string name; + + if (value != nullptr) { + ownerName = value->GetOwnerName(); + name = value->GetName(); + } + + size_t serialized = 0; + serialized += Serializer::Serialize(stream, ownerName); + serialized += Serializer::Serialize(stream, name); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::Function*& value) + { + std::string ownerName; + std::string name; + + size_t deserialized = 0; + deserialized += Serializer::Deserialize(stream, ownerName); + deserialized += Serializer::Deserialize(stream, name); + + if (const Mirror::Class* owner = Mirror::Class::Find(ownerName); + owner != nullptr) { + value = owner->FindStaticFunction(name); + } else { + value = Mirror::GlobalScope::Get().FindFunction(name); + } + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::Constructor*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::Constructor* value) + { + std::string ownerName; + std::string name; + + if (value != nullptr) { + ownerName = value->GetOwnerName(); + name = value->GetName(); + } + + size_t serialized = 0; + serialized += Serializer::Serialize(stream, ownerName); + serialized += Serializer::Serialize(stream, name); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::Constructor*& value) + { + std::string ownerName; + std::string name; + + size_t deserialized = 0; + deserialized += Serializer::Deserialize(stream, ownerName); + deserialized += Serializer::Deserialize(stream, name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + value = owner != nullptr ? owner->FindConstructor(name) : nullptr; + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::Destructor*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::Destructor* value) + { + const std::string ownerName = value != nullptr ? value->GetOwnerName() : ""; + return Serializer::Serialize(stream, ownerName); + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::Destructor*& value) + { + std::string ownerName; + const size_t deserialized = Serializer::Deserialize(stream, ownerName); + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + value = owner != nullptr ? &owner->GetDestructor() : nullptr; + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::MemberVariable*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::MemberVariable* value) + { + std::string ownerName; + std::string name; + + if (value != nullptr) { + ownerName = value->GetOwnerName(); + name = value->GetName(); + } + + size_t serialized = 0; + serialized += Serializer::Serialize(stream, ownerName); + serialized += Serializer::Serialize(stream, name); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::MemberVariable*& value) + { + std::string ownerName; + std::string name; + + size_t deserialized = 0; + deserialized += Serializer::Deserialize(stream, ownerName); + deserialized += Serializer::Deserialize(stream, name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + value = owner != nullptr ? owner->FindMemberVariable(name) : nullptr; + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::MemberFunction*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::MemberFunction* value) + { + std::string ownerName; + std::string name; + + if (value != nullptr) { + ownerName = value->GetOwnerName(); + name = value->GetName(); + } + + size_t serialized = 0; + serialized += Serializer::Serialize(stream, ownerName); + serialized += Serializer::Serialize(stream, name); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::MemberFunction*& value) + { + std::string ownerName; + std::string name; + + size_t deserialized = 0; + deserialized += Serializer::Deserialize(stream, ownerName); + deserialized += Serializer::Deserialize(stream, name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + value = owner != nullptr ? owner->FindMemberFunction(name) : nullptr; + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::Class*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::Class* value) + { + const std::string name = value != nullptr ? value->GetName() : ""; + return Serializer::Serialize(stream, name); + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::Class*& value) + { + std::string name; + const size_t deserialized = Serializer::Deserialize(stream, name); + value = Mirror::Class::Find(name); + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::EnumValue*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::EnumValue* value) + { + std::string ownerName; + std::string name; + + if (value != nullptr) { + ownerName = value->GetOwnerName(); + name = value->GetName(); + } + + size_t serialized = 0; + serialized += Serializer::Serialize(stream, ownerName); + serialized += Serializer::Serialize(stream, name); + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::EnumValue*& value) + { + std::string ownerName; + std::string name; + + size_t deserialized = 0; + deserialized += Serializer::Deserialize(stream, ownerName); + deserialized += Serializer::Deserialize(stream, name); + + const Mirror::Enum* owner = Mirror::Enum::Find(ownerName); + value = owner != nullptr ? owner->FindValue(name) : nullptr; + return deserialized; + } + }; + + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("const Mirror::Enum*"); + + static size_t Serialize(BinarySerializeStream& stream, const Mirror::Enum* value) + { + const std::string name = value != nullptr ? value->GetName() : ""; + return Serializer::Serialize(stream, name); + } + + static size_t Deserialize(BinaryDeserializeStream& stream, const Mirror::Enum*& value) + { + std::string name; + const size_t deserialized = Serializer::Deserialize(stream, name); + value = Mirror::Enum::Find(name); + return deserialized; + } + }; + template struct JsonSerializer { static void JsonSerializeDyn(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Class& clazz, const Mirror::Argument& inObj) @@ -1076,13 +1374,18 @@ namespace Common { // NOLINT rapidjson::Value membersJson; membersJson.SetArray(); membersJson.Reserve(memberVariables.size(), inAllocator); - for (const auto& member : memberVariables | std::views::values) { + + for (const auto& memberVariable : memberVariables | std::views::values) { + if (memberVariable.IsTransient()) { + continue; + } + rapidjson::Value memberNameJson; - JsonSerializer::JsonSerialize(memberNameJson, inAllocator, member.GetName()); + JsonSerializer::JsonSerialize(memberNameJson, inAllocator, memberVariable.GetName()); - bool sameAsDefault = defaultObject.Empty() || !member.GetTypeInfo()->equalComparable + bool sameAsDefault = defaultObject.Empty() || !memberVariable.GetTypeInfo()->equalComparable ? false - : member.GetDyn(inObj) == member.GetDyn(defaultObject); + : memberVariable.GetDyn(inObj) == memberVariable.GetDyn(defaultObject); rapidjson::Value memberSameAsDefaultJson; JsonSerializer::JsonSerialize(memberSameAsDefaultJson, inAllocator, sameAsDefault); @@ -1091,7 +1394,7 @@ namespace Common { // NOLINT if (sameAsDefault) { memberContentJson.SetNull(); } else { - member.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); + memberVariable.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); } rapidjson::Value memberJson; @@ -1184,11 +1487,11 @@ namespace Common { // NOLINT template struct JsonSerializer { - static void JsonSerialize(rapidjson::Value& outValue, rapidjson::Document::AllocatorType& inAllocator, const E& inValue) + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const E& inValue) { if (const Mirror::Enum* metaEnum = Mirror::Enum::Find(); metaEnum == nullptr) { - JsonSerializer>::JsonSerialize(outValue, inAllocator, static_cast>(inValue)); + JsonSerializer>::JsonSerialize(outJsonValue, inAllocator, static_cast>(inValue)); } else { const Mirror::EnumValue& metaEnumValue = metaEnum->GetValue(inValue); @@ -1198,23 +1501,23 @@ namespace Common { // NOLINT rapidjson::Value valueNameJson; JsonSerializer::JsonSerialize(valueNameJson, inAllocator, metaEnumValue.GetName()); - outValue.SetArray(); - outValue.PushBack(enumNameJson, inAllocator); - outValue.PushBack(valueNameJson, inAllocator); + outJsonValue.SetArray(); + outJsonValue.PushBack(enumNameJson, inAllocator); + outJsonValue.PushBack(valueNameJson, inAllocator); } } - static void JsonDeserialize(const rapidjson::Value& inValue, E& outValue) + static void JsonDeserialize(const rapidjson::Value& inJsonValue, E& outValue) { - if (inValue.IsArray()) { - if (inValue.Size() != 2) { + if (inJsonValue.IsArray()) { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { return; } std::string metaEnumName; std::string metaEnumValueName; - JsonSerializer::JsonDeserialize(inValue[0], metaEnumName); - JsonSerializer::JsonDeserialize(inValue[1], metaEnumValueName); + JsonSerializer::JsonDeserialize(inJsonValue[0], metaEnumName); + JsonSerializer::JsonDeserialize(inJsonValue[1], metaEnumValueName); const Mirror::Enum* aspectMetaEnum = Mirror::Enum::Find(metaEnumName); const Mirror::Enum* metaEnum = Mirror::Enum::Find(); @@ -1229,12 +1532,296 @@ namespace Common { // NOLINT metaEnumValue->Set(outValue); } else { std::underlying_type_t unlderlyingValue; - JsonSerializer>::JsonDeserialize(inValue, unlderlyingValue); + JsonSerializer>::JsonDeserialize(inJsonValue, unlderlyingValue); outValue = static_cast(unlderlyingValue); } } }; + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Variable* inValue) + { + std::string ownerName; + std::string name; + + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + + rapidjson::Value ownerNameJson; + JsonSerializer::JsonSerialize(ownerNameJson, inAllocator, ownerName); + + rapidjson::Value nameJson; + JsonSerializer::JsonSerialize(nameJson, inAllocator, name); + + outJsonValue.SetArray(); + outJsonValue.PushBack(ownerNameJson, inAllocator); + outJsonValue.PushBack(nameJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::Variable*& outValue) + { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { + return; + } + + std::string ownerName; + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue[0], ownerName); + JsonSerializer::JsonDeserialize(inJsonValue[1], name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + outValue = owner != nullptr ? owner->FindStaticVariable(name) : Mirror::GlobalScope::Get().FindVariable(name); + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Function* inValue) + { + std::string ownerName; + std::string name; + + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + + rapidjson::Value ownerNameJson; + JsonSerializer::JsonSerialize(ownerNameJson, inAllocator, ownerName); + + rapidjson::Value nameJson; + JsonSerializer::JsonSerialize(nameJson, inAllocator, name); + + outJsonValue.SetArray(); + outJsonValue.PushBack(ownerNameJson, inAllocator); + outJsonValue.PushBack(nameJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::Function*& outValue) + { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { + return; + } + + std::string ownerName; + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue[0], ownerName); + JsonSerializer::JsonDeserialize(inJsonValue[1], name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + outValue = owner != nullptr ? owner->FindStaticFunction(name) : Mirror::GlobalScope::Get().FindFunction(name); + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Constructor* inValue) + { + std::string ownerName; + std::string name; + + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + + rapidjson::Value ownerNameJson; + JsonSerializer::JsonSerialize(ownerNameJson, inAllocator, ownerName); + + rapidjson::Value nameJson; + JsonSerializer::JsonSerialize(nameJson, inAllocator, name); + + outJsonValue.SetArray(); + outJsonValue.PushBack(ownerNameJson, inAllocator); + outJsonValue.PushBack(nameJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::Constructor*& outValue) + { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { + return; + } + + std::string ownerName; + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue[0], ownerName); + JsonSerializer::JsonDeserialize(inJsonValue[1], name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + outValue = owner != nullptr ? owner->FindConstructor(name) : nullptr; + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Destructor* inValue) + { + const std::string ownerName = inValue != nullptr ? inValue->GetOwnerName() : ""; + JsonSerializer::JsonSerialize(outJsonValue, inAllocator, ownerName); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::Destructor*& outValue) + { + std::string ownerName; + JsonSerializer::JsonDeserialize(inJsonValue, ownerName); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + outValue = owner != nullptr ? &owner->GetDestructor() : nullptr; + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::MemberVariable* inValue) + { + std::string ownerName; + std::string name; + + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + + rapidjson::Value ownerNameJson; + JsonSerializer::JsonSerialize(ownerNameJson, inAllocator, ownerName); + + rapidjson::Value nameJson; + JsonSerializer::JsonSerialize(nameJson, inAllocator, name); + + outJsonValue.SetArray(); + outJsonValue.PushBack(ownerNameJson, inAllocator); + outJsonValue.PushBack(nameJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::MemberVariable*& outValue) + { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { + return; + } + + std::string ownerName; + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue[0], ownerName); + JsonSerializer::JsonDeserialize(inJsonValue[1], name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + outValue = owner != nullptr ? owner->FindMemberVariable(name) : nullptr; + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::MemberFunction* inValue) + { + std::string ownerName; + std::string name; + + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + + rapidjson::Value ownerNameJson; + JsonSerializer::JsonSerialize(ownerNameJson, inAllocator, ownerName); + + rapidjson::Value nameJson; + JsonSerializer::JsonSerialize(nameJson, inAllocator, name); + + outJsonValue.SetArray(); + outJsonValue.PushBack(ownerNameJson, inAllocator); + outJsonValue.PushBack(nameJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::MemberFunction*& outValue) + { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { + return; + } + + std::string ownerName; + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue[0], ownerName); + JsonSerializer::JsonDeserialize(inJsonValue[1], name); + + const Mirror::Class* owner = Mirror::Class::Find(ownerName); + outValue = owner != nullptr ? owner->FindMemberFunction(name) : nullptr; + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Class* inValue) + { + const std::string name = inValue != nullptr ? inValue->GetName() : ""; + JsonSerializer::JsonSerialize(outJsonValue, inAllocator, name); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::Class*& outValue) + { + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue, name); + outValue = Mirror::Class::Find(name); + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::EnumValue* inValue) + { + std::string ownerName; + std::string name; + + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + + rapidjson::Value ownerNameJson; + JsonSerializer::JsonSerialize(ownerNameJson, inAllocator, ownerName); + + rapidjson::Value nameJson; + JsonSerializer::JsonSerialize(nameJson, inAllocator, name); + + outJsonValue.SetArray(); + outJsonValue.PushBack(ownerNameJson, inAllocator); + outJsonValue.PushBack(nameJson, inAllocator); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::EnumValue*& outValue) + { + if (!inJsonValue.IsArray() || inJsonValue.Size() != 2) { + return; + } + + std::string ownerName; + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue[0], ownerName); + JsonSerializer::JsonDeserialize(inJsonValue[1], name); + + const Mirror::Enum* owner = Mirror::Enum::Find(ownerName); + outValue = owner != nullptr ? owner->FindValue(name) : nullptr; + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Enum* inValue) + { + const std::string name = inValue != nullptr ? inValue->GetName() : ""; + JsonSerializer::JsonSerialize(outJsonValue, inAllocator, name); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, const Mirror::Enum*& outValue) + { + std::string name; + JsonSerializer::JsonDeserialize(inJsonValue, name); + outValue = Mirror::Enum::Find(name); + } + }; + template struct StringConverter { static std::string ToStringDyn(const Mirror::Class& clazz, const Mirror::Argument& argument) @@ -1276,7 +1863,114 @@ namespace Common { // NOLINT } }; - // TODO Type class serialization/tostring/tojson + template <> + struct StringConverter { + static std::string ToString(const Mirror::Variable* inValue) + { + std::string ownerName; + std::string name; + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + return fmt::format("{}{}{}", ownerName, ownerName.empty() ? "" : ":", name); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::Variable* inValue) + { + std::string ownerName; + std::string name; + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + return fmt::format("{}{}{}{}", ownerName, ownerName.empty() ? "" : ":", name, name.empty() ? "" : "()"); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::Constructor* inValue) + { + std::string ownerName; + std::string name; + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + return fmt::format("{}::{}({})", ownerName, StringUtils::AfterLast(ownerName, "::"), name); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::Destructor* inValue) + { + const std::string ownerName = inValue != nullptr ? inValue->GetOwnerName() : ""; + return fmt::format("{}::~{}()", ownerName, StringUtils::AfterLast(ownerName, "::")); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::MemberVariable* inValue) + { + std::string ownerName; + std::string name; + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + return fmt::format("{}::{}", ownerName, name); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::MemberFunction* inValue) + { + std::string ownerName; + std::string name; + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + return fmt::format("{}::{}()", ownerName, name); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::Class* inValue) + { + return inValue != nullptr ? inValue->GetName() : ""; + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::EnumValue* inValue) + { + std::string ownerName; + std::string name; + if (inValue != nullptr) { + ownerName = inValue->GetOwnerName(); + name = inValue->GetName(); + } + return fmt::format("{}::{}", ownerName, name); + } + }; + + template <> + struct StringConverter { + static std::string ToString(const Mirror::Enum* inValue) + { + return inValue != nullptr ? inValue->GetName() : ""; + } + }; } namespace Mirror { diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 6bf991c8..6b9f2cc4 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -497,6 +497,7 @@ namespace Mirror { } if constexpr (std::is_destructible_v) { Destructor::ConstructParams detorParams; + detorParams.owner = inId; detorParams.destructor = [](const Argument& object) -> void { Assert(!object.IsConstRef()); object.As().~C(); diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 5e25ccca..9e66f654 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -818,6 +818,16 @@ namespace Mirror { return GetDyn(); } + const std::string& Variable::GetOwnerName() const + { + return owner.name; + } + + const Id& Variable::GetOwnerId() const + { + return owner; + } + const Class* Variable::GetOwner() const { return owner.IsNull() ? nullptr : Class::Find(owner); @@ -850,6 +860,16 @@ namespace Mirror { Function::~Function() = default; + const std::string& Function::GetOwnerName() const + { + return owner.name; + } + + const Id& Function::GetOwnerId() const + { + return owner; + } + const Class* Function::GetOwner() const { return owner.IsNull() ? nullptr : Class::Find(owner); @@ -894,6 +914,16 @@ namespace Mirror { Constructor::~Constructor() = default; + const std::string& Constructor::GetOwnerName() const + { + return owner.name; + } + + const Id& Constructor::GetOwnerId() const + { + return owner; + } + const Class* Constructor::GetOwner() const { return owner.IsNull() ? nullptr : Class::Find(owner); @@ -946,12 +976,28 @@ namespace Mirror { Destructor::Destructor(ConstructParams&& params) : ReflNode(std::string(IdPresets::detor.name)) + , owner(std::move(params.owner)) , destructor(std::move(params.destructor)) { } Destructor::~Destructor() = default; + const std::string& Destructor::GetOwnerName() const + { + return owner.name; + } + + const Id& Destructor::GetOwnerId() const + { + return owner; + } + + const Class* Destructor::GetOwner() const + { + return owner.IsNull() ? nullptr : Class::Find(owner); + } + void Destructor::InvokeDyn(const Argument& argument) const { destructor(argument); @@ -969,6 +1015,16 @@ namespace Mirror { MemberVariable::~MemberVariable() = default; + const std::string& MemberVariable::GetOwnerName() const + { + return owner.name; + } + + const Id& MemberVariable::GetOwnerId() const + { + return owner; + } + const Class* MemberVariable::GetOwner() const { return owner.IsNull() ? nullptr : Class::Find(owner); @@ -1011,6 +1067,16 @@ namespace Mirror { MemberFunction::~MemberFunction() = default; + const std::string& MemberFunction::GetOwnerName() const + { + return owner.name; + } + + const Id& MemberFunction::GetOwnerId() const + { + return owner; + } + const Class* MemberFunction::GetOwner() const { return owner.IsNull() ? nullptr : Class::Find(owner); @@ -1524,6 +1590,16 @@ namespace Mirror { return GetIntegralDyn(); } + const std::string& EnumValue::GetOwnerName() const + { + return owner.name; + } + + const Id& EnumValue::GetOwnerId() const + { + return owner; + } + const Enum* EnumValue::GetOwner() const { return owner.IsNull() ? nullptr : Enum::Find(owner); diff --git a/Engine/Source/Mirror/Test/SerializationTest.cpp b/Engine/Source/Mirror/Test/SerializationTest.cpp index 28a09923..637628d5 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.cpp +++ b/Engine/Source/Mirror/Test/SerializationTest.cpp @@ -4,17 +4,36 @@ #include -#include +#include +#include +#include #include #include -int ga = 0; -float gb = 0.0f; -std::string gc; +int ga = 1; +float gb = 2.0f; +std::string gc = "3"; + +int gf(int a, int b) +{ + return a + b; +} + +int SerializationTestStruct3::ga = 1; + +int SerializationTestStruct3::gf(int a, int b) +{ + return a + b; +} + +int SerializationTestStruct3::f() const // NOLINT +{ + return 1; +} template -void PerformMetaObjectSerializationTest(const std::filesystem::path& fileName, const T& object) +void PerformSerializationTest(const std::filesystem::path& fileName, const T& object) { std::filesystem::create_directories(fileName.parent_path()); { @@ -31,6 +50,40 @@ void PerformMetaObjectSerializationTest(const std::filesystem::path& fileName, c } } +template +void PerformJsonSerializationTest(const T& inValue, const std::string& inExceptJson) +{ + std::string json; + { + rapidjson::Document document; + + rapidjson::Value jsonValue; + Common::JsonSerialize(jsonValue, document.GetAllocator(), inValue); + document.CopyFrom(jsonValue, document.GetAllocator()); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + json = std::string(buffer.GetString(), buffer.GetSize()); + if (!inExceptJson.empty()) { + ASSERT_EQ(json, inExceptJson); + } + } + + { + rapidjson::Document document; + document.Parse(json.c_str()); + + rapidjson::Value jsonValue; + jsonValue.CopyFrom(document, document.GetAllocator()); + + T value; + Common::JsonDeserialize(jsonValue, value); + ASSERT_EQ(inValue, value); + } +} + TEST(SerializationTest, VariableFileTest) { static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.VariableFileSerializationTest.bin"; @@ -69,7 +122,7 @@ TEST(SerializationTest, VariableFileTest) TEST(SerializationTest, ClassFileTest) { - PerformMetaObjectSerializationTest( + PerformSerializationTest( "../Test/Generated/Mirror/SerializationTest.ClassFileSerializationTest.bin", SerializationTestStruct0 { 1, 2, "3.0" }); } @@ -83,62 +136,99 @@ TEST(SerializationTest, ContainerFileTest) obj.d = { { false, true }, { true, false } }; obj.e = { { 1, 2.0f, "3" } }; - PerformMetaObjectSerializationTest( + PerformSerializationTest( "../Test/Generated/Mirror/SerializationTest.ContainerFileSerializationTest.bin", obj); } TEST(SerializationTest, MetaObjectWithBaseClassTest) { - PerformMetaObjectSerializationTest( + PerformSerializationTest( "../Test/Generated/Mirror/SerializationTest.MetaObjectWithBaseClassTest.bin", SerializationTestStruct2 { { 1, 2, "3.0" }, 4.0 }); } TEST(SerializationTest, EnumSerializationTest) { - static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.EnumSerializationTest.bin"; - std::filesystem::create_directories(fileName.parent_path()); - - { - Common::BinaryFileSerializeStream stream(fileName.string()); - Serialize(stream, SerializationTestEnum::b); - } - - { - Common::BinaryFileDeserializeStream stream(fileName.string()); - SerializationTestEnum metaEnum; - Deserialize(stream, metaEnum); - ASSERT_EQ(metaEnum, SerializationTestEnum::b); - } + PerformSerializationTest( + "../Test/Generated/Mirror/SerializationTest.EnumSerializationTest.bin", + SerializationTestEnum::b); } -TEST(SerializationTest, MetaTypeSerializationTest) +TEST(SerializationTest, ReflNodeSerializationTest) { - // TODO + static std::filesystem::path fileName = "../Test/Generated/Mirror/SerializationTest.MetaTypeSerializationTest.bin"; + + const auto& globalScope = GlobalScope::Get(); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &globalScope.GetVariable("ga")); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &globalScope.GetFunction("gf")); + + const auto* clazz = &Class::Get(); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, clazz); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &clazz->GetDefaultConstructor()); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &clazz->GetDestructor()); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &clazz->GetStaticVariable("ga")); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &clazz->GetStaticFunction("gf")); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &clazz->GetMemberVariable("a")); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &clazz->GetMemberFunction("f")); + + const auto* enun = &Enum::Get(); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, enun); + PerformSerializationTest(fileName, nullptr); + PerformSerializationTest(fileName, &enun->GetValue("a")); } TEST(SerializationTest, MetaObjectJsonSerializationTest) { - // TODO + PerformJsonSerializationTest( + SerializationTestStruct2 { { 1, 2, "3.0" }, 4.0 }, + R"({"className":"SerializationTestStruct2","baseClass":{"className":"SerializationTestStruct0","baseClass":null,"members":[{"memberName":"a","sameAsDefault":false,"content":1},{"memberName":"b","sameAsDefault":false,"content":2.0},{"memberName":"c","sameAsDefault":false,"content":"3.0"}]},"members":[{"memberName":"d","sameAsDefault":false,"content":4.0}]})"); } TEST(SerializationTest, EnumJsonSerializationTest) { - // TODO + PerformJsonSerializationTest( + SerializationTestEnum::b, + R"(["SerializationTestEnum","b"])"); } TEST(SerializationTest, MetaTypeJsonSerializationTest) { - // TODO -} - -TEST(SerializationTest, TransientTest) -{ - // TODO -} - -TEST(SerializationTest, CallbackTest) -{ - // TODO + const auto& globalScope = GlobalScope::Get(); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&globalScope.GetVariable("ga"), R"(["","ga"])"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&globalScope.GetFunction("gf"), R"(["","gf"])"); + + const auto* clazz = &Class::Get(); + PerformJsonSerializationTest(nullptr, R"("")"); + PerformJsonSerializationTest(clazz, R"("SerializationTestStruct3")"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&clazz->GetDefaultConstructor(), R"(["SerializationTestStruct3","_defaultCtor"])"); + PerformJsonSerializationTest(nullptr, R"("")"); + PerformJsonSerializationTest(&clazz->GetDestructor(), R"("SerializationTestStruct3")"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&clazz->GetStaticVariable("ga"), R"(["SerializationTestStruct3","ga"])"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&clazz->GetStaticFunction("gf"), R"(["SerializationTestStruct3","gf"])"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&clazz->GetMemberVariable("a"), R"(["SerializationTestStruct3","a"])"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&clazz->GetMemberFunction("f"), R"(["SerializationTestStruct3","f"])"); + + const auto* enun = &Enum::Get(); + PerformJsonSerializationTest(nullptr, R"("")"); + PerformJsonSerializationTest(enun, R"("SerializationTestEnum")"); + PerformJsonSerializationTest(nullptr, R"(["",""])"); + PerformJsonSerializationTest(&enun->GetValue("a"), R"(["SerializationTestEnum","a"])"); } diff --git a/Engine/Source/Mirror/Test/SerializationTest.h b/Engine/Source/Mirror/Test/SerializationTest.h index 0ccd8d06..fdd7784b 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.h +++ b/Engine/Source/Mirror/Test/SerializationTest.h @@ -21,6 +21,8 @@ EProperty() extern int ga; EProperty() extern float gb; EProperty() extern std::string gc; +EFunc() int gf(int a, int b); + struct EClass() SerializationTestStruct0 { EClassBody(SerializationTestStruct0) @@ -60,3 +62,13 @@ struct EClass() SerializationTestStruct2 : SerializationTestStruct0 { EProperty() double d; }; + +struct EClass() SerializationTestStruct3 { + EClassBody(SerializationTestStruct3) + + EProperty() static int ga; + EFunc() static int gf(int a, int b); + + EProperty() int a; + EFunc() int f() const; +}; diff --git a/Tool/MirrorTool/Src/Generator.cpp b/Tool/MirrorTool/Src/Generator.cpp index ba559718..d8584fb6 100644 --- a/Tool/MirrorTool/Src/Generator.cpp +++ b/Tool/MirrorTool/Src/Generator.cpp @@ -216,7 +216,7 @@ namespace MirrorTool { stream << "{"; stream << GetNamespaceGlobalCode(metaInfo.global); for (const auto& ns : metaInfo.namespaces) { - stream << GetNamespaceEnumsCode(ns); + stream << GetNamespaceGlobalCode(ns); } stream << Common::newline; stream << Common::tab<1> << "return 0;" << Common::newline; From 6d401d95e5f86d71cbf141b575472d908d1c86d1 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Fri, 11 Oct 2024 19:03:19 +0800 Subject: [PATCH 7/7] refactor: misc refactor and fixup --- Engine/Source/Common/Test/StringTest.cpp | 3 - Engine/Source/Mirror/Include/Mirror/Meta.h | 11 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 72 ++++----- .../Source/Mirror/Include/Mirror/Registry.h | 38 ++--- .../Source/Mirror/Test/SerializationTest.cpp | 7 - Engine/Source/RHI-Vulkan/CMakeLists.txt | 7 + Engine/Source/Runtime/Include/Runtime/World.h | 150 ++++-------------- Engine/Source/Runtime/Src/World.cpp | 128 ++++++++------- Engine/Source/Runtime/Test/WorldTest.cpp | 68 ++++---- Engine/Source/Runtime/Test/WorldTest.h | 49 +++--- Tool/MirrorTool/Src/Generator.cpp | 5 + Tool/MirrorTool/Src/Parser.cpp | 2 +- 12 files changed, 230 insertions(+), 310 deletions(-) diff --git a/Engine/Source/Common/Test/StringTest.cpp b/Engine/Source/Common/Test/StringTest.cpp index 900b86aa..4a119489 100644 --- a/Engine/Source/Common/Test/StringTest.cpp +++ b/Engine/Source/Common/Test/StringTest.cpp @@ -136,7 +136,4 @@ TEST(StringUtilsTest, ToStringTest) const std::set v7 = { 1, 2, 3 }; ASSERT_EQ(Common::ToString(v7), "(1, 2, 3)"); - - const std::unordered_map v8 = { { 1, false }, { 2, true } }; - ASSERT_EQ(Common::ToString(v8), "{1: false, 2: true}"); } diff --git a/Engine/Source/Mirror/Include/Mirror/Meta.h b/Engine/Source/Mirror/Include/Mirror/Meta.h index b5996bc2..39bb2e22 100644 --- a/Engine/Source/Mirror/Include/Mirror/Meta.h +++ b/Engine/Source/Mirror/Include/Mirror/Meta.h @@ -22,9 +22,16 @@ namespace Mirror { class Class; } -// TODO maybe need virtual const Mirror::Class& GetClass() ? #define EClassBody(className) \ private: \ static int _mirrorRegistry; \ public: \ - static const Mirror::Class& GetClass(); \ + static const Mirror::Class& GetStaticClass(); \ + const Mirror::Class& GetClass(); \ + +#define EPolyClassBody(className) \ +private: \ + static int _mirrorRegistry; \ +public: \ + static const Mirror::Class& GetStaticClass(); \ + virtual const Mirror::Class& GetClass(); \ diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 08e25a7e..8f2d8875 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -847,7 +847,11 @@ namespace Mirror { std::unordered_map values; }; - template concept MetaClass = requires(T inValue) { { T::GetClass() } -> std::same_as; }; + template concept MetaClass = requires(T inValue) + { + { T::GetStaticClass() } -> std::same_as; + { inValue.GetClass() } -> std::same_as; + }; } namespace Mirror::Internal { @@ -861,30 +865,31 @@ namespace Mirror::Internal { } template - Argument ForwardAsArgument(T&& value) + Any ForwardAsAny(T&& value) { StaticCheckArgumentType(); if constexpr (std::is_lvalue_reference_v) { - return { Any(std::ref(std::forward(value))) }; + return { std::ref(std::forward(value)) }; } else { - return { Any(std::forward(value)) }; + return { std::forward(value) }; } } + template + Argument ForwardAsArgument(T&& value) + { + StaticCheckArgumentType(); + return ForwardAsAny(std::forward(value)); + } + template ArgumentList ForwardAsArgumentList(Args&&... args) { ArgumentList result; result.reserve(sizeof...(args)); (void) std::initializer_list { ([&]() -> void { - StaticCheckArgumentType(); - - if constexpr (std::is_lvalue_reference_v) { - result.emplace_back(Any(std::ref(std::forward(args)))); - } else { - result.emplace_back(Any(std::forward(args))); - } + result.emplace_back(ForwardAsArgument(std::forward(args))); }(), 0)... }; return result; } @@ -1372,23 +1377,19 @@ namespace Common { // NOLINT } rapidjson::Value membersJson; - membersJson.SetArray(); - membersJson.Reserve(memberVariables.size(), inAllocator); + membersJson.SetObject(); for (const auto& memberVariable : memberVariables | std::views::values) { if (memberVariable.IsTransient()) { continue; } - rapidjson::Value memberNameJson; - JsonSerializer::JsonSerialize(memberNameJson, inAllocator, memberVariable.GetName()); - bool sameAsDefault = defaultObject.Empty() || !memberVariable.GetTypeInfo()->equalComparable ? false : memberVariable.GetDyn(inObj) == memberVariable.GetDyn(defaultObject); - rapidjson::Value memberSameAsDefaultJson; - JsonSerializer::JsonSerialize(memberSameAsDefaultJson, inAllocator, sameAsDefault); + rapidjson::Value memberNameJson; + JsonSerializer::JsonSerialize(memberNameJson, inAllocator, memberVariable.GetName()); rapidjson::Value memberContentJson; if (sameAsDefault) { @@ -1396,13 +1397,7 @@ namespace Common { // NOLINT } else { memberVariable.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); } - - rapidjson::Value memberJson; - memberJson.SetObject(); - memberJson.AddMember("memberName", memberNameJson, inAllocator); - memberJson.AddMember("sameAsDefault", memberSameAsDefaultJson, inAllocator); - memberJson.AddMember("content", memberContentJson, inAllocator); - membersJson.PushBack(memberJson, inAllocator); + membersJson.AddMember(memberNameJson, memberContentJson, inAllocator); } outJsonValue.SetObject(); @@ -1439,38 +1434,27 @@ namespace Common { // NOLINT } const auto& membersJson = inJsonValue["members"]; - if (!membersJson.IsArray()) { + if (!membersJson.IsObject()) { return; } - for (rapidjson::SizeType i = 0; i < membersJson.Size(); i++) { - const auto& memberJson = membersJson[i]; - if (!memberJson.HasMember("memberName")) { - continue; - } - + for (auto iter = membersJson.MemberBegin(); iter != membersJson.MemberEnd(); ++iter) { std::string memberName; - JsonSerializer::JsonDeserialize(memberJson["memberName"], memberName); + JsonSerializer::JsonDeserialize(iter->name, memberName); + if (!clazz.HasMemberVariable(memberName)) { continue; } const auto& memberVariable = clazz.GetMemberVariable(memberName); - bool sameAsDefault = false; - if (memberJson.HasMember("sameAsDefault")) { - JsonSerializer::JsonDeserialize(memberJson["sameAsDefault"], sameAsDefault); - } - if (sameAsDefault) { + if ( const auto& valueJson = iter->value; + valueJson.IsNull()) { if (!defaultObject.Empty()) { memberVariable.SetDyn(outObj, memberVariable.GetDyn(defaultObject)); } - continue; - } - - if (!memberJson.HasMember("content")) { - continue; + } else { + memberVariable.GetDyn(outObj).JsonDeserialize(valueJson); } - memberVariable.GetDyn(outObj).JsonDeserialize(memberJson["content"]); } } diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 6b9f2cc4..a603b312 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -18,10 +18,10 @@ namespace Mirror::Internal { template auto GetArgTypeInfosByArgsTuple(std::index_sequence); template auto ForwardArgumentsListAsTuple(const ArgumentList& args, std::index_sequence); - template auto InvokeFunction(ArgsTuple& args, std::index_sequence); - template auto InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence); - template auto InvokeConstructorStack(ArgsTuple& args, std::index_sequence); - template auto InvokeConstructorNew(ArgsTuple& 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); } namespace Mirror { @@ -82,7 +82,7 @@ namespace Mirror { public: ~EnumRegistry() override; - template EnumRegistry& Value(const Id& inId); + template EnumRegistry& Value(const Id& inId); private: friend class Registry; @@ -166,25 +166,25 @@ namespace Mirror::Internal { } template - auto InvokeFunction(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeFunction(ArgsTuple& args, std::index_sequence) { return Ptr(std::get(args)...); } template - auto InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence) { return (object.*Ptr)(std::get(args)...); } template - auto InvokeConstructorStack(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeConstructorStack(ArgsTuple& args, std::index_sequence) { return Class(std::get(args)...); } template - auto InvokeConstructorNew(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeConstructorNew(ArgsTuple& args, std::index_sequence) { return new Class(std::get(args)...); } @@ -245,12 +245,12 @@ namespace Mirror { params.stackConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); - return { Internal::InvokeConstructorStack(argsTuple, std::make_index_sequence {}) }; + return Internal::ForwardAsAny(Internal::InvokeConstructorStack(argsTuple, 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::InvokeConstructorNew(argsTuple, std::make_index_sequence {}) }; + return Internal::ForwardAsAny(Internal::InvokeConstructorNew(argsTuple, std::make_index_sequence {})); }; return MetaDataRegistry::SetContext(&clazz.EmplaceConstructor(inId, std::move(params))); @@ -310,7 +310,7 @@ namespace Mirror { Internal::InvokeFunction(argsTuple, std::make_index_sequence {}); return {}; } else { - return { Internal::InvokeFunction(argsTuple, std::make_index_sequence {}) }; + return Internal::ForwardAsAny(Internal::InvokeFunction(argsTuple, std::make_index_sequence {})); } }; @@ -373,7 +373,7 @@ namespace Mirror { Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {}); return {}; } else { - return { Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {}) }; + return Internal::ForwardAsAny(Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {})); } }; @@ -431,7 +431,7 @@ namespace Mirror { Internal::InvokeFunction(argsTuple, std::make_index_sequence {}); return {}; } else { - return { Internal::InvokeFunction(argsTuple, std::make_index_sequence {}) }; + return Internal::ForwardAsAny(Internal::InvokeFunction(argsTuple, std::make_index_sequence {})); } }; @@ -448,7 +448,7 @@ namespace Mirror { EnumRegistry::~EnumRegistry() = default; template - template + template EnumRegistry& EnumRegistry::Value(const Id& inId) { const auto iter = enumInfo.values.find(inId); @@ -458,16 +458,16 @@ namespace Mirror { params.id = inId; params.owner = enumInfo.GetId(); params.getter = []() -> Any { - return { Value }; + return { V }; }; params.integralGetter = []() -> EnumValue::IntegralValue { - return static_cast(Value); + return static_cast(V); }; params.setter = [](const Argument& value) -> void { - value.As() = Value; + value.As() = V; }; params.comparer = [](const Argument& value) -> bool { - return value.As() == Value; + return value.As() == V; }; return MetaDataRegistry>::SetContext(&enumInfo.EmplaceElement(inId, std::move(params))); diff --git a/Engine/Source/Mirror/Test/SerializationTest.cpp b/Engine/Source/Mirror/Test/SerializationTest.cpp index 637628d5..e3071bda 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.cpp +++ b/Engine/Source/Mirror/Test/SerializationTest.cpp @@ -188,13 +188,6 @@ TEST(SerializationTest, ReflNodeSerializationTest) PerformSerializationTest(fileName, &enun->GetValue("a")); } -TEST(SerializationTest, MetaObjectJsonSerializationTest) -{ - PerformJsonSerializationTest( - SerializationTestStruct2 { { 1, 2, "3.0" }, 4.0 }, - R"({"className":"SerializationTestStruct2","baseClass":{"className":"SerializationTestStruct0","baseClass":null,"members":[{"memberName":"a","sameAsDefault":false,"content":1},{"memberName":"b","sameAsDefault":false,"content":2.0},{"memberName":"c","sameAsDefault":false,"content":"3.0"}]},"members":[{"memberName":"d","sameAsDefault":false,"content":4.0}]})"); -} - TEST(SerializationTest, EnumJsonSerializationTest) { PerformJsonSerializationTest( diff --git a/Engine/Source/RHI-Vulkan/CMakeLists.txt b/Engine/Source/RHI-Vulkan/CMakeLists.txt index 8b4f63b5..19ba5a95 100644 --- a/Engine/Source/RHI-Vulkan/CMakeLists.txt +++ b/Engine/Source/RHI-Vulkan/CMakeLists.txt @@ -17,3 +17,10 @@ AddLibrary( PUBLIC_INC Include LIB RHI VulkanSDK spirv-cross VulkanMemoryAllocator ${PLATFORM_EXT_LIBS} ) + +# .mm files can not perform unity build with .cpp files +if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set_target_properties( + RHI-Vulkan PROPERTIES + UNITY_BUILD OFF) +endif() diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 7f975cfb..5f9d2bfc 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -21,64 +21,34 @@ namespace Runtime { using Entity = entt::entity; constexpr auto entityNull = entt::null; - struct RUNTIME_API EClass() Component { + class RUNTIME_API EClass() Component { EClassBody(Component) + Component(); }; - struct RUNTIME_API EClass() State { + class RUNTIME_API EClass() State { EClassBody(State) + State(); }; - struct RUNTIME_API EClass() Event { - EClassBody(Event) - }; + class Commands; + + class RUNTIME_API EClass() System { + EPolyClassBody(System) + System(); + virtual ~System(); - struct RUNTIME_API EClass() System { - EClassBody(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 EventDerived = std::is_base_of_v; - template concept EventDerivedOrVoid = std::is_void_v || EventDerived; template concept SystemDerived = std::is_base_of_v; - template struct SystemExecuteFuncTraits {}; template struct Exclude {}; } namespace Runtime { - class Commands; - - template - struct SystemExecuteFuncTraits { - using ListenEvent = Arg; - using SignalEvent = Ret; - }; - - template - struct SystemExecuteFuncTraits { - using ListenEvent = Arg; - using SignalEvent = Ret; - }; -} - -namespace Runtime { - struct RUNTIME_API EClass() WorldStart : Event { - EClassBody(WorldStart) - }; - - struct RUNTIME_API EClass() WorldStop : Event { - EClassBody(WorldStop) - }; - - struct RUNTIME_API EClass() WorldTick : Event { - EClassBody(WorldTick) - - explicit WorldTick(float inFrameTimeMs); - - float frameTimeMs; - }; - class World; class Ticker; @@ -106,7 +76,6 @@ namespace Runtime { using StateClass = const Mirror::Class*; using SystemClass = const Mirror::Class*; - using EventClass = const Mirror::Class*; class RUNTIME_API Commands { public: @@ -133,13 +102,14 @@ namespace Runtime { // TODO runtime view private: - friend class EventBroadcaster; + 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 = ""); @@ -149,47 +119,31 @@ namespace Runtime { DefaultMovable(World) template void AddSystem(Args&&... inSystemArgs); - template void BroadcastEvent(Args&&... inEventArgs); + void AddBarrier(); - void Start(); + void Play(); void Stop(); + void Pause(); + void Resume(); void Tick(float inFrameTimeMs); bool Started() const; + bool Playing() const; private: - // TODO - friend class Common::Serializer; friend class Commands; - friend class EventBroadcaster; - template void AddSystemInternal(Args&&... inSystemArgs); + using SystemOp = std::function; + void ExecuteSystemGraph(const SystemOp& inOp); - bool started; + bool setuped; + bool playing; std::string name; std::unordered_map states; - std::unordered_map systemObjs; - std::unordered_map> listenersMap; - std::unordered_map signals; + std::unordered_map systems; + std::vector> systemsGraph; + std::vector systemsInBarriers; entt::registry registry; }; - - class RUNTIME_API EventBroadcaster { - public: - NonCopyable(EventBroadcaster) - - explicit EventBroadcaster(World& inWorld); - template void Compile(Args&&... inEventArgs); - void Dispatch(); - - private: - template void MakeInitialEvent(Args&&... inEventArgs); - void AllocateEvent(EventClass inEventClass); - void BuildGraph(EventClass inEventClass, const tf::Task& wait = {}); - - World& world; - tf::Taskflow taskflow; - std::unordered_map allocatedEvents; - }; } namespace Runtime::Internal { @@ -348,54 +302,8 @@ namespace Runtime { template void World::AddSystem(Args&&... inSystemArgs) { - using ListenEvent = typename SystemExecuteFuncTraits::ListenEvent; - using SignalEvent = typename SystemExecuteFuncTraits::SignalEvent; - - AddSystemInternal(std::forward(inSystemArgs)...); - } - - template - void World::BroadcastEvent(Args&&... inEventArgs) - { - EventBroadcaster broadcaster(*this); - broadcaster.Compile(std::forward(inEventArgs)...); - broadcaster.Dispatch(); - } - - template - void World::AddSystemInternal(Args&&... inSystemArgs) - { - static_assert(!std::is_same_v); - - const auto* systemClass = Internal::GetClassChecked(); - const auto* listenEventClass = Internal::GetClassChecked(); - const Mirror::Class* signalEventClass = nullptr; - if constexpr (!std::is_same_v) { - signalEventClass = Internal::GetClassChecked(); - } - - Assert(!systemObjs.contains(systemClass) && !signals.contains(systemClass)); - systemObjs.emplace(systemClass, Mirror::Any(System(std::forward(inSystemArgs)...))); - listenersMap[listenEventClass].emplace_back(systemClass); - if (signalEventClass != nullptr) { - signals.emplace(systemClass, signalEventClass); - } - } - - template - void EventBroadcaster::Compile(Args&&... inEventArgs) - { - const auto* eventClass = Internal::GetClassChecked(); - - AllocateEvent(eventClass); - MakeInitialEvent(std::forward(inEventArgs)...); - BuildGraph(eventClass); - } - - template - void EventBroadcaster::MakeInitialEvent(Args&&... inEventArgs) - { - const auto* eventClass = Internal::GetClassChecked(); - allocatedEvents.at(eventClass) = E(std::forward(inEventArgs)...); + SystemClass clazz = Internal::GetClassChecked(); + systems.emplace(clazz, System(std::forward(inSystemArgs)...)); + systemsInBarriers.emplace_back(clazz); } }; diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index dea49c30..07ba4fe7 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -11,10 +11,17 @@ namespace Runtime { return &Mirror::Class::Get(inName); } - WorldTick::WorldTick(float inFrameTimeMs) - : frameTimeMs(inFrameTimeMs) - { - } + 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) @@ -34,7 +41,8 @@ namespace Runtime { } World::World(std::string inName) - : started(false) + : setuped(false) + , playing(false) , name(std::move(inName)) { EngineHolder::Get().MountWorld(this); @@ -45,87 +53,87 @@ namespace Runtime { EngineHolder::Get().UnmountWorld(this); } - void World::Start() + void World::AddBarrier() { - Assert(!started); - started = true; - BroadcastEvent(); + systemsGraph.emplace_back(systemsInBarriers); + systemsInBarriers.clear(); } - void World::Stop() + void World::Play() { - Assert(started); - started = false; - BroadcastEvent(); + Assert(!setuped && systemsInBarriers.empty()); + setuped = true; + playing = true; + ExecuteSystemGraph([&](const System& inSystem) -> void { + Commands commands(*this); + inSystem.Setup(commands); + }); } - void World::Tick(float inFrameTimeMs) + void World::Stop() { - Assert(started); - BroadcastEvent(inFrameTimeMs); + Assert(setuped); + setuped = false; + playing = false; } - bool World::Started() const + void World::Pause() { - return started; + Assert(setuped && playing); + playing = false; } - EventBroadcaster::EventBroadcaster(World& inWorld) - : world(inWorld) + void World::Resume() { + Assert(setuped && !playing); + playing = true; } - void EventBroadcaster::Dispatch() + void World::Tick(float inFrameTimeMs) { - tf::Executor executor; - executor.run(taskflow); + Assert(setuped && playing); + ExecuteSystemGraph([&](const System& inSystem) -> void { + Commands commands(*this); + inSystem.Tick(commands, inFrameTimeMs); + }); } - void EventBroadcaster::AllocateEvent(EventClass inEventClass) // NOLINT + bool World::Started() const { - AssertWithReason( - !allocatedEvents.contains(inEventClass), - "system dependency do not support a event signal multi times in a dispatch graph, please check your systems"); - - allocatedEvents.emplace(inEventClass, Mirror::Any()); - if (!world.listenersMap.contains(inEventClass)) { - return; - } - - for (const auto* listener : world.listenersMap.at(inEventClass)) { - if (auto iter = world.signals.find(listener); - iter != world.signals.end()) { - AllocateEvent(iter->second); - } - } + return setuped; } - void EventBroadcaster::BuildGraph(EventClass inEventClass, const tf::Task& wait) // NOLINT + bool World::Playing() const { - if (!world.listenersMap.contains(inEventClass)) { - return; - } + return playing; + } - for (const auto* listener : world.listenersMap.at(inEventClass)) { - const auto iter = world.signals.find(listener); - const bool hasSignalEvent = iter != world.signals.end(); - - auto task = taskflow.emplace([iter, hasSignalEvent, inEventClass, listener, this]() -> void { - const auto& listenEvent = allocatedEvents.at(inEventClass); - - Commands commands(world); - auto result = listener->GetMemberFunction("Execute").InvokeDyn(world.systemObjs.at(listener), { Mirror::Any(std::ref(commands)), listenEvent }); - if (hasSignalEvent) { - allocatedEvents.at(iter->second) = result; - } - }); - if (!wait.empty()) { - task.succeed(wait); + void World::ExecuteSystemGraph(const SystemOp& inOp) + { + 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); } - if (hasSignalEvent) { - BuildGraph(iter->second, task); + barrierTask = newBarrierTask(); + for (const auto& task : tasks) { + barrierTask.succeed(task); } } + + tf::Executor executor; + executor + .run(taskFlow) + .wait(); } } diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp index 78fb9a25..06dc173a 100644 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -9,48 +9,62 @@ struct WorldTest : testing::Test { void SetUp() override { - Runtime::EngineHolder::Load("RuntimeTest", {}); + EngineHolder::Load("RuntimeTest", {}); } }; -void BasicSetupSystem::Execute(Runtime::Commands& commands, const Runtime::WorldStart&) // NOLINT +GlobalCounter::GlobalCounter() + : tickTime(0) + , value(0) { - for (auto i = 0; i < 5; i++) { - const Runtime::Entity entity = commands.CreateEntity(); - commands.EmplaceComp(entity); - commands.EmplaceComp(entity); - } } -StartVerify BasicTickSystem::Execute(Runtime::Commands& commands, const Runtime::WorldTick&) // NOLINT +ParralCountSystemA::ParralCountSystemA() = default; + +ParralCountSystemA::~ParralCountSystemA() = default; + +void ParralCountSystemA::Tick(Commands& commands, float inTimeMs) const { - auto& count = commands.GetState(); - count.value += 1; + auto& globalCounter = commands.GetState(); + globalCounter.tickTime += 1; + globalCounter.value += 2; +} + +ParralCountSystemB::ParralCountSystemB() = default; - auto view = commands.View(); - view.Each([](Position& position, Velocity& velocity) -> void { - position.x += velocity.x; - position.y += velocity.y; - }); +ParralCountSystemB::~ParralCountSystemB() = default; - return {}; +void ParralCountSystemB::Tick(Commands& commands, float inTimeMs) const +{ + commands.GetState().value += 3; } -void PositionVerifySystem::Execute(Runtime::Commands& commands, const StartVerify&) // NOLINT +GlobalCounterVerifySystem::GlobalCounterVerifySystem() = default; + +GlobalCounterVerifySystem::~GlobalCounterVerifySystem() = default; + +void GlobalCounterVerifySystem::Setup(Commands& commands) const { - const IterTimeCount& count = commands.GetState(); + commands.EmplaceState(); +} - auto view = commands.View(); - view.Each([&](const Position& position, const Velocity& velocity) -> void { - ASSERT_EQ(position.x, velocity.x * count.value); - }); +void GlobalCounterVerifySystem::Tick(Commands& commands, float inTimeMs) const +{ + const auto& globalCounter = commands.GetState(); + ASSERT_EQ(globalCounter.value, globalCounter.tickTime * 5); } TEST_F(WorldTest, ECSBasic) { - Runtime::World world; - world.AddSystem(); - world.AddSystem(); - world.Start(); - world.Tick(10.f); + 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 index 094da24d..db03802e 100644 --- a/Engine/Source/Runtime/Test/WorldTest.h +++ b/Engine/Source/Runtime/Test/WorldTest.h @@ -7,44 +7,41 @@ #include #include -struct EClass() Position : Runtime::Component { - EClassBody(Position); +using namespace Runtime; - float x; - float y; -}; +class EClass() GlobalCounter final : public State { + EClassBody(GlobalCounter) -struct EClass() Velocity : Runtime::Component { - EClassBody(Velocity); + GlobalCounter(); - float x; - float y; + EProperty() uint32_t tickTime; + EProperty() uint32_t value; }; -struct EClass() IterTimeCount : Runtime::State { - EClassBody(IterTimeCount); +class EClass() ParralCountSystemA final : public System { + EPolyClassBody(ParralCountSystemA) - size_t value; -}; + ParralCountSystemA(); + ~ParralCountSystemA() override; -struct EClass() StartVerify : Runtime::Event { - EClassBody(StartVerify); + EFunc() void Tick(Commands& commands, float inTimeMs) const override; }; -struct EClass() BasicSetupSystem : Runtime::System { - EClassBody(SetupSystem); +class EClass() ParralCountSystemB final : public System { + EPolyClassBody(ParralCountSystemB) - EFunc() void Execute(Runtime::Commands& commands, const Runtime::WorldStart&); -}; + ParralCountSystemB(); + ~ParralCountSystemB() override; -struct EClass() BasicTickSystem : Runtime::System { - EClassBody(BasicTickSystem); - - EFunc() StartVerify Execute(Runtime::Commands& commands, const Runtime::WorldTick&); + EFunc() void Tick(Commands& commands, float inTimeMs) const override; }; -struct EClass() PositionVerifySystem : Runtime::System { - EClassBody(PositionVerifySystem) +class EClass() GlobalCounterVerifySystem final : public System { + EPolyClassBody(GlobalCounterVerifySystem) + + GlobalCounterVerifySystem(); + ~GlobalCounterVerifySystem() override; - EFunc() void Execute(Runtime::Commands& commands, const StartVerify&); + EFunc() void Setup(Commands& commands) const override; + EFunc() void Tick(Commands& commands, float inTimeMs) const override; }; diff --git a/Tool/MirrorTool/Src/Generator.cpp b/Tool/MirrorTool/Src/Generator.cpp index d8584fb6..96b31be0 100644 --- a/Tool/MirrorTool/Src/Generator.cpp +++ b/Tool/MirrorTool/Src/Generator.cpp @@ -142,6 +142,11 @@ 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 << "{" << Common::newline; + stream << Common::tab<1> << fmt::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 << "{" << Common::newline; stream << Common::tab<1> << fmt::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index d13408aa..121fac48 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -294,7 +294,7 @@ namespace MirrorTool { CXString retTypeSpelling = clang_getTypeSpelling(retType); FunctionInfo functionInfo; - functionInfo.name = GetOuterName(context.outerName, context.name); + functionInfo.outerName = GetOuterName(context.outerName, context.name); functionInfo.name = spellingStr; functionInfo.retType = clang_getCString(retTypeSpelling); context.functions.emplace_back(std::move(functionInfo));