Skip to content

Feat: Misc Update #385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Mar 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ jobs:
if: runner.os == 'macOS'

- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: ${{env.CMAKE_VERSION}}

- name: Update Cache Files
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{github.workspace}}/ThirdParty/Zip
key: ${{runner.os}}-3rd-zip
Expand Down
6 changes: 5 additions & 1 deletion Engine/Source/Common/Include/Common/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@

#include <string>

#include <rapidjson/document.h>

namespace Common {
class FileUtils {
public:
static std::string ReadTextFile(const std::string& fileName);
static std::string ReadTextFile(const std::string& inFileName);
static rapidjson::Document ReadJsonFile(const std::string& inFileName);
static void WriteJsonFile(const std::string& inFileName, const rapidjson::Document& inJsonDocument, bool inPretty = true);
};
}
1 change: 1 addition & 0 deletions Engine/Source/Common/Include/Common/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include <filesystem>
#include <functional>

namespace Common {
class Path {
Expand Down
134 changes: 98 additions & 36 deletions Engine/Source/Common/Include/Common/Serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,16 @@
#include <unordered_map>
#include <set>
#include <map>
#include <variant>

#include <rapidjson/document.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/filewritestream.h>
#include <rapidjson/writer.h>
#include <rapidjson/prettywriter.h>

#include <Common/Utility.h>
#include <Common/Debug.h>
#include <Common/Hash.h>
#include <Common/String.h>
#include <Common/FileSystem.h>
#include <Common/File.h>

namespace Common {
class BinarySerializeStream {
Expand Down Expand Up @@ -476,39 +474,15 @@ namespace Common {

template <typename T> void JsonSerializeToFile(const std::string& inFile, const T& inValue, bool inPretty)
{
Common::Path parentPath = Common::Path(inFile).Parent();
if (!parentPath.Exists()) {
parentPath.MakeDir();
}

rapidjson::Document document;
JsonSerialize<T>(document, document.GetAllocator(), inValue);

char buffer[65536];
std::FILE* file = fopen(inFile.c_str(), "wb");
rapidjson::FileWriteStream stream(file, buffer, sizeof(buffer));

if (inPretty) {
rapidjson::PrettyWriter writer(stream);
document.Accept(writer);
} else {
rapidjson::Writer writer(stream);
document.Accept(writer);
}
(void) fclose(file);
FileUtils::WriteJsonFile(inFile, document, inPretty);
}

template <typename T> void JsonDeserializeFromFile(const std::string& inFile, T& outValue)
{
char buffer[65536];
std::FILE* file = fopen(inFile.c_str(), "rb");
rapidjson::FileReadStream stream(file, buffer, sizeof(buffer));

rapidjson::Document document;
document.ParseStream(stream);

const rapidjson::Document document = FileUtils::ReadJsonFile(inFile);
JsonDeserialize<T>(document, outValue);
(void) fclose(file);
}

template <Serializable T>
Expand Down Expand Up @@ -982,21 +956,21 @@ namespace Common {
template <size_t... I>
static size_t SerializeInternal(BinarySerializeStream& stream, const std::tuple<T...>& value, std::index_sequence<I...>)
{
size_t result = 0;
size_t serialized = 0;
std::initializer_list<int> { ([&]() -> void {
result += Serializer<T>::Serialize(stream, std::get<I>(value));
serialized += Serializer<T>::Serialize(stream, std::get<I>(value));
}(), 0)... };
return result;
return serialized;
}

template <size_t... I>
static size_t DeserializeInternal(BinaryDeserializeStream& stream, std::tuple<T...>& value, std::index_sequence<I...>)
{
size_t result = 0;
size_t deserialized = 0;
std::initializer_list<int> { ([&]() -> void {
result += Serializer<T>::Deserialize(stream, std::get<I>(value));
deserialized += Serializer<T>::Deserialize(stream, std::get<I>(value));
}(), 0)... };
return result;
return deserialized;
}

static size_t Serialize(BinarySerializeStream& stream, const std::tuple<T...>& value)
Expand Down Expand Up @@ -1035,6 +1009,51 @@ namespace Common {
}
};

template <typename... T> struct VariantTypeId {};
template <typename T> struct VariantTypeId<T> { static constexpr size_t value = HashUtils::StrCrc32("std::variant"); };
template <typename T, typename... T2> struct VariantTypeId<T, T2...> { static constexpr size_t value = Serializer<T>::typeId + VariantTypeId<T2...>::value; };

template <Serializable... T>
struct Serializer<std::variant<T...>> {
static constexpr size_t typeId = VariantTypeId<T...>::value;

static size_t Serialize(BinarySerializeStream& stream, const std::variant<T...>& value)
{
size_t serialized = 0;
serialized += Serializer<uint64_t>::Serialize(stream, value.index());
std::visit([&](auto&& v) -> void { // NOLINT
serialized += Serializer<std::decay_t<decltype(v)>>::Serialize(stream, v);
}, value);
return serialized;
}

template <size_t... I>
static size_t DeserializeInternal(BinaryDeserializeStream& stream, std::variant<T...>& value, size_t aspectIndex, std::index_sequence<I...>)
{
size_t deserialized = 0;
(void) std::initializer_list<int> { ([&]() -> void {
if (I != aspectIndex) {
return;
}

T tempValue;
deserialized += Serializer<T>::Deserialize(stream, tempValue);
value = std::move(tempValue);
}(), 0)... };
return deserialized;
}

static size_t Deserialize(BinaryDeserializeStream& stream, std::variant<T...>& value)
{
size_t deserialized = 0;

uint64_t index;
deserialized += Serializer<uint64_t>::Deserialize(stream, index);
deserialized += DeserializeInternal(stream, value, index, std::make_index_sequence<sizeof...(T)> {});
return deserialized;
}
};

template <>
struct JsonSerializer<int8_t> {
static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const int8_t& inValue)
Expand Down Expand Up @@ -1528,4 +1547,47 @@ namespace Common {
JsonDeserializeInternal(inJsonValue, outValue, std::make_index_sequence<sizeof...(T)>());
}
};

template <JsonSerializable... T>
struct JsonSerializer<std::variant<T...>> {
static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::variant<T...>& inValue)
{
rapidjson::Value typeValue;
JsonSerializer<uint64_t>::JsonSerialize(typeValue, inAllocator, inValue.index());

rapidjson::Value contentValue;
std::visit([&](auto&& v) -> void {
JsonSerializer<std::decay_t<decltype(v)>>::JsonSerialize(contentValue, inAllocator, v);
}, inValue);

outJsonValue.SetObject();
outJsonValue.AddMember("type", typeValue, inAllocator);
outJsonValue.AddMember("content", contentValue, inAllocator);
}

template <size_t... I>
static void JsonDeserializeInternal(const rapidjson::Value& inContentJsonValue, std::variant<T...>& outValue, size_t inAspectIndex, std::index_sequence<I...>)
{
(void) std::initializer_list<int> { ([&]() -> void {
if (I != inAspectIndex) {
return;
}

T temp;
JsonSerializer<T>::JsonDeserialize(inContentJsonValue, temp);
outValue = std::move(temp);
}(), 0)... };
}

static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::variant<T...>& outValue)
{
if (!inJsonValue.HasMember("type") || !inJsonValue.HasMember("content")) {
return;
}

uint64_t aspectIndex;
JsonSerializer<uint64_t>::JsonDeserialize(inJsonValue["type"], aspectIndex);
JsonDeserializeInternal(inJsonValue["content"], outValue, aspectIndex, std::make_index_sequence<sizeof...(T)> {});
}
};
}
4 changes: 2 additions & 2 deletions Engine/Source/Common/Include/Common/Time.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace Common {

Time ToTime() const;
AccurateTime ToAccurateTime() const;
float ToSeconds() const;
float ToMilliseconds() const;
double ToSeconds() const;
double ToMilliseconds() const;
uint64_t ToMicroseconds() const;
const std::chrono::system_clock::time_point& GetNative() const;

Expand Down
44 changes: 42 additions & 2 deletions Engine/Source/Common/Src/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@
//

#include <fstream>
#include <cstdio>

#include <rapidjson/filereadstream.h>
#include <rapidjson/filewritestream.h>
#include <rapidjson/writer.h>
#include <rapidjson/prettywriter.h>

#include <Common/File.h>
#include <Common/Debug.h>
#include <Common/FileSystem.h>

namespace Common {
std::string FileUtils::ReadTextFile(const std::string& fileName)
std::string FileUtils::ReadTextFile(const std::string& inFileName)
{
std::string result;
{
std::ifstream file(fileName, std::ios::ate | std::ios::binary);
std::ifstream file(inFileName, std::ios::ate | std::ios::binary);
Assert(file.is_open());
const size_t size = file.tellg();
result.resize(size);
Expand All @@ -22,4 +29,37 @@ namespace Common {
}
return result;
}

rapidjson::Document FileUtils::ReadJsonFile(const std::string& inFileName)
{
char buffer[65536];
std::FILE* file = fopen(inFileName.c_str(), "rb"); // NOLINT
rapidjson::FileReadStream stream(file, buffer, sizeof(buffer));

rapidjson::Document document;
document.ParseStream(stream);
(void) fclose(file);
return document;
}

void FileUtils::WriteJsonFile(const std::string& inFileName, const rapidjson::Document& inJsonDocument, bool inPretty)
{
Common::Path parentPath = Common::Path(inFileName).Parent();
if (!parentPath.Exists()) {
parentPath.MakeDir();
}

char buffer[65536];
std::FILE* file = fopen(inFileName.c_str(), "wb"); // NOLINT
rapidjson::FileWriteStream stream(file, buffer, sizeof(buffer));

if (inPretty) {
rapidjson::PrettyWriter writer(stream);
inJsonDocument.Accept(writer);
} else {
rapidjson::Writer writer(stream);
inJsonDocument.Accept(writer);
}
(void) fclose(file);
}
}
8 changes: 4 additions & 4 deletions Engine/Source/Common/Src/Time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ namespace Common {
return AccurateTime { *this };
}

float TimePoint::ToSeconds() const
double TimePoint::ToSeconds() const
{
return ToMilliseconds() / 1000.0f;
return ToMilliseconds() / 1000.0;
}

float TimePoint::ToMilliseconds() const
double TimePoint::ToMilliseconds() const
{
return static_cast<float>(ToMicroseconds()) / 1000.0f;
return static_cast<double>(ToMicroseconds()) / 1000.0;
}

uint64_t TimePoint::ToMicroseconds() const
Expand Down
6 changes: 4 additions & 2 deletions Engine/Source/Common/Test/SerializationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Created by johnk on 2023/7/13.
//

#include <filesystem>

#include <Common/Memory.h>
#include <SerializationTest.h>

Expand Down Expand Up @@ -76,6 +74,7 @@ TEST(SerializationTest, TypedSerializationTest)
PerformTypedSerializationTest<std::unordered_map<int, bool>>({ { 1, false }, { 2, true } });
PerformTypedSerializationTest<std::map<int, bool>>({ { 1, false }, { 2, true } });
PerformTypedSerializationTest<std::tuple<int, bool, int>>({ 1, true, 2 });
PerformTypedSerializationTest<std::variant<int, bool, float>>({ true });
}

TEST(SerializationTest, TypedSerializationWithFileTest)
Expand Down Expand Up @@ -107,6 +106,7 @@ TEST(SerializationTest, TypedSerializationWithFileTest)
PerformTypeSerializationWithFileTest<std::unordered_map<int, bool>>(fileName, { { 1, false }, { 2, true } });
PerformTypeSerializationWithFileTest<std::map<int, bool>>(fileName, { { 1, false }, { 2, true } });
PerformTypeSerializationWithFileTest<std::tuple<int, bool, int>>(fileName, { 1, true, 2 });
PerformTypeSerializationWithFileTest<std::variant<int, bool, float>>(fileName, { true });
}

TEST(SerializationTest, JsonSerializationTest)
Expand Down Expand Up @@ -137,6 +137,7 @@ TEST(SerializationTest, JsonSerializationTest)
PerformJsonSerializationTest<std::map<int, bool>>({ { 1, false }, { 2, true } }, R"([{"key":1,"value":false},{"key":2,"value":true}])");
PerformJsonSerializationTest<std::map<std::string, int>>({ { "1", 1 }, { "2", 2 } }, R"([{"key":"1","value":1},{"key":"2","value":2}])");
PerformJsonSerializationTest<std::tuple<int, bool, int>>({ 1, true, 2 }, R"({"0":1,"1":true,"2":2})");
PerformJsonSerializationTest<std::variant<int, bool, float>>({ true }, R"({"type":1,"content":true})");
}

TEST(SerializationTest, JsonSerializationWithFileTest)
Expand Down Expand Up @@ -169,4 +170,5 @@ TEST(SerializationTest, JsonSerializationWithFileTest)
PerformJsonSerializationWithFileTest<std::map<int, bool>>(fileName, { { 1, false }, { 2, true } });
PerformJsonSerializationWithFileTest<std::map<std::string, int>>(fileName, { { "1", 1 }, { "2", 2 } });
PerformJsonSerializationWithFileTest<std::tuple<int, bool, int>>(fileName, { 1, true, 2 });
PerformTypeSerializationWithFileTest<std::variant<int, bool, float>>(fileName, { true });
}
Loading