1 // Copyright 2008 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 // Extremely simple serialization framework. 8 9 // (mis)-features: 10 // + Super fast 11 // + Very simple 12 // + Same code is used for serialization and deserializaition (in most cases) 13 // - Zero backwards/forwards compatibility 14 // - Serialization code for anything complex has to be manually written. 15 16 #include <array> 17 #include <cstddef> 18 #include <cstring> 19 #include <deque> 20 #include <list> 21 #include <map> 22 #include <optional> 23 #include <set> 24 #include <string> 25 #include <type_traits> 26 #include <utility> 27 #include <vector> 28 29 #include "Common/Assert.h" 30 #include "Common/CommonTypes.h" 31 #include "Common/Flag.h" 32 #include "Common/Inline.h" 33 #include "Common/Logging/Log.h" 34 35 // XXX: Replace this with std::is_trivially_copyable<T> once we stop using volatile 36 // on things that are put in savestates, as volatile types are not trivially copyable. 37 template <typename T> 38 constexpr bool IsTriviallyCopyable = std::is_trivially_copyable<std::remove_volatile_t<T>>::value; 39 40 // Wrapper class 41 class PointerWrap 42 { 43 public: 44 enum Mode 45 { 46 MODE_READ = 1, // load 47 MODE_WRITE, // save 48 MODE_MEASURE, // calculate size 49 MODE_VERIFY, // compare 50 }; 51 52 u8** ptr; 53 Mode mode; 54 55 public: PointerWrap(u8 ** ptr_,Mode mode_)56 PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} SetMode(Mode mode_)57 void SetMode(Mode mode_) { mode = mode_; } GetMode()58 Mode GetMode() const { return mode; } 59 template <typename K, class V> Do(std::map<K,V> & x)60 void Do(std::map<K, V>& x) 61 { 62 u32 count = (u32)x.size(); 63 Do(count); 64 65 switch (mode) 66 { 67 case MODE_READ: 68 for (x.clear(); count != 0; --count) 69 { 70 std::pair<K, V> pair; 71 Do(pair.first); 72 Do(pair.second); 73 x.insert(pair); 74 } 75 break; 76 77 case MODE_WRITE: 78 case MODE_MEASURE: 79 case MODE_VERIFY: 80 for (auto& elem : x) 81 { 82 Do(elem.first); 83 Do(elem.second); 84 } 85 break; 86 } 87 } 88 89 template <typename V> Do(std::set<V> & x)90 void Do(std::set<V>& x) 91 { 92 u32 count = (u32)x.size(); 93 Do(count); 94 95 switch (mode) 96 { 97 case MODE_READ: 98 for (x.clear(); count != 0; --count) 99 { 100 V value; 101 Do(value); 102 x.insert(value); 103 } 104 break; 105 106 case MODE_WRITE: 107 case MODE_MEASURE: 108 case MODE_VERIFY: 109 for (const V& val : x) 110 { 111 Do(val); 112 } 113 break; 114 } 115 } 116 117 template <typename T> Do(std::vector<T> & x)118 void Do(std::vector<T>& x) 119 { 120 DoContiguousContainer(x); 121 } 122 123 template <typename T> Do(std::list<T> & x)124 void Do(std::list<T>& x) 125 { 126 DoContainer(x); 127 } 128 129 template <typename T> Do(std::deque<T> & x)130 void Do(std::deque<T>& x) 131 { 132 DoContainer(x); 133 } 134 135 template <typename T> Do(std::basic_string<T> & x)136 void Do(std::basic_string<T>& x) 137 { 138 DoContiguousContainer(x); 139 } 140 141 template <typename T, typename U> Do(std::pair<T,U> & x)142 void Do(std::pair<T, U>& x) 143 { 144 Do(x.first); 145 Do(x.second); 146 } 147 148 template <typename T> Do(std::optional<T> & x)149 void Do(std::optional<T>& x) 150 { 151 bool present = x.has_value(); 152 Do(present); 153 154 switch (mode) 155 { 156 case MODE_READ: 157 if (present) 158 { 159 x = std::make_optional<T>(); 160 Do(x.value()); 161 } 162 else 163 { 164 x = std::nullopt; 165 } 166 break; 167 168 case MODE_WRITE: 169 case MODE_MEASURE: 170 case MODE_VERIFY: 171 if (present) 172 Do(x.value()); 173 174 break; 175 } 176 } 177 178 template <typename T, std::size_t N> DoArray(std::array<T,N> & x)179 void DoArray(std::array<T, N>& x) 180 { 181 DoArray(x.data(), static_cast<u32>(x.size())); 182 } 183 184 template <typename T, typename std::enable_if_t<IsTriviallyCopyable<T>, int> = 0> DoArray(T * x,u32 count)185 void DoArray(T* x, u32 count) 186 { 187 DoVoid(x, count * sizeof(T)); 188 } 189 190 template <typename T, typename std::enable_if_t<!IsTriviallyCopyable<T>, int> = 0> DoArray(T * x,u32 count)191 void DoArray(T* x, u32 count) 192 { 193 for (u32 i = 0; i < count; ++i) 194 Do(x[i]); 195 } 196 197 template <typename T, std::size_t N> DoArray(T (& arr)[N])198 void DoArray(T (&arr)[N]) 199 { 200 DoArray(arr, static_cast<u32>(N)); 201 } 202 Do(Common::Flag & flag)203 void Do(Common::Flag& flag) 204 { 205 bool s = flag.IsSet(); 206 Do(s); 207 if (mode == MODE_READ) 208 flag.Set(s); 209 } 210 211 template <typename T> Do(std::atomic<T> & atomic)212 void Do(std::atomic<T>& atomic) 213 { 214 T temp = atomic.load(); 215 Do(temp); 216 if (mode == MODE_READ) 217 atomic.store(temp); 218 } 219 220 template <typename T> Do(T & x)221 void Do(T& x) 222 { 223 static_assert(IsTriviallyCopyable<T>, "Only sane for trivially copyable types"); 224 // Note: 225 // Usually we can just use x = **ptr, etc. However, this doesn't work 226 // for unions containing BitFields (long story, stupid language rules) 227 // or arrays. This will get optimized anyway. 228 DoVoid((void*)&x, sizeof(x)); 229 } 230 231 template <typename T> DoPOD(T & x)232 void DoPOD(T& x) 233 { 234 DoVoid((void*)&x, sizeof(x)); 235 } 236 Do(bool & x)237 void Do(bool& x) 238 { 239 // bool's size can vary depending on platform, which can 240 // cause breakages. This treats all bools as if they were 241 // 8 bits in size. 242 u8 stable = static_cast<u8>(x); 243 244 Do(stable); 245 246 if (mode == MODE_READ) 247 x = stable != 0; 248 } 249 250 template <typename T> DoPointer(T * & x,T * const base)251 void DoPointer(T*& x, T* const base) 252 { 253 // pointers can be more than 2^31 apart, but you're using this function wrong if you need that 254 // much range 255 ptrdiff_t offset = x - base; 256 Do(offset); 257 if (mode == MODE_READ) 258 { 259 x = base + offset; 260 } 261 } 262 263 void DoMarker(const std::string& prevName, u32 arbitraryNumber = 0x42) 264 { 265 u32 cookie = arbitraryNumber; 266 Do(cookie); 267 268 if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) 269 { 270 PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting " 271 "savestate load...", 272 prevName.c_str(), cookie, cookie, arbitraryNumber, arbitraryNumber); 273 mode = PointerWrap::MODE_MEASURE; 274 } 275 } 276 277 template <typename T, typename Functor> DoEachElement(T & container,Functor member)278 void DoEachElement(T& container, Functor member) 279 { 280 u32 size = static_cast<u32>(container.size()); 281 Do(size); 282 container.resize(size); 283 284 for (auto& elem : container) 285 member(*this, elem); 286 } 287 288 private: 289 template <typename T> DoContiguousContainer(T & container)290 void DoContiguousContainer(T& container) 291 { 292 u32 size = static_cast<u32>(container.size()); 293 Do(size); 294 container.resize(size); 295 296 if (size > 0) 297 DoArray(&container[0], size); 298 } 299 300 template <typename T> DoContainer(T & x)301 void DoContainer(T& x) 302 { 303 DoEachElement(x, [](PointerWrap& p, typename T::value_type& elem) { p.Do(elem); }); 304 } 305 DoVoid(void * data,u32 size)306 DOLPHIN_FORCE_INLINE void DoVoid(void* data, u32 size) 307 { 308 switch (mode) 309 { 310 case MODE_READ: 311 memcpy(data, *ptr, size); 312 break; 313 314 case MODE_WRITE: 315 memcpy(*ptr, data, size); 316 break; 317 318 case MODE_MEASURE: 319 break; 320 321 case MODE_VERIFY: 322 DEBUG_ASSERT_MSG(COMMON, !memcmp(data, *ptr, size), 323 "Savestate verification failure: buf %p != %p (size %u).\n", data, *ptr, 324 size); 325 break; 326 } 327 328 *ptr += size; 329 } 330 }; 331