serialize_meta.hh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. #ifndef SERIALIZE_META_HH
  2. #define SERIALIZE_META_HH
  3. #include "hash_map.hh"
  4. #include "likely.hh"
  5. #include "xxhash.hh"
  6. #include <memory>
  7. #include <tuple>
  8. #include <typeindex>
  9. #include <type_traits>
  10. #include <utility>
  11. #include <vector>
  12. namespace openmsx {
  13. /** Utility to do T* t = new T(...)
  14. *
  15. * The tricky part is that the constructor of T can have a variable number
  16. * of parameters.
  17. *
  18. * For example:
  19. * Creator<Foo> creator;
  20. * auto args = std::tuple(42, 3.14);
  21. * std::unique_ptr<Foo> foo = creator(args);
  22. * This is equivalent to
  23. * auto foo = std::make_unique<Foo>(42, 3.14);
  24. * But the former can be used in a generic context (where the number of
  25. * constructor parameters is unknown).
  26. */
  27. template<typename T> struct Creator
  28. {
  29. template<typename TUPLE>
  30. std::unique_ptr<T> operator()(TUPLE tuple) {
  31. auto makeT = [](auto&& ...args) {
  32. return std::make_unique<T>(std::forward<decltype(args)>(args)...);
  33. };
  34. return std::apply(makeT, tuple);
  35. }
  36. };
  37. ///////////////////////////////
  38. // Polymorphic class loader/saver
  39. // forward declarations
  40. // ClassSaver: used to actually save a class. We also store the name of
  41. // the class so that the loader knows which concrete class it should load.
  42. template<typename T> struct ClassSaver;
  43. // NonPolymorphicPointerLoader: once we know which concrete type to load,
  44. // we use the 'normal' class loader to load it.
  45. template<typename T> struct NonPolymorphicPointerLoader;
  46. // Used by PolymorphicInitializer to initialize a concrete type.
  47. template<typename T> struct ClassLoader;
  48. /** Store association between polymorphic class (base- or subclass) and
  49. * the list of constructor arguments.
  50. * Specializations of this class should store the constructor arguments
  51. * as a 'using type = tupple<...>'.
  52. */
  53. template<typename T> struct PolymorphicConstructorArgs;
  54. /** Store association between (polymorphic) sub- and baseclass.
  55. * Specialization of this class should provide a 'using type = <base>'.
  56. */
  57. template<typename T> struct PolymorphicBaseClass;
  58. template<typename Base> struct MapConstrArgsEmpty
  59. {
  60. using TUPLEIn = typename PolymorphicConstructorArgs<Base>::type;
  61. std::tuple<> operator()(const TUPLEIn& /*t*/)
  62. {
  63. return std::tuple<>();
  64. }
  65. };
  66. template<typename Base, typename Derived> struct MapConstrArgsCopy
  67. {
  68. using TUPLEIn = typename PolymorphicConstructorArgs<Base>::type;
  69. using TUPLEOut = typename PolymorphicConstructorArgs<Derived>::type;
  70. static_assert(std::is_same_v<TUPLEIn, TUPLEOut>,
  71. "constructor argument types must match");
  72. TUPLEOut operator()(const TUPLEIn& t)
  73. {
  74. return t;
  75. }
  76. };
  77. /** Define mapping between constructor arg list of base- and subclass.
  78. *
  79. * When loading a polymorphic base class, the user must provide the union of
  80. * constructor arguments for all subclasses (because it's not yet known which
  81. * concrete subtype will be deserialized). This class defines the mapping
  82. * between this union of parameters and the subset used for a specific
  83. * subclass.
  84. *
  85. * In case the parameter list of the subclass is empty or if it is the same
  86. * as the base class, this mapping will be defined automatically. In the other
  87. * cases, the user must define a specialization of this class.
  88. */
  89. template<typename Base, typename Derived> struct MapConstructorArguments
  90. : std::conditional_t<std::is_same<std::tuple<>,
  91. typename PolymorphicConstructorArgs<Derived>::type>::value,
  92. MapConstrArgsEmpty<Base>,
  93. MapConstrArgsCopy<Base, Derived>> {};
  94. /** Stores the name of a base class.
  95. * This name is used as tag-name in XML archives.
  96. *
  97. * Specializations of this class should provide a function
  98. * static const char* getName()
  99. */
  100. template<typename Base> struct BaseClassName;
  101. template<typename Archive> class PolymorphicSaverBase
  102. {
  103. public:
  104. virtual ~PolymorphicSaverBase() = default;
  105. virtual void save(Archive& ar, const void* p) const = 0;
  106. };
  107. template<typename Archive> class PolymorphicLoaderBase
  108. {
  109. public:
  110. virtual ~PolymorphicLoaderBase() = default;
  111. virtual void* load(Archive& ar, unsigned id, const void* args) const = 0;
  112. };
  113. template<typename Archive> class PolymorphicInitializerBase
  114. {
  115. public:
  116. virtual ~PolymorphicInitializerBase() = default;
  117. virtual void init(Archive& ar, void* t, unsigned id) const = 0;
  118. };
  119. template<typename Archive, typename T>
  120. class PolymorphicSaver : public PolymorphicSaverBase<Archive>
  121. {
  122. public:
  123. explicit PolymorphicSaver(const char* name_)
  124. : name(name_)
  125. {
  126. }
  127. void save(Archive& ar, const void* v) const override
  128. {
  129. using BaseType = typename PolymorphicBaseClass<T>::type;
  130. auto base = static_cast<const BaseType*>(v);
  131. auto tp = static_cast<const T*>(base);
  132. ClassSaver<T> saver;
  133. saver(ar, *tp, true, name, true); // save id, type, constr-args
  134. }
  135. private:
  136. const char* name;
  137. };
  138. template<typename Archive, typename T>
  139. class PolymorphicLoader : public PolymorphicLoaderBase<Archive>
  140. {
  141. public:
  142. void* load(Archive& ar, unsigned id, const void* args) const override
  143. {
  144. using BaseType = typename PolymorphicBaseClass<T>::type;
  145. using TUPLEIn = typename PolymorphicConstructorArgs<BaseType>::type;
  146. using TUPLEOut = typename PolymorphicConstructorArgs<T>::type;
  147. auto& argsIn = *static_cast<const TUPLEIn*>(args);
  148. MapConstructorArguments<BaseType, T> mapArgs;
  149. TUPLEOut argsOut = mapArgs(argsIn);
  150. NonPolymorphicPointerLoader<T> loader;
  151. return loader(ar, id, argsOut);
  152. }
  153. };
  154. void polyInitError(const char* expected, const char* actual);
  155. template<typename Archive, typename T>
  156. class PolymorphicInitializer : public PolymorphicInitializerBase<Archive>
  157. {
  158. public:
  159. void init(Archive& ar, void* v, unsigned id) const override
  160. {
  161. using BaseType = typename PolymorphicBaseClass<T>::type;
  162. auto base = static_cast<BaseType*>(v);
  163. if (unlikely(dynamic_cast<T*>(base) != static_cast<T*>(base))) {
  164. polyInitError(typeid(T).name(), typeid(*base).name());
  165. }
  166. auto t = static_cast<T*>(base);
  167. ClassLoader<T> loader;
  168. loader(ar, *t, std::tuple<>(), id);
  169. }
  170. };
  171. template<typename Archive>
  172. class PolymorphicSaverRegistry
  173. {
  174. public:
  175. static PolymorphicSaverRegistry& instance();
  176. template<typename T> void registerClass(const char* name)
  177. {
  178. static_assert(std::is_polymorphic_v<T>,
  179. "must be a polymorphic type");
  180. static_assert(!std::is_abstract_v<T>,
  181. "can't be an abstract type");
  182. registerHelper(typeid(T),
  183. std::make_unique<PolymorphicSaver<Archive, T>>(name));
  184. }
  185. template<typename T> static void save(Archive& ar, T* t)
  186. {
  187. save(ar, t, typeid(*t));
  188. }
  189. template<typename T> static void save(const char* tag, Archive& ar, T& t)
  190. {
  191. save(tag, ar, &t, typeid(t));
  192. }
  193. private:
  194. PolymorphicSaverRegistry() = default;
  195. ~PolymorphicSaverRegistry() = default;
  196. void registerHelper(const std::type_info& type,
  197. std::unique_ptr<PolymorphicSaverBase<Archive>> saver);
  198. static void save(Archive& ar, const void* t,
  199. const std::type_info& typeInfo);
  200. static void save(const char* tag, Archive& ar, const void* t,
  201. const std::type_info& typeInfo);
  202. std::vector<std::pair<std::type_index,
  203. std::unique_ptr<PolymorphicSaverBase<Archive>>>> saverMap;
  204. bool initialized = false;
  205. };
  206. template<typename Archive>
  207. class PolymorphicLoaderRegistry
  208. {
  209. public:
  210. static PolymorphicLoaderRegistry& instance();
  211. template<typename T> void registerClass(const char* name)
  212. {
  213. static_assert(std::is_polymorphic_v<T>,
  214. "must be a polymorphic type");
  215. static_assert(!std::is_abstract_v<T>,
  216. "can't be an abstract type");
  217. registerHelper(name,
  218. std::make_unique<PolymorphicLoader<Archive, T>>());
  219. }
  220. static void* load(Archive& ar, unsigned id, const void* args);
  221. private:
  222. PolymorphicLoaderRegistry() = default;
  223. ~PolymorphicLoaderRegistry() = default;
  224. void registerHelper(
  225. const char* name,
  226. std::unique_ptr<PolymorphicLoaderBase<Archive>> loader);
  227. hash_map<std::string_view, std::unique_ptr<PolymorphicLoaderBase<Archive>>, XXHasher>
  228. loaderMap;
  229. };
  230. template<typename Archive>
  231. class PolymorphicInitializerRegistry
  232. {
  233. public:
  234. static PolymorphicInitializerRegistry& instance();
  235. template<typename T> void registerClass(const char* name)
  236. {
  237. static_assert(std::is_polymorphic_v<T>,
  238. "must be a polymorphic type");
  239. static_assert(!std::is_abstract_v<T>,
  240. "can't be an abstract type");
  241. registerHelper(name,
  242. std::make_unique<PolymorphicInitializer<Archive, T>>());
  243. }
  244. static void init(const char* tag, Archive& ar, void* t);
  245. private:
  246. PolymorphicInitializerRegistry() = default;
  247. ~PolymorphicInitializerRegistry() = default;
  248. void registerHelper(
  249. const char* name,
  250. std::unique_ptr<PolymorphicInitializerBase<Archive>> initializer);
  251. hash_map<std::string_view, std::unique_ptr<PolymorphicInitializerBase<Archive>>, XXHasher>
  252. initializerMap;
  253. };
  254. template<typename Archive, typename T> struct RegisterSaverHelper
  255. {
  256. explicit RegisterSaverHelper(const char* name)
  257. {
  258. PolymorphicSaverRegistry<Archive>::instance().
  259. template registerClass<T>(name);
  260. }
  261. };
  262. template<typename Archive, typename T> struct RegisterLoaderHelper
  263. {
  264. explicit RegisterLoaderHelper(const char* name)
  265. {
  266. PolymorphicLoaderRegistry<Archive>::instance().
  267. template registerClass<T>(name);
  268. }
  269. };
  270. template<typename Archive, typename T> struct RegisterInitializerHelper
  271. {
  272. explicit RegisterInitializerHelper(const char* name)
  273. {
  274. PolymorphicInitializerRegistry<Archive>::instance().
  275. template registerClass<T>(name);
  276. }
  277. };
  278. #define REGISTER_CONSTRUCTOR_ARGS_0(C) \
  279. template<> struct PolymorphicConstructorArgs<C> \
  280. { using type = std::tuple<>; };
  281. #define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
  282. template<> struct PolymorphicConstructorArgs<C> \
  283. { using type = std::tuple<T1>; };
  284. #define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
  285. template<> struct PolymorphicConstructorArgs<C> \
  286. { using type = std::tuple<T1,T2>; };
  287. #define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
  288. template<> struct PolymorphicConstructorArgs<C> \
  289. { using type = std::tuple<T1,T2,T3>; };
  290. class MemInputArchive;
  291. class MemOutputArchive;
  292. class XmlInputArchive;
  293. class XmlOutputArchive;
  294. /*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
  295. static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
  296. static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
  297. static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
  298. static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
  299. static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
  300. static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
  301. static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
  302. #define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
  303. static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
  304. static RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
  305. static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
  306. static RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
  307. static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
  308. template<> struct PolymorphicBaseClass<C> { using type = B; };
  309. #define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
  310. static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
  311. static RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
  312. static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
  313. static RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
  314. static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
  315. template<> struct PolymorphicBaseClass<C> { using type = B; };
  316. #define REGISTER_BASE_NAME_HELPER(B,N) \
  317. template<> struct BaseClassName<B> \
  318. { static const char* getName() { static constexpr const char* const name = N; return name; } };
  319. // public macros
  320. // these are a more convenient way to define specializations of the
  321. // PolymorphicConstructorArgs and PolymorphicBaseClass classes
  322. #define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
  323. REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
  324. REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
  325. #define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
  326. REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
  327. REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
  328. #define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
  329. REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
  330. REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
  331. #define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
  332. REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
  333. REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
  334. #define REGISTER_BASE_CLASS(CLASS,NAME) \
  335. REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
  336. REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
  337. #define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
  338. REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
  339. REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
  340. #define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
  341. REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
  342. REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
  343. #define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
  344. REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
  345. REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
  346. #define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
  347. REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
  348. //////////////
  349. /** Store serialization-version number of a class.
  350. *
  351. * Classes are individually versioned. Use the SERIALIZE_CLASS_VERSION
  352. * macro below as a convenient way to set the version of a class.
  353. *
  354. * The initial (=default) version is 1. When the layout of a class changes
  355. * in an incompatible way, you should increase the version number. But
  356. * remember: to be able to load older version the (de)serialize code for the
  357. * older version(s) must be kept.
  358. *
  359. * Version number 0 is special. It means the layout for this class will _NEVER_
  360. * change. This can be a bit more efficient because the version number must
  361. * not be stored in the stream. Though be careful to only use version 0 for
  362. * _VERY_ stable classes, std::pair is a good example of a stable class.
  363. */
  364. template<typename T> struct SerializeClassVersion
  365. {
  366. static constexpr unsigned value = 1;
  367. };
  368. #define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
  369. template<> struct SerializeClassVersion<CLASS> \
  370. { \
  371. static constexpr unsigned value = VERSION; \
  372. };
  373. } // namespace openmsx
  374. #endif