Merge pull request #4908 from hamish-milne/feature/savestates-2

Save states
This commit is contained in:
Ben 2020-04-17 21:52:51 +02:00 committed by GitHub
commit c605bb42db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
354 changed files with 6100 additions and 604 deletions

View file

@ -54,6 +54,7 @@ add_custom_command(OUTPUT scm_rev.cpp
add_library(common STATIC
alignment.h
announce_multiplayer_room.h
archives.h
assert.h
detached_tasks.cpp
detached_tasks.h
@ -66,6 +67,7 @@ add_library(common STATIC
common_funcs.h
common_paths.h
common_types.h
construct.h
file_util.cpp
file_util.h
hash.h
@ -78,6 +80,8 @@ add_library(common STATIC
logging/text_formatter.cpp
logging/text_formatter.h
math_util.h
memory_ref.h
memory_ref.cpp
microprofile.cpp
microprofile.h
microprofileui.h
@ -89,6 +93,11 @@ add_library(common STATIC
scm_rev.cpp
scm_rev.h
scope_exit.h
serialization/atomic.h
serialization/boost_discrete_interval.hpp
serialization/boost_flat_set.h
serialization/boost_small_vector.hpp
serialization/boost_vector.hpp
string_util.cpp
string_util.h
swap.h
@ -121,7 +130,7 @@ endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC fmt microprofile)
target_link_libraries(common PUBLIC fmt microprofile Boost::boost Boost::serialization)
target_link_libraries(common PRIVATE libzstd_static)
if (ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak)

21
src/common/archives.h Normal file
View file

@ -0,0 +1,21 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/export.hpp>
using iarchive = boost::archive::binary_iarchive;
using oarchive = boost::archive::binary_oarchive;
#define SERIALIZE_IMPL(A) \
template void A::serialize<iarchive>(iarchive & ar, const unsigned int file_version); \
template void A::serialize<oarchive>(oarchive & ar, const unsigned int file_version);
#define SERIALIZE_EXPORT_IMPL(A) \
BOOST_CLASS_EXPORT_IMPLEMENT(A) \
BOOST_SERIALIZATION_REGISTER_ARCHIVE(iarchive) \
BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive)

View file

@ -47,6 +47,7 @@
#define DUMP_DIR "dump"
#define LOAD_DIR "load"
#define SHADER_DIR "shaders"
#define STATES_DIR "states"
// Filenames
// Files in the directory returned by GetUserPath(UserPath::LogDir)

34
src/common/construct.h Normal file
View file

@ -0,0 +1,34 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <boost/serialization/serialization.hpp>
/// Allows classes to define `save_construct` and `load_construct` methods for serialization
/// This is used where we don't call the default constructor during deserialization, as a shortcut
/// instead of using load_construct_data directly
class construct_access {
public:
template <class Archive, class T>
static void save_construct(Archive& ar, const T* t, const unsigned int file_version) {
t->save_construct(ar, file_version);
}
template <class Archive, class T>
static void load_construct(Archive& ar, T* t, const unsigned int file_version) {
T::load_construct(ar, t, file_version);
}
};
#define BOOST_SERIALIZATION_CONSTRUCT(T) \
namespace boost::serialization { \
template <class Archive> \
void save_construct_data(Archive& ar, const T* t, const unsigned int file_version) { \
construct_access::save_construct(ar, t, file_version); \
} \
template <class Archive> \
void load_construct_data(Archive& ar, T* t, const unsigned int file_version) { \
construct_access::load_construct(ar, t, file_version); \
} \
}

View file

@ -726,6 +726,34 @@ void SetUserPath(const std::string& path) {
g_paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
g_paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
g_paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
g_paths.emplace(UserPath::StatesDir, user_path + STATES_DIR DIR_SEP);
}
std::string g_currentRomPath{};
void SetCurrentRomPath(const std::string& path) {
g_currentRomPath = path;
}
bool StringReplace(std::string& haystack, const std::string& a, const std::string& b, bool swap) {
const auto& needle = swap ? b : a;
const auto& replacement = swap ? a : b;
if (needle.empty()) {
return false;
}
auto index = haystack.find(needle, 0);
if (index == std::string::npos) {
return false;
}
haystack.replace(index, needle.size(), replacement);
return true;
}
std::string SerializePath(const std::string& input, bool is_saving) {
auto result = input;
StringReplace(result, "%CITRA_ROM_FILE%", g_currentRomPath, is_saving);
StringReplace(result, "%CITRA_USER_DIR%", GetUserPath(UserPath::UserDir), is_saving);
return result;
}
const std::string& GetUserPath(UserPath path) {
@ -882,8 +910,9 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
IOFile::IOFile() {}
IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
Open(filename, openmode, flags);
IOFile::IOFile(const std::string& filename, const char openmode[], int flags)
: filename(filename), openmode(openmode), flags(flags) {
Open();
}
IOFile::~IOFile() {
@ -902,10 +931,14 @@ IOFile& IOFile::operator=(IOFile&& other) noexcept {
void IOFile::Swap(IOFile& other) noexcept {
std::swap(m_file, other.m_file);
std::swap(m_good, other.m_good);
std::swap(filename, other.filename);
std::swap(openmode, other.openmode);
std::swap(flags, other.flags);
}
bool IOFile::Open(const std::string& filename, const char openmode[], int flags) {
bool IOFile::Open() {
Close();
#ifdef _WIN32
if (flags != 0) {
m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(),
@ -916,7 +949,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[], int flags)
Common::UTF8ToUTF16W(openmode).c_str()) == 0;
}
#else
m_file = std::fopen(filename.c_str(), openmode);
m_file = std::fopen(filename.c_str(), openmode.c_str());
m_good = m_file != nullptr;
#endif

View file

@ -14,6 +14,9 @@
#include <string_view>
#include <type_traits>
#include <vector>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/wrapper.hpp>
#include "common/common_types.h"
#ifdef _MSC_VER
#include "common/string_util.h"
@ -34,10 +37,39 @@ enum class UserPath {
RootDir,
SDMCDir,
ShaderDir,
StatesDir,
SysDataDir,
UserDir,
};
// Replaces install-specific paths with standard placeholders, and back again
std::string SerializePath(const std::string& input, bool is_saving);
// A serializable path string
struct Path : public boost::serialization::wrapper_traits<const Path> {
std::string& str;
explicit Path(std::string& _str) : str(_str) {}
static const Path make(std::string& str) {
return Path(str);
}
template <class Archive>
void save(Archive& ar, const unsigned int) const {
auto s_path = SerializePath(str, true);
ar << s_path;
}
template <class Archive>
void load(Archive& ar, const unsigned int) const {
ar >> str;
str = SerializePath(str, false);
}
BOOST_SERIALIZATION_SPLIT_MEMBER();
friend class boost::serialization::access;
};
// FileSystem tree node/
struct FSTEntry {
bool isDirectory;
@ -45,6 +77,17 @@ struct FSTEntry {
std::string physicalName; // name on disk
std::string virtualName; // name in FST names table
std::vector<FSTEntry> children;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& isDirectory;
ar& size;
ar& Path::make(physicalName);
ar& Path::make(virtualName);
ar& children;
}
friend class boost::serialization::access;
};
// Returns true if file filename exists
@ -137,6 +180,8 @@ bool SetCurrentDir(const std::string& directory);
void SetUserPath(const std::string& path = "");
void SetCurrentRomPath(const std::string& path);
// Returns a pointer to a string with a Citra data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(UserPath path);
@ -221,7 +266,6 @@ public:
void Swap(IOFile& other) noexcept;
bool Open(const std::string& filename, const char openmode[], int flags = 0);
bool Close();
template <typename T>
@ -305,8 +349,31 @@ public:
}
private:
bool Open();
std::FILE* m_file = nullptr;
bool m_good = true;
std::string filename;
std::string openmode;
u32 flags;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& Path::make(filename);
ar& openmode;
ar& flags;
u64 pos;
if (Archive::is_saving::value) {
pos = Tell();
}
ar& pos;
if (Archive::is_loading::value) {
Open();
Seek(pos, SEEK_SET);
}
}
friend class boost::serialization::access;
};
} // namespace FileUtil

View file

@ -0,0 +1,8 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "common/memory_ref.h"
SERIALIZE_EXPORT_IMPL(BufferMem)

136
src/common/memory_ref.h Normal file
View file

@ -0,0 +1,136 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <vector>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "common/assert.h"
#include "common/common_types.h"
/// Abstract host-side memory - for example a static buffer, or local vector
class BackingMem {
public:
virtual ~BackingMem() = default;
virtual u8* GetPtr() = 0;
virtual const u8* GetPtr() const = 0;
virtual std::size_t GetSize() const = 0;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {}
friend class boost::serialization::access;
};
/// Backing memory implemented by a local buffer
class BufferMem : public BackingMem {
public:
BufferMem() = default;
explicit BufferMem(std::size_t size) : data(size) {}
u8* GetPtr() override {
return data.data();
}
const u8* GetPtr() const override {
return data.data();
}
std::size_t GetSize() const override {
return data.size();
}
std::vector<u8>& Vector() {
return data;
}
const std::vector<u8>& Vector() const {
return data;
}
private:
std::vector<u8> data;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<BackingMem>(*this);
ar& data;
}
friend class boost::serialization::access;
};
BOOST_CLASS_EXPORT_KEY(BufferMem);
/// A managed reference to host-side memory. Fast enough to be used everywhere instead of u8*
/// Supports serialization.
class MemoryRef {
public:
MemoryRef() = default;
MemoryRef(std::nullptr_t) {}
MemoryRef(std::shared_ptr<BackingMem> backing_mem_)
: backing_mem(std::move(backing_mem_)), offset(0) {
Init();
}
MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u64 offset_)
: backing_mem(std::move(backing_mem_)), offset(offset_) {
ASSERT(offset < backing_mem->GetSize());
Init();
}
explicit operator bool() const {
return cptr != nullptr;
}
operator u8*() {
return cptr;
}
u8* GetPtr() {
return cptr;
}
operator const u8*() const {
return cptr;
}
const u8* GetPtr() const {
return cptr;
}
std::size_t GetSize() const {
return csize;
}
MemoryRef& operator+=(u32 offset_by) {
ASSERT(offset_by < csize);
offset += offset_by;
Init();
return *this;
}
MemoryRef operator+(u32 offset_by) const {
ASSERT(offset_by < csize);
return MemoryRef(backing_mem, offset + offset_by);
}
private:
std::shared_ptr<BackingMem> backing_mem{};
u64 offset{};
// Cached values for speed
u8* cptr{};
std::size_t csize{};
void Init() {
if (backing_mem) {
cptr = backing_mem->GetPtr() + offset;
csize = static_cast<std::size_t>(backing_mem->GetSize() - offset);
} else {
cptr = nullptr;
csize = 0;
}
}
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& backing_mem;
ar& offset;
Init();
}
friend class boost::serialization::access;
};

View file

@ -0,0 +1,29 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <atomic>
#include <boost/serialization/split_free.hpp>
namespace boost::serialization {
template <class Archive, class T>
void serialize(Archive& ar, std::atomic<T>& value, const unsigned int file_version) {
boost::serialization::split_free(ar, value, file_version);
}
template <class Archive, class T>
void save(Archive& ar, const std::atomic<T>& value, const unsigned int file_version) {
ar << value.load();
}
template <class Archive, class T>
void load(Archive& ar, std::atomic<T>& value, const unsigned int file_version) {
T tmp;
ar >> tmp;
value.store(tmp);
}
} // namespace boost::serialization

View file

@ -0,0 +1,38 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <boost/icl/discrete_interval.hpp>
#include "common/common_types.h"
#include "common/logging/log.h"
namespace boost::serialization {
template <class Archive, class DomainT, ICL_COMPARE Compare>
void save(Archive& ar, const boost::icl::discrete_interval<DomainT, Compare>& obj,
const unsigned int file_version) {
ar << obj.lower();
ar << obj.upper();
ar << obj.bounds()._bits;
}
template <class Archive, class DomainT, ICL_COMPARE Compare>
void load(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj,
const unsigned int file_version) {
DomainT upper, lower;
boost::icl::bound_type bounds;
ar >> lower;
ar >> upper;
ar >> bounds;
obj = boost::icl::discrete_interval(lower, upper, boost::icl::interval_bounds(bounds));
}
template <class Archive, class DomainT, ICL_COMPARE Compare>
void serialize(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj,
const unsigned int file_version) {
boost::serialization::split_free(ar, obj, file_version);
}
} // namespace boost::serialization

View file

@ -0,0 +1,38 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <boost/container/flat_set.hpp>
#include <boost/serialization/split_free.hpp>
#include "common/common_types.h"
namespace boost::serialization {
template <class Archive, class T>
void save(Archive& ar, const boost::container::flat_set<T>& set, const unsigned int file_version) {
ar << static_cast<u64>(set.size());
for (auto& v : set) {
ar << v;
}
}
template <class Archive, class T>
void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version) {
u64 count{};
ar >> count;
set.clear();
for (u64 i = 0; i < count; i++) {
T value{};
ar >> value;
set.insert(value);
}
}
template <class Archive, class T>
void serialize(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version) {
boost::serialization::split_free(ar, set, file_version);
}
} // namespace boost::serialization

View file

@ -0,0 +1,38 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <boost/icl/interval_set.hpp>
#include <boost/serialization/split_free.hpp>
#include "common/serialization/boost_discrete_interval.hpp"
namespace boost::serialization {
template <class Archive, class T>
void save(Archive& ar, const boost::icl::interval_set<T>& set, const unsigned int file_version) {
ar << static_cast<u64>(set.iterative_size());
for (auto& v : set) {
ar << v;
}
}
template <class Archive, class T>
void load(Archive& ar, boost::icl::interval_set<T>& set, const unsigned int file_version) {
u64 count{};
ar >> count;
set.clear();
for (u64 i = 0; i < count; i++) {
typename boost::icl::interval_set<T>::interval_type value{};
ar >> value;
set += value;
}
}
template <class Archive, class T>
void serialize(Archive& ar, boost::icl::interval_set<T>& set, const unsigned int file_version) {
boost::serialization::split_free(ar, set, file_version);
}
} // namespace boost::serialization

View file

@ -0,0 +1,144 @@
#ifndef BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
#define BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
#pragma once
#endif
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// boost_vector.hpp: serialization for boost vector templates
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// fast array serialization (C) Copyright 2005 Matthias Troyer
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#include <boost/container/small_vector.hpp>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/archive/detail/basic_iarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/collection_size_type.hpp>
#include <boost/serialization/item_version_type.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/mpl/bool_fwd.hpp>
#include <boost/mpl/if.hpp>
#include <boost/serialization/array_wrapper.hpp>
#include <boost/serialization/collections_load_imp.hpp>
#include <boost/serialization/collections_save_imp.hpp>
#include <boost/serialization/split_free.hpp>
// default is being compatible with version 1.34.1 files, not 1.35 files
#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5)
#endif
namespace boost {
namespace serialization {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// vector< T >
// the default versions
template <class Archive, class U, std::size_t N>
inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
const unsigned int /* file_version */, mpl::false_) {
boost::serialization::stl::save_collection<Archive, boost::container::small_vector<U, N>>(ar,
t);
}
template <class Archive, class U, std::size_t N>
inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
const unsigned int /* file_version */, mpl::false_) {
const boost::archive::library_version_type library_version(ar.get_library_version());
// retrieve number of elements
item_version_type item_version(0);
collection_size_type count;
ar >> BOOST_SERIALIZATION_NVP(count);
if (boost::archive::library_version_type(3) < library_version) {
ar >> BOOST_SERIALIZATION_NVP(item_version);
}
t.reserve(count);
stl::collection_load_impl(ar, t, count, item_version);
}
// the optimized versions
template <class Archive, class U, std::size_t N>
inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
const unsigned int /* file_version */, mpl::true_) {
const collection_size_type count(t.size());
ar << BOOST_SERIALIZATION_NVP(count);
if (!t.empty())
// explict template arguments to pass intel C++ compiler
ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]),
count);
}
template <class Archive, class U, std::size_t N>
inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
const unsigned int /* file_version */, mpl::true_) {
collection_size_type count(t.size());
ar >> BOOST_SERIALIZATION_NVP(count);
t.resize(count);
unsigned int item_version = 0;
if (BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
ar >> BOOST_SERIALIZATION_NVP(item_version);
}
if (!t.empty())
// explict template arguments to pass intel C++ compiler
ar >> serialization::make_array<U, collection_size_type>(static_cast<U*>(&t[0]), count);
}
// dispatch to either default or optimized versions
template <class Archive, class U, std::size_t N>
inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
const unsigned int file_version) {
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
typename remove_const<U>::type>::type use_optimized;
save(ar, t, file_version, use_optimized());
}
template <class Archive, class U, std::size_t N>
inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
const unsigned int file_version) {
#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
if (ar.get_library_version() == boost::archive::library_version_type(5)) {
load(ar, t, file_version, boost::is_arithmetic<U>());
return;
}
#endif
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
typename remove_const<U>::type>::type use_optimized;
load(ar, t, file_version, use_optimized());
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template <class Archive, class U, std::size_t N>
inline void serialize(Archive& ar, boost::container::small_vector<U, N>& t,
const unsigned int file_version) {
boost::serialization::split_free(ar, t, file_version);
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template <class Archive, std::size_t N>
inline void serialize(Archive& ar, boost::container::small_vector<bool, N>& t,
const unsigned int file_version) {
boost::serialization::split_free(ar, t, file_version);
}
} // namespace serialization
} // namespace boost
#endif // BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP

View file

@ -0,0 +1,149 @@
#ifndef BOOST_SERIALIZATION_BOOST_VECTOR_HPP
#define BOOST_SERIALIZATION_BOOST_VECTOR_HPP
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
#pragma once
#endif
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// boost_vector.hpp: serialization for boost vector templates
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// fast array serialization (C) Copyright 2005 Matthias Troyer
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#include <boost/container/vector.hpp>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/archive/detail/basic_iarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/collection_size_type.hpp>
#include <boost/serialization/item_version_type.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/mpl/bool_fwd.hpp>
#include <boost/mpl/if.hpp>
#include <boost/serialization/array_wrapper.hpp>
#include <boost/serialization/collections_load_imp.hpp>
#include <boost/serialization/collections_save_imp.hpp>
#include <boost/serialization/split_free.hpp>
// default is being compatible with version 1.34.1 files, not 1.35 files
#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5)
#endif
namespace boost {
namespace serialization {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// vector< T >
// the default versions
template <class Archive, class U, class Allocator, class Options>
inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
const unsigned int /* file_version */, mpl::false_) {
boost::serialization::stl::save_collection<Archive,
boost::container::vector<U, Allocator, Options>>(ar,
t);
}
template <class Archive, class U, class Allocator, class Options>
inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
const unsigned int /* file_version */, mpl::false_) {
const boost::archive::library_version_type library_version(ar.get_library_version());
// retrieve number of elements
item_version_type item_version(0);
collection_size_type count;
ar >> BOOST_SERIALIZATION_NVP(count);
if (boost::archive::library_version_type(3) < library_version) {
ar >> BOOST_SERIALIZATION_NVP(item_version);
}
t.reserve(count);
stl::collection_load_impl(ar, t, count, item_version);
}
// the optimized versions
template <class Archive, class U, class Allocator, class Options>
inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
const unsigned int /* file_version */, mpl::true_) {
const collection_size_type count(t.size());
ar << BOOST_SERIALIZATION_NVP(count);
if (!t.empty())
// explict template arguments to pass intel C++ compiler
ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]),
count);
}
template <class Archive, class U, class Allocator, class Options>
inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
const unsigned int /* file_version */, mpl::true_) {
collection_size_type count(t.size());
ar >> BOOST_SERIALIZATION_NVP(count);
t.resize(count);
unsigned int item_version = 0;
if (BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
ar >> BOOST_SERIALIZATION_NVP(item_version);
}
if (!t.empty())
// explict template arguments to pass intel C++ compiler
ar >> serialization::make_array<U, collection_size_type>(static_cast<U*>(&t[0]), count);
}
// dispatch to either default or optimized versions
template <class Archive, class U, class Allocator, class Options>
inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
const unsigned int file_version) {
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
typename remove_const<U>::type>::type use_optimized;
save(ar, t, file_version, use_optimized());
}
template <class Archive, class U, class Allocator, class Options>
inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
const unsigned int file_version) {
#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
if (ar.get_library_version() == boost::archive::library_version_type(5)) {
load(ar, t, file_version, boost::is_arithmetic<U>());
return;
}
#endif
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
typename remove_const<U>::type>::type use_optimized;
load(ar, t, file_version, use_optimized());
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template <class Archive, class U, class Allocator, class Options>
inline void serialize(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
const unsigned int file_version) {
boost::serialization::split_free(ar, t, file_version);
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template <class Archive, class Allocator, class Options>
inline void serialize(Archive& ar, boost::container::vector<bool, Allocator, Options>& t,
const unsigned int file_version) {
boost::serialization::split_free(ar, t, file_version);
}
} // namespace serialization
} // namespace boost
#include <boost/serialization/collection_traits.hpp>
BOOST_SERIALIZATION_COLLECTION_TRAITS(boost::container::vector)
#endif // BOOST_SERIALIZATION_BOOST_VECTOR_HPP

View file

@ -7,6 +7,9 @@
#include <algorithm>
#include <array>
#include <deque>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/split_member.hpp>
#include "common/common_types.h"
namespace Common {
@ -157,6 +160,52 @@ private:
Queue* first;
// The priority level queues of thread ids.
std::array<Queue, NUM_QUEUES> queues;
s64 ToIndex(const Queue* q) const {
if (q == nullptr) {
return -2;
} else if (q == UnlinkedTag()) {
return -1;
} else {
return q - queues.data();
}
}
Queue* ToPointer(s64 idx) {
if (idx == -1) {
return UnlinkedTag();
} else if (idx < 0) {
return nullptr;
} else {
return &queues[idx];
}
}
friend class boost::serialization::access;
template <class Archive>
void save(Archive& ar, const unsigned int file_version) const {
const s64 idx = ToIndex(first);
ar << idx;
for (std::size_t i = 0; i < NUM_QUEUES; i++) {
const s64 idx1 = ToIndex(queues[i].next_nonempty);
ar << idx1;
ar << queues[i].data;
}
}
template <class Archive>
void load(Archive& ar, const unsigned int file_version) {
s64 idx;
ar >> idx;
first = ToPointer(idx);
for (std::size_t i = 0; i < NUM_QUEUES; i++) {
ar >> idx;
queues[i].next_nonempty = ToPointer(idx);
ar >> queues[i].data;
}
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
};
} // namespace Common

View file

@ -32,6 +32,7 @@
#include <cmath>
#include <type_traits>
#include <boost/serialization/access.hpp>
namespace Common {
@ -44,6 +45,13 @@ class Vec4;
template <typename T>
class Vec2 {
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& x;
ar& y;
}
public:
T x;
T y;
@ -191,6 +199,14 @@ inline float Vec2<float>::Normalize() {
template <typename T>
class Vec3 {
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& x;
ar& y;
ar& z;
}
public:
T x;
T y;
@ -399,6 +415,15 @@ using Vec3f = Vec3<float>;
template <typename T>
class Vec4 {
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& x;
ar& y;
ar& z;
ar& w;
}
public:
T x;
T y;