#pragma once #include #include #include #include #include #include #include #include #include #include namespace utils { class buffer_serializer; class buffer_deserializer; template concept Serializable = requires(T a, const T ac, buffer_serializer& serializer, buffer_deserializer& deserializer) { { ac.serialize(serializer) } -> std::same_as; { a.deserialize(deserializer) } -> std::same_as; }; template struct is_optional : std::false_type { }; template struct is_optional> : std::true_type { }; namespace detail { template struct has_serialize_function : std::false_type { }; template struct has_serialize_function< T, std::void_t(), std::declval&>()))>> : std::true_type { }; template struct has_deserialize_function : std::false_type { }; template struct has_deserialize_function< T, std::void_t(), std::declval&>()))>> : std::true_type { }; template struct has_deserializer_constructor : std::bool_constant> { }; } class buffer_serializer { public: buffer_serializer() = default; void write(const void* buffer, const size_t length) { const auto old_size_remainder = static_cast(length); constexpr auto check_size = sizeof(old_size_remainder); if (this->break_offset_ && this->buffer_.size() <= *this->break_offset_ && this->buffer_.size() + length + check_size > *this->break_offset_) { throw std::runtime_error("Break offset reached!"); } const auto* security_buffer = reinterpret_cast(&old_size_remainder); this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + check_size); const auto* byte_buffer = static_cast(buffer); this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); } 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)); } void write_vector(const std::vector& vec) { this->write(static_cast(vec.size())); uint8_t byte = 0; uint8_t bit_index = 0; for (const bool b : vec) { if (b) { byte |= (1u << bit_index); } ++bit_index; if (bit_index == 8) { this->write(byte); byte = 0; bit_index = 0; } } if (bit_index != 0) { this->write(byte); } } 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: template buffer_deserializer(const std::span buffer) : buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) { static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); } template buffer_deserializer(const std::vector& buffer) : buffer_deserializer(std::span(buffer)) { } buffer_deserializer(const buffer_serializer& serializer) : buffer_deserializer(serializer.get_buffer()) { } std::span read_data(const size_t length) { const auto length_rest = static_cast(length); constexpr auto check_size = sizeof(length_rest); if (this->offset_ + (length + check_size) > this->buffer_.size()) { throw std::runtime_error("Out of bounds read from byte buffer"); } if (static_cast(this->buffer_[this->offset_]) != length_rest) { throw std::runtime_error("Reading from serialized buffer mismatches written data!"); } this->offset_ += check_size; const std::span result(this->buffer_.data() + this->offset_, length); this->offset_ += length; return result; } void read(void* data, const size_t length) { const auto span = this->read_data(length); memcpy(data, span.data(), length); } template void read(T& object) { constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; if constexpr (Serializable) { object.deserialize(*this); } else if constexpr (detail::has_deserialize_function::value) { deserialize(*this, object); } else if constexpr (is_trivially_copyable) { union { T* type_{}; void* void_; } pointers; pointers.type_ = &object; this->read(pointers.void_, sizeof(object)); } else { static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); std::abort(); } } template T read() { auto object = this->construct_object(); this->read(object); return object; } template void read_atomic(std::atomic& val) { val = this->read(); } template void read_optional(std::optional& val) { if (this->read()) { val.emplace(this->read()); } else { val = std::nullopt; } } template requires(std::is_invocable_r_v) void read_optional(std::optional& val, const F& factory) { if (this->read()) { val.emplace(factory()); this->read(*val); } else { val = {}; } } template void read_vector(std::vector& result) { const auto size = this->read(); result.clear(); result.reserve(static_cast(size)); for (uint64_t i = 0; i < size; ++i) { result.emplace_back(this->read()); } } void read_vector(std::vector& result) { const auto bit_count = this->read(); result.clear(); result.reserve(static_cast(bit_count)); const auto size = (bit_count + 7) / 8; for (uint64_t i = 0; i < size; ++i) { const auto byte = this->read(); for (uint8_t bit = 0; bit < 8 && result.size() < bit_count; ++bit) { result.push_back((byte >> bit) & 1u); } } } template std::vector read_vector() { std::vector result{}; this->read_vector(result); return result; } template void read_list(std::list& result) { const auto size = this->read(); result.clear(); for (uint64_t i = 0; i < size; ++i) { result.emplace_back(this->read()); } } template std::list read_list() { std::list result{}; this->read_list(result); return result; } template void read_map(Map& map) { using key_type = typename Map::key_type; using value_type = typename Map::mapped_type; map.clear(); const auto size = this->read(); for (uint64_t i = 0; i < size; ++i) { auto key = this->read(); auto value = this->read(); map.emplace(std::move(key), std::move(value)); } } template Map read_map() { Map map{}; this->read_map(map); return map; } template void read_string(std::basic_string& result) { const auto size = this->read(); result.clear(); result.reserve(static_cast(size)); for (uint64_t i = 0; i < size; ++i) { result.push_back(this->read()); } } template std::basic_string read_string() { std::basic_string result{}; this->read_string(result); return result; } size_t get_remaining_size() const { return this->buffer_.size() - offset_; } std::span get_remaining_data() { return this->read_data(this->get_remaining_size()); } size_t get_offset() const { return this->offset_; } template requires(std::is_invocable_r_v) void register_factory(F factory) { this->factories_[std::type_index(typeid(T))] = [f = std::move(factory)]() -> T* { return new T(f()); }; } private: size_t offset_{0}; std::span buffer_{}; std::unordered_map> factories_{}; template T construct_object() { if constexpr (detail::has_deserializer_constructor::value) { return T(*this); } else if constexpr (std::is_default_constructible_v) { return {}; } else { const auto factory = this->factories_.find(std::type_index(typeid(T))); if (factory == this->factories_.end()) { throw std::runtime_error("Object construction failed. Missing factory for type: " + std::string(typeid(T).name())); } auto* object = static_cast(factory->second()); auto obj = std::move(*object); delete object; return obj; } } }; template <> inline void buffer_deserializer::read(bool& object) { object = this->read() != 0; } template <> inline void buffer_deserializer::read(std::string& object) { object = this->read_string(); } template <> inline void buffer_deserializer::read(std::wstring& object) { object = this->read_string(); } template <> inline void buffer_deserializer::read(std::u16string& object) { object = this->read_string(); } template <> inline void buffer_serializer::write(const bool& object) { this->write(object ? 1 : 0); } template <> inline void buffer_serializer::write(const std::string& object) { this->write_string(object); } template <> inline void buffer_serializer::write(const std::wstring& object) { this->write_string(object); } template <> inline void buffer_serializer::write(const std::u16string& object) { this->write_string(object); } }