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