Optimize deserializer construction

This commit is contained in:
momo5502
2025-03-20 19:02:23 +01:00
parent b69fe7e2c0
commit 0e57c684a8
3 changed files with 197 additions and 192 deletions

View File

@@ -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<const std::byte*>(buffer);
this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length);
#ifndef NDEBUG
const auto* security_buffer = reinterpret_cast<const std::byte*>(&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 <typename T>
requires(!is_optional<T>::value)
void write(const T& object)
{
constexpr auto is_trivially_copyable = std::is_trivially_copyable_v<T>;
if constexpr (Serializable<T>)
{
object.serialize(*this);
}
else if constexpr (detail::has_serialize_function<T>::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 <typename T>
void write_atomic(const std::atomic<T>& val)
{
this->write(val.load());
}
template <typename T>
void write_optional(const std::optional<T>& val)
{
this->write(val.has_value());
if (val.has_value())
{
this->write(*val);
}
}
template <typename T>
void write_span(const std::span<T> vec)
{
this->write(static_cast<uint64_t>(vec.size()));
for (const auto& v : vec)
{
this->write(v);
}
}
template <typename T>
void write_vector(const std::vector<T>& vec)
{
this->write_span(std::span(vec));
}
template <typename T>
void write_list(const std::list<T>& vec)
{
this->write(static_cast<uint64_t>(vec.size()));
for (const auto& v : vec)
{
this->write(v);
}
}
template <typename T>
void write_string(const std::basic_string_view<T> str)
{
this->write_span<const T>(str);
}
template <typename T>
void write_string(const std::basic_string<T>& str)
{
this->write_string(std::basic_string_view<T>(str));
}
template <typename Map>
void write_map(const Map& map)
{
this->write<uint64_t>(map.size());
for (const auto& entry : map)
{
this->write(entry.first);
this->write(entry.second);
}
}
const std::vector<std::byte>& get_buffer() const
{
return this->buffer_;
}
std::vector<std::byte> move_buffer()
{
return std::move(this->buffer_);
}
void set_break_offset(const size_t break_offset)
{
this->break_offset_ = break_offset;
}
std::optional<size_t> 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<std::byte> buffer_{};
std::optional<size_t> break_offset_{};
};
class buffer_deserializer
{
public:
@@ -77,11 +264,16 @@ namespace utils
}
template <typename T>
buffer_deserializer(const std::vector<T>& buffer, bool no_debugging = false)
buffer_deserializer(const std::vector<T>& 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<const std::byte> 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<const std::byte*>(buffer);
this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length);
#ifndef NDEBUG
const auto* security_buffer = reinterpret_cast<const std::byte*>(&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 <typename T>
requires(!is_optional<T>::value)
void write(const T& object)
{
constexpr auto is_trivially_copyable = std::is_trivially_copyable_v<T>;
if constexpr (Serializable<T>)
{
object.serialize(*this);
}
else if constexpr (detail::has_serialize_function<T>::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 <typename T>
void write_atomic(const std::atomic<T>& val)
{
this->write(val.load());
}
template <typename T>
void write_optional(const std::optional<T>& val)
{
this->write(val.has_value());
if (val.has_value())
{
this->write(*val);
}
}
template <typename T>
void write_span(const std::span<T> vec)
{
this->write(static_cast<uint64_t>(vec.size()));
for (const auto& v : vec)
{
this->write(v);
}
}
template <typename T>
void write_vector(const std::vector<T> vec)
{
this->write_span(std::span(vec));
}
template <typename T>
void write_list(const std::list<T> vec)
{
this->write(static_cast<uint64_t>(vec.size()));
for (const auto& v : vec)
{
this->write(v);
}
}
template <typename T>
void write_string(const std::basic_string_view<T> str)
{
this->write_span<const T>(str);
}
template <typename T>
void write_string(const std::basic_string<T>& str)
{
this->write_string(std::basic_string_view<T>(str));
}
template <typename Map>
void write_map(const Map& map)
{
this->write<uint64_t>(map.size());
for (const auto& entry : map)
{
this->write(entry.first);
this->write(entry.second);
}
}
const std::vector<std::byte>& get_buffer() const
{
return this->buffer_;
}
std::vector<std::byte> move_buffer()
{
return std::move(this->buffer_);
}
void set_break_offset(const size_t break_offset)
{
this->break_offset_ = break_offset;
}
std::optional<size_t> 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<std::byte> buffer_{};
std::optional<size_t> break_offset_{};
};
template <>
inline void buffer_deserializer::read<bool>(bool& object)
{

View File

@@ -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);
};

View File

@@ -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);