ChunkFile.h 8.0 KB

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