From 0e57c684a88d70445332f02cbb881cd5e2bd8c0a Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 20 Mar 2025 19:02:23 +0100 Subject: [PATCH] Optimize deserializer construction --- src/emulator/serialization.hpp | 381 +++++++++--------- .../emulation_test_utils.hpp | 2 +- .../serialization_test.cpp | 6 +- 3 files changed, 197 insertions(+), 192 deletions(-) diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index 53fab16a..ae84ed9a 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -65,6 +65,193 @@ namespace utils }; } + class buffer_serializer + { + public: + buffer_serializer() = default; + + void write(const void* buffer, const size_t length) + { +#ifndef NDEBUG + const uint64_t old_size = this->buffer_.size(); +#endif + + if (this->break_offset_ && this->buffer_.size() <= *this->break_offset_ && + this->buffer_.size() + length > *this->break_offset_) + { + throw std::runtime_error("Break offset reached!"); + } + + const auto* byte_buffer = static_cast(buffer); + this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); + +#ifndef NDEBUG + const auto* security_buffer = reinterpret_cast(&old_size); + this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + sizeof(old_size)); +#endif + } + + void write(const buffer_serializer& object) + { + const auto& buffer = object.get_buffer(); + this->write(buffer.data(), buffer.size()); + } + + template + requires(!is_optional::value) + void write(const T& object) + { + constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; + + if constexpr (Serializable) + { + object.serialize(*this); + } + else if constexpr (detail::has_serialize_function::value) + { + serialize(*this, object); + } + else if constexpr (is_trivially_copyable) + { + union + { + const T* type_{}; + const void* void_; + } pointers; + + pointers.type_ = &object; + + this->write(pointers.void_, sizeof(object)); + } + else + { + static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); + std::abort(); + } + } + + template + void write_atomic(const std::atomic& val) + { + this->write(val.load()); + } + + template + void write_optional(const std::optional& val) + { + this->write(val.has_value()); + + if (val.has_value()) + { + this->write(*val); + } + } + + template + void write_span(const std::span vec) + { + this->write(static_cast(vec.size())); + + for (const auto& v : vec) + { + this->write(v); + } + } + + template + void write_vector(const std::vector& vec) + { + this->write_span(std::span(vec)); + } + + template + void write_list(const std::list& vec) + { + this->write(static_cast(vec.size())); + + for (const auto& v : vec) + { + this->write(v); + } + } + + template + void write_string(const std::basic_string_view str) + { + this->write_span(str); + } + + template + void write_string(const std::basic_string& str) + { + this->write_string(std::basic_string_view(str)); + } + + template + void write_map(const Map& map) + { + this->write(map.size()); + + for (const auto& entry : map) + { + this->write(entry.first); + this->write(entry.second); + } + } + + const std::vector& get_buffer() const + { + return this->buffer_; + } + + std::vector move_buffer() + { + return std::move(this->buffer_); + } + + void set_break_offset(const size_t break_offset) + { + this->break_offset_ = break_offset; + } + + std::optional get_diff(const buffer_serializer& other) const + { + const auto& b1 = this->get_buffer(); + const auto& b2 = other.get_buffer(); + + const auto s1 = b1.size(); + const auto s2 = b2.size(); + + for (size_t i = 0; i < s1 && i < s2; ++i) + { + if (b1.at(i) != b2.at(i)) + { + return i; + } + } + + if (s1 != s2) + { + return std::min(s1, s2); + } + + return std::nullopt; + } + + void print_diff(const buffer_serializer& other) const + { + const auto diff = this->get_diff(other); + if (diff) + { + printf("Diff at %zd\n", *diff); + } + } + + private: + std::vector buffer_{}; + std::optional break_offset_{}; + }; + class buffer_deserializer { public: @@ -77,11 +264,16 @@ namespace utils } template - buffer_deserializer(const std::vector& buffer, bool no_debugging = false) + buffer_deserializer(const std::vector& buffer, const bool no_debugging = false) : buffer_deserializer(std::span(buffer), no_debugging) { } + buffer_deserializer(const buffer_serializer& serializer, const bool no_debugging = false) + : buffer_deserializer(serializer.get_buffer(), no_debugging) + { + } + std::span read_data(const size_t length) { #ifndef NDEBUG @@ -348,193 +540,6 @@ namespace utils } }; - class buffer_serializer - { - public: - buffer_serializer() = default; - - void write(const void* buffer, const size_t length) - { -#ifndef NDEBUG - const uint64_t old_size = this->buffer_.size(); -#endif - - if (this->break_offset_ && this->buffer_.size() <= *this->break_offset_ && - this->buffer_.size() + length > *this->break_offset_) - { - throw std::runtime_error("Break offset reached!"); - } - - const auto* byte_buffer = static_cast(buffer); - this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); - -#ifndef NDEBUG - const auto* security_buffer = reinterpret_cast(&old_size); - this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + sizeof(old_size)); -#endif - } - - void write(const buffer_serializer& object) - { - const auto& buffer = object.get_buffer(); - this->write(buffer.data(), buffer.size()); - } - - template - requires(!is_optional::value) - void write(const T& object) - { - constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; - - if constexpr (Serializable) - { - object.serialize(*this); - } - else if constexpr (detail::has_serialize_function::value) - { - serialize(*this, object); - } - else if constexpr (is_trivially_copyable) - { - union - { - const T* type_{}; - const void* void_; - } pointers; - - pointers.type_ = &object; - - this->write(pointers.void_, sizeof(object)); - } - else - { - static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); - std::abort(); - } - } - - template - void write_atomic(const std::atomic& val) - { - this->write(val.load()); - } - - template - void write_optional(const std::optional& val) - { - this->write(val.has_value()); - - if (val.has_value()) - { - this->write(*val); - } - } - - template - void write_span(const std::span vec) - { - this->write(static_cast(vec.size())); - - for (const auto& v : vec) - { - this->write(v); - } - } - - template - void write_vector(const std::vector vec) - { - this->write_span(std::span(vec)); - } - - template - void write_list(const std::list vec) - { - this->write(static_cast(vec.size())); - - for (const auto& v : vec) - { - this->write(v); - } - } - - template - void write_string(const std::basic_string_view str) - { - this->write_span(str); - } - - template - void write_string(const std::basic_string& str) - { - this->write_string(std::basic_string_view(str)); - } - - template - void write_map(const Map& map) - { - this->write(map.size()); - - for (const auto& entry : map) - { - this->write(entry.first); - this->write(entry.second); - } - } - - const std::vector& get_buffer() const - { - return this->buffer_; - } - - std::vector move_buffer() - { - return std::move(this->buffer_); - } - - void set_break_offset(const size_t break_offset) - { - this->break_offset_ = break_offset; - } - - std::optional get_diff(const buffer_serializer& other) const - { - const auto& b1 = this->get_buffer(); - const auto& b2 = other.get_buffer(); - - const auto s1 = b1.size(); - const auto s2 = b2.size(); - - for (size_t i = 0; i < s1 && i < s2; ++i) - { - if (b1.at(i) != b2.at(i)) - { - return i; - } - } - - if (s1 != s2) - { - return std::min(s1, s2); - } - - return std::nullopt; - } - - void print_diff(const buffer_serializer& other) const - { - const auto diff = this->get_diff(other); - if (diff) - { - printf("Diff at %zd\n", *diff); - } - } - - private: - std::vector buffer_{}; - std::optional break_offset_{}; - }; - template <> inline void buffer_deserializer::read(bool& object) { diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index 7764dd7d..69b4babc 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -135,7 +135,7 @@ namespace test const auto limit = emu.get_executed_instructions(); const auto reset_emulator = [&] { - utils::buffer_deserializer deserializer{start_state.get_buffer()}; + utils::buffer_deserializer deserializer{start_state}; emu.deserialize(deserializer); }; diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 1ca329a2..b82de8d3 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -16,7 +16,7 @@ namespace test utils::buffer_serializer end_state1{}; emu.serialize(end_state1); - utils::buffer_deserializer deserializer{start_state.get_buffer()}; + utils::buffer_deserializer deserializer{start_state}; emu.deserialize(deserializer); emu.start(); @@ -39,7 +39,7 @@ namespace test utils::buffer_serializer serializer1{}; emu1.serialize(serializer1); - utils::buffer_deserializer deserializer{serializer1.get_buffer()}; + utils::buffer_deserializer deserializer{serializer1}; auto new_emu = create_empty_emulator(); new_emu.deserialize(deserializer); @@ -82,7 +82,7 @@ namespace test utils::buffer_serializer serializer{}; emu.serialize(serializer); - utils::buffer_deserializer deserializer{serializer.get_buffer()}; + utils::buffer_deserializer deserializer{serializer}; auto new_emu = create_empty_emulator(); new_emu.deserialize(deserializer);