mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-28 07:21:02 +00:00
Finish context saving/restoration
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <string_view>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
|
||||
@@ -20,32 +21,52 @@ namespace utils
|
||||
namespace detail
|
||||
{
|
||||
template <typename, typename = void>
|
||||
struct has_serialize_function : std::false_type {};
|
||||
struct has_serialize_function : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_serialize_function<T, std::void_t<decltype(serialize(std::declval<buffer_serializer&>(), std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
struct has_serialize_function<T, std::void_t<decltype(serialize(std::declval<buffer_serializer&>(),
|
||||
std::declval<const T&>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename, typename = void>
|
||||
struct has_deserialize_function : std::false_type {};
|
||||
struct has_deserialize_function : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_deserialize_function<T, std::void_t<decltype(deserialize(std::declval<buffer_deserializer&>(), std::declval<T&>()))>>
|
||||
: std::true_type {};
|
||||
struct has_deserialize_function<T, std::void_t<decltype(deserialize(
|
||||
std::declval<buffer_deserializer&>(), std::declval<T&>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
class buffer_deserializer
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
buffer_deserializer(const std::span<T>& buffer)
|
||||
buffer_deserializer(const std::span<T> buffer)
|
||||
: buffer_(reinterpret_cast<const std::byte*>(buffer.data()), buffer.size() * sizeof(T))
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
buffer_deserializer(const std::vector<T>& buffer)
|
||||
: buffer_deserializer(std::span(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
std::span<const std::byte> read_data(const size_t length)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const uint64_t real_old_size = this->offset_;
|
||||
#endif
|
||||
|
||||
if (this->offset_ + length > this->buffer_.size())
|
||||
{
|
||||
throw std::runtime_error("Out of bounds read from byte buffer");
|
||||
@@ -54,6 +75,23 @@ namespace utils
|
||||
const std::span result(this->buffer_.data() + this->offset_, length);
|
||||
this->offset_ += length;
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
uint64_t old_size{};
|
||||
if (this->offset_ + sizeof(old_size) > this->buffer_.size())
|
||||
{
|
||||
throw std::runtime_error("Out of bounds read from byte buffer");
|
||||
}
|
||||
|
||||
memcpy(&old_size, this->buffer_.data() + this->offset_, sizeof(old_size));
|
||||
if (old_size != real_old_size)
|
||||
{
|
||||
throw std::runtime_error("Reading from serialized buffer mismatches written data!");
|
||||
}
|
||||
|
||||
this->offset_ += sizeof(old_size);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -64,10 +102,8 @@ namespace utils
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T read()
|
||||
void read(T& object)
|
||||
{
|
||||
T object{};
|
||||
|
||||
if constexpr (std::is_base_of_v<serializable, T>)
|
||||
{
|
||||
object.deserialize(*this);
|
||||
@@ -78,63 +114,98 @@ namespace utils
|
||||
}
|
||||
else if constexpr (std::is_trivially_copyable_v<T>)
|
||||
{
|
||||
this->read(&object, sizeof(object));
|
||||
union
|
||||
{
|
||||
T* type_{};
|
||||
void* void_;
|
||||
} pointers;
|
||||
|
||||
pointers.type_ = &object;
|
||||
|
||||
this->read(pointers.void_, sizeof(object));
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(std::false_type::value, "Key must be trivially copyable or implement serializable!");
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T read()
|
||||
{
|
||||
T object{};
|
||||
this->read(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void read_vector(std::vector<T>& result)
|
||||
{
|
||||
const auto size = this->read<uint64_t>();
|
||||
result.clear();
|
||||
result.reserve(size);
|
||||
|
||||
for (uint64_t i = 0; i < size; ++i)
|
||||
{
|
||||
result.emplace_back(this->read<T>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> read_vector()
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
|
||||
|
||||
std::vector<T> result{};
|
||||
const auto size = this->read<uint64_t>();
|
||||
const auto totalSize = size * sizeof(T);
|
||||
|
||||
if (this->offset_ + totalSize > this->buffer_.size())
|
||||
{
|
||||
throw std::runtime_error("Out of bounds read from byte buffer");
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
this->read(result.data(), totalSize);
|
||||
|
||||
this->read_vector(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
std::map<Key, Value> read_map()
|
||||
template <typename Map>
|
||||
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<uint64_t>();
|
||||
std::map<Key, Value> map{};
|
||||
|
||||
for (uint64_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto key = this->read<Key>();
|
||||
auto value = this->read<Value>();
|
||||
auto key = this->read<key_type>();
|
||||
auto value = this->read<value_type>();
|
||||
|
||||
map[std::move(key)] = std::move(value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Map>
|
||||
Map read_map()
|
||||
{
|
||||
Map map{};
|
||||
this->read_map(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
std::string read_string()
|
||||
template <typename T = char>
|
||||
void read_string(std::basic_string<T>& result)
|
||||
{
|
||||
std::string result{};
|
||||
const auto size = this->read<uint64_t>();
|
||||
const auto span = this->read_data(size);
|
||||
|
||||
result.resize(size);
|
||||
memcpy(result.data(), span.data(), size);
|
||||
result.clear();
|
||||
result.reserve(size);
|
||||
|
||||
for (uint64_t i = 0; i < size; ++i)
|
||||
{
|
||||
result.push_back(this->read<T>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T= char>
|
||||
std::basic_string<T> read_string()
|
||||
{
|
||||
std::basic_string<T> result{};
|
||||
this->read_string(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -165,7 +236,17 @@ namespace utils
|
||||
|
||||
void write(const void* buffer, const size_t length)
|
||||
{
|
||||
this->buffer_.append(static_cast<const char*>(buffer), length);
|
||||
#ifndef NDEBUG
|
||||
const uint64_t old_size = this->buffer_.size();
|
||||
#endif
|
||||
|
||||
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)
|
||||
@@ -187,7 +268,15 @@ namespace utils
|
||||
}
|
||||
else if constexpr (std::is_trivially_copyable_v<T>)
|
||||
{
|
||||
this->write(&object, sizeof(object));
|
||||
union
|
||||
{
|
||||
const T* type_{};
|
||||
const void* void_;
|
||||
} pointers;
|
||||
|
||||
pointers.type_ = &object;
|
||||
|
||||
this->write(pointers.void_, sizeof(object));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -207,8 +296,26 @@ namespace utils
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
void write_map(const std::map<Key, Value>& map)
|
||||
template <typename T>
|
||||
void write_vector(const std::vector<T> vec)
|
||||
{
|
||||
this->write_span(std::span(vec));
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
@@ -219,17 +326,41 @@ namespace utils
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& get_buffer() const
|
||||
const std::vector<std::byte>& get_buffer() const
|
||||
{
|
||||
return this->buffer_;
|
||||
}
|
||||
|
||||
std::string move_buffer()
|
||||
std::vector<std::byte> move_buffer()
|
||||
{
|
||||
return std::move(this->buffer_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string buffer_{};
|
||||
std::vector<std::byte> buffer_{};
|
||||
};
|
||||
|
||||
template <>
|
||||
inline void buffer_deserializer::read<std::string>(std::string& object)
|
||||
{
|
||||
object = this->read_string<char>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void buffer_deserializer::read<std::wstring>(std::wstring& object)
|
||||
{
|
||||
object = this->read_string<wchar_t>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void buffer_serializer::write<std::string>(const std::string& object)
|
||||
{
|
||||
this->write_string(object);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void buffer_serializer::write<std::wstring>(const std::wstring& object)
|
||||
{
|
||||
this->write_string(object);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user