mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-02 11:03:34 -06:00
142 lines
3.1 KiB
C++
142 lines
3.1 KiB
C++
// 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 <cstddef>
|
|
#include <vector>
|
|
|
|
namespace Serialization {
|
|
|
|
template <typename T>
|
|
concept Container = requires(T t) {
|
|
typename T::iterator;
|
|
{ t.begin() } -> std::same_as<typename T::iterator>;
|
|
{ t.end() } -> std::same_as<typename T::iterator>;
|
|
{ t.size() } -> std::convertible_to<std::size_t>;
|
|
};
|
|
|
|
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<u8>&& TakeOff() {
|
|
offset = 0;
|
|
return std::move(container);
|
|
}
|
|
|
|
[[nodiscard]] bool IsEoS() const {
|
|
return offset >= container.size();
|
|
}
|
|
|
|
Archive() = default;
|
|
explicit Archive(std::vector<u8>&& v) : container{v} {}
|
|
|
|
private:
|
|
u32 offset{};
|
|
std::vector<u8> container{};
|
|
|
|
friend struct Writer;
|
|
friend struct Reader;
|
|
};
|
|
|
|
struct Writer {
|
|
template <typename T>
|
|
void Write(const T* ptr, size_t size) {
|
|
if (ar.offset + size >= ar.container.size()) {
|
|
ar.Grow(size);
|
|
}
|
|
std::memcpy(ar.CurrPtr(), reinterpret_cast<const void*>(ptr), size);
|
|
ar.Advance(size);
|
|
}
|
|
|
|
template <typename T>
|
|
requires(!Container<T>)
|
|
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 <typename T>
|
|
void Read(T* ptr, size_t size) {
|
|
ASSERT(ar.offset + size <= ar.container.size());
|
|
std::memcpy(reinterpret_cast<void*>(ptr), ar.CurrPtr(), size);
|
|
ar.Advance(size);
|
|
}
|
|
|
|
template <typename T>
|
|
requires(!Container<T>)
|
|
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
|