// SPDX-FileCopyrightText: Copyright 2025-2026 shadBloodborne Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include "common/assert.h" #include "common/types.h" #include #include namespace Serialization { template concept Container = requires(T t) { typename T::iterator; { t.begin() } -> std::same_as; { t.end() } -> std::same_as; { t.size() } -> std::convertible_to; }; struct Archive { void Alloc(size_t size) { container.resize(size); } void Grow(size_t size) { container.resize(container.size() + size); } void Merge(const Archive& ar) { container.insert(container.end(), ar.container.cbegin(), ar.container.cend()); offset = container.size(); } [[nodiscard]] size_t SizeBytes() const { return container.size(); } u8* CurrPtr() { return container.data() + offset; } void Advance(size_t size) { ASSERT(offset + size <= container.size()); offset += size; } std::vector&& TakeOff() { offset = 0; return std::move(container); } [[nodiscard]] bool IsEoS() const { return offset >= container.size(); } Archive() = default; explicit Archive(std::vector&& v) : container{v} {} private: u32 offset{}; std::vector container{}; friend struct Writer; friend struct Reader; }; struct Writer { template void Write(const T* ptr, size_t size) { if (ar.offset + size >= ar.container.size()) { ar.Grow(size); } std::memcpy(ar.CurrPtr(), reinterpret_cast(ptr), size); ar.Advance(size); } template requires(!Container) void Write(const T& value) { const auto size = sizeof(value); Write(&value, size); } void Write(const auto& v) { Write(v.size()); for (const auto& elem : v) { Write(elem); } } void Write(const std::string& s) { Write(s.size()); Write(s.c_str(), s.size()); } Writer() = delete; explicit Writer(Archive& ar_) : ar{ar_} {} Archive& ar; }; struct Reader { template void Read(T* ptr, size_t size) { ASSERT(ar.offset + size <= ar.container.size()); std::memcpy(reinterpret_cast(ptr), ar.CurrPtr(), size); ar.Advance(size); } template requires(!Container) void Read(T& value) { const auto size = sizeof(value); Read(&value, size); } void Read(auto& v) { size_t num_elements{}; Read(num_elements); for (int i = 0; i < num_elements; ++i) { v.emplace_back(); Read(v.back()); } } void Read(std::string& s) { size_t length{}; Read(length); s.resize(length); Read(s.data(), length); } Reader() = delete; explicit Reader(Archive& ar_) : ar{ar_} {} Archive& ar; }; } // namespace Serialization