| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2008 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | #pragma once
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Extremely simple serialization framework.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // (mis)-features:
 | 
					
						
							|  |  |  | // + Super fast
 | 
					
						
							|  |  |  | // + Very simple
 | 
					
						
							|  |  |  | // + Same code is used for serialization and deserializaition (in most cases)
 | 
					
						
							|  |  |  | // - Zero backwards/forwards compatibility
 | 
					
						
							|  |  |  | // - Serialization code for anything complex has to be manually written.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-20 13:32:04 +02:00
										 |  |  | #include <array>
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <cstddef>
 | 
					
						
							| 
									
										
										
										
											2017-09-09 15:52:35 -04:00
										 |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <deque>
 | 
					
						
							|  |  |  | #include <list>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | #include <map>
 | 
					
						
							| 
									
										
										
										
											2013-08-25 20:06:58 -04:00
										 |  |  | #include <set>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2013-04-09 18:57:39 -05:00
										 |  |  | #include <type_traits>
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <utility>
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 16:39:47 -04:00
										 |  |  | #include "Common/Assert.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-09 11:34:43 -04:00
										 |  |  | #include "Common/Compiler.h"
 | 
					
						
							| 
									
										
										
										
											2014-08-24 19:38:33 -04:00
										 |  |  | #include "Common/Flag.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 16:39:47 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-26 02:18:13 +01:00
										 |  |  | // XXX: Replace this with std::is_trivially_copyable<T> once we stop using volatile
 | 
					
						
							|  |  |  | // on things that are put in savestates, as volatile types are not trivially copyable.
 | 
					
						
							|  |  |  | template <typename T> | 
					
						
							|  |  |  | constexpr bool IsTriviallyCopyable = std::is_trivially_copyable<std::remove_volatile_t<T>>::value; | 
					
						
							| 
									
										
										
										
											2013-08-25 20:06:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-28 01:26:56 +00:00
										 |  |  | // Wrapper class
 | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | class PointerWrap | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   enum Mode | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MODE_READ = 1,  // load
 | 
					
						
							|  |  |  |     MODE_WRITE,     // save
 | 
					
						
							|  |  |  |     MODE_MEASURE,   // calculate size
 | 
					
						
							|  |  |  |     MODE_VERIFY,    // compare
 | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u8** ptr; | 
					
						
							|  |  |  |   Mode mode; | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} | 
					
						
							|  |  |  |   void SetMode(Mode mode_) { mode = mode_; } | 
					
						
							|  |  |  |   Mode GetMode() const { return mode; } | 
					
						
							|  |  |  |   template <typename K, class V> | 
					
						
							|  |  |  |   void Do(std::map<K, V>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u32 count = (u32)x.size(); | 
					
						
							|  |  |  |     Do(count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (mode) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case MODE_READ: | 
					
						
							|  |  |  |       for (x.clear(); count != 0; --count) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         std::pair<K, V> pair; | 
					
						
							|  |  |  |         Do(pair.first); | 
					
						
							|  |  |  |         Do(pair.second); | 
					
						
							|  |  |  |         x.insert(pair); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case MODE_WRITE: | 
					
						
							|  |  |  |     case MODE_MEASURE: | 
					
						
							|  |  |  |     case MODE_VERIFY: | 
					
						
							|  |  |  |       for (auto& elem : x) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         Do(elem.first); | 
					
						
							|  |  |  |         Do(elem.second); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename V> | 
					
						
							|  |  |  |   void Do(std::set<V>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u32 count = (u32)x.size(); | 
					
						
							|  |  |  |     Do(count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (mode) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case MODE_READ: | 
					
						
							|  |  |  |       for (x.clear(); count != 0; --count) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         V value; | 
					
						
							|  |  |  |         Do(value); | 
					
						
							|  |  |  |         x.insert(value); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case MODE_WRITE: | 
					
						
							|  |  |  |     case MODE_MEASURE: | 
					
						
							|  |  |  |     case MODE_VERIFY: | 
					
						
							| 
									
										
										
										
											2017-01-14 17:38:35 +01:00
										 |  |  |       for (const V& val : x) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       { | 
					
						
							|  |  |  |         Do(val); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void Do(std::vector<T>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoContainer(x); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void Do(std::list<T>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoContainer(x); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void Do(std::deque<T>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoContainer(x); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void Do(std::basic_string<T>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoContainer(x); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T, typename U> | 
					
						
							|  |  |  |   void Do(std::pair<T, U>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Do(x.first); | 
					
						
							|  |  |  |     Do(x.second); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T, std::size_t N> | 
					
						
							|  |  |  |   void DoArray(std::array<T, N>& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoArray(x.data(), (u32)x.size()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void DoArray(T* x, u32 count) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-12-26 02:18:13 +01:00
										 |  |  |     static_assert(IsTriviallyCopyable<T>, "Only sane for trivially copyable types"); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     DoVoid(x, count * sizeof(T)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T, std::size_t N> | 
					
						
							|  |  |  |   void DoArray(T (&arr)[N]) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoArray(arr, static_cast<u32>(N)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void Do(Common::Flag& flag) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     bool s = flag.IsSet(); | 
					
						
							|  |  |  |     Do(s); | 
					
						
							|  |  |  |     if (mode == MODE_READ) | 
					
						
							|  |  |  |       flag.Set(s); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void Do(std::atomic<T>& atomic) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     T temp = atomic.load(); | 
					
						
							|  |  |  |     Do(temp); | 
					
						
							|  |  |  |     if (mode == MODE_READ) | 
					
						
							|  |  |  |       atomic.store(temp); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void Do(T& x) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-12-26 02:18:13 +01:00
										 |  |  |     static_assert(IsTriviallyCopyable<T>, "Only sane for trivially copyable types"); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     // Note:
 | 
					
						
							|  |  |  |     // Usually we can just use x = **ptr, etc.  However, this doesn't work
 | 
					
						
							|  |  |  |     // for unions containing BitFields (long story, stupid language rules)
 | 
					
						
							|  |  |  |     // or arrays.  This will get optimized anyway.
 | 
					
						
							|  |  |  |     DoVoid((void*)&x, sizeof(x)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void DoPOD(T& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DoVoid((void*)&x, sizeof(x)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void Do(bool& x) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // bool's size can vary depending on platform, which can
 | 
					
						
							|  |  |  |     // cause breakages. This treats all bools as if they were
 | 
					
						
							|  |  |  |     // 8 bits in size.
 | 
					
						
							|  |  |  |     u8 stable = static_cast<u8>(x); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Do(stable); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mode == MODE_READ) | 
					
						
							|  |  |  |       x = stable != 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							|  |  |  |   void DoPointer(T*& x, T* const base) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // pointers can be more than 2^31 apart, but you're using this function wrong if you need that
 | 
					
						
							|  |  |  |     // much range
 | 
					
						
							|  |  |  |     ptrdiff_t offset = x - base; | 
					
						
							|  |  |  |     Do(offset); | 
					
						
							|  |  |  |     if (mode == MODE_READ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       x = base + offset; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void DoMarker(const std::string& prevName, u32 arbitraryNumber = 0x42) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u32 cookie = arbitraryNumber; | 
					
						
							|  |  |  |     Do(cookie); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting " | 
					
						
							|  |  |  |                   "savestate load...", | 
					
						
							|  |  |  |                   prevName.c_str(), cookie, cookie, arbitraryNumber, arbitraryNumber); | 
					
						
							|  |  |  |       mode = PointerWrap::MODE_MEASURE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-03-19 21:51:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 06:42:52 +00:00
										 |  |  |   template <typename T, typename Functor> | 
					
						
							|  |  |  |   void DoEachElement(T& container, Functor member) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u32 size = static_cast<u32>(container.size()); | 
					
						
							|  |  |  |     Do(size); | 
					
						
							|  |  |  |     container.resize(size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& elem : container) | 
					
						
							|  |  |  |       member(*this, elem); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-02 03:28:44 -06:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   template <typename T> | 
					
						
							|  |  |  |   void DoContainer(T& x) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-09-01 06:42:52 +00:00
										 |  |  |     DoEachElement(x, [](PointerWrap& p, typename T::value_type& elem) { p.Do(elem); }); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-09 11:47:01 -04:00
										 |  |  |   DOLPHIN_FORCE_INLINE void DoVoid(void* data, u32 size) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |     switch (mode) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case MODE_READ: | 
					
						
							|  |  |  |       memcpy(data, *ptr, size); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case MODE_WRITE: | 
					
						
							|  |  |  |       memcpy(*ptr, data, size); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case MODE_MEASURE: | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case MODE_VERIFY: | 
					
						
							| 
									
										
										
										
											2018-03-14 20:34:35 -04:00
										 |  |  |       DEBUG_ASSERT_MSG(COMMON, !memcmp(data, *ptr, size), | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |                        "Savestate verification failure: buf %p != %p (size %u).\n", data, *ptr, | 
					
						
							|  |  |  |                        size); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *ptr += size; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-12-08 04:46:09 +00:00
										 |  |  | }; |