mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #4908 from hamish-milne/feature/savestates-2
Save states
This commit is contained in:
		
						commit
						c605bb42db
					
				
					 354 changed files with 6100 additions and 604 deletions
				
			
		|  | @ -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
									
								
							
							
						
						
									
										21
									
								
								src/common/archives.h
									
										
									
									
									
										Normal 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) | ||||
|  | @ -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
									
								
							
							
						
						
									
										34
									
								
								src/common/construct.h
									
										
									
									
									
										Normal 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);                                     \ | ||||
|     }                                                                                              \ | ||||
|     } | ||||
|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
							
								
								
									
										8
									
								
								src/common/memory_ref.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/common/memory_ref.cpp
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										136
									
								
								src/common/memory_ref.h
									
										
									
									
									
										Normal 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; | ||||
| }; | ||||
							
								
								
									
										29
									
								
								src/common/serialization/atomic.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/common/serialization/atomic.h
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										38
									
								
								src/common/serialization/boost_discrete_interval.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/common/serialization/boost_discrete_interval.hpp
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										38
									
								
								src/common/serialization/boost_flat_set.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/common/serialization/boost_flat_set.h
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										38
									
								
								src/common/serialization/boost_interval_set.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/common/serialization/boost_interval_set.hpp
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										144
									
								
								src/common/serialization/boost_small_vector.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/common/serialization/boost_small_vector.hpp
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										149
									
								
								src/common/serialization/boost_vector.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								src/common/serialization/boost_vector.hpp
									
										
									
									
									
										Normal 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
 | ||||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue