openMSX
serialize_meta.hh
Go to the documentation of this file.
1 #ifndef SERIALIZE_META_HH
2 #define SERIALIZE_META_HH
3 
4 #include "hash_map.hh"
5 #include "likely.hh"
6 #include "xxhash.hh"
7 #include <memory>
8 #include <tuple>
9 #include <typeindex>
10 #include <type_traits>
11 #include <utility>
12 #include <vector>
13 
14 namespace openmsx {
15 
30 template<typename T> struct Creator
31 {
32  template<typename TUPLE>
33  std::unique_ptr<T> operator()(TUPLE tuple) {
34  auto makeT = [](auto&& ...args) {
35  return std::make_unique<T>(std::forward<decltype(args)>(args)...);
36  };
37  return std::apply(makeT, tuple);
38  }
39 };
40 
42 
43 // Polymorphic class loader/saver
44 
45 // forward declarations
46 // ClassSaver: used to actually save a class. We also store the name of
47 // the class so that the loader knows which concrete class it should load.
48 template<typename T> struct ClassSaver;
49 // NonPolymorphicPointerLoader: once we know which concrete type to load,
50 // we use the 'normal' class loader to load it.
51 template<typename T> struct NonPolymorphicPointerLoader;
52 // Used by PolymorphicInitializer to initialize a concrete type.
53 template<typename T> struct ClassLoader;
54 
60 template<typename T> struct PolymorphicConstructorArgs;
61 
65 template<typename T> struct PolymorphicBaseClass;
66 
67 template<typename Base> struct MapConstrArgsEmpty
68 {
70  std::tuple<> operator()(const TUPLEIn& /*t*/)
71  {
72  return std::tuple<>();
73  }
74 };
75 template<typename Base, typename Derived> struct MapConstrArgsCopy
76 {
79  static_assert(std::is_same_v<TUPLEIn, TUPLEOut>,
80  "constructor argument types must match");
82  {
83  return t;
84  }
85 };
86 
99 template<typename Base, typename Derived> struct MapConstructorArguments
100  : std::conditional_t<std::is_same<std::tuple<>,
101  typename PolymorphicConstructorArgs<Derived>::type>::value,
102  MapConstrArgsEmpty<Base>,
103  MapConstrArgsCopy<Base, Derived>> {};
104 
111 template<typename Base> struct BaseClassName;
112 
113 template<typename Archive> class PolymorphicSaverBase
114 {
115 public:
116  virtual ~PolymorphicSaverBase() = default;
117  virtual void save(Archive& ar, const void* p) const = 0;
118 };
119 
120 template<typename Archive> class PolymorphicLoaderBase
121 {
122 public:
123  virtual ~PolymorphicLoaderBase() = default;
124  virtual void* load(Archive& ar, unsigned id, const void* args) const = 0;
125 };
126 
127 template<typename Archive> class PolymorphicInitializerBase
128 {
129 public:
130  virtual ~PolymorphicInitializerBase() = default;
131  virtual void init(Archive& ar, void* t, unsigned id) const = 0;
132 };
133 
134 template<typename Archive, typename T>
135 class PolymorphicSaver : public PolymorphicSaverBase<Archive>
136 {
137 public:
138  explicit PolymorphicSaver(const char* name_)
139  : name(name_)
140  {
141  }
142  void save(Archive& ar, const void* v) const override
143  {
144  using BaseType = typename PolymorphicBaseClass<T>::type;
145  auto base = static_cast<const BaseType*>(v);
146  auto tp = static_cast<const T*>(base);
147  ClassSaver<T> saver;
148  saver(ar, *tp, true, name, true); // save id, type, constr-args
149  }
150 private:
151  const char* name;
152 };
153 
154 template<typename Archive, typename T>
156 {
157 public:
158  void* load(Archive& ar, unsigned id, const void* args) const override
159  {
160  using BaseType = typename PolymorphicBaseClass<T>::type;
161  using TUPLEIn = typename PolymorphicConstructorArgs<BaseType>::type;
162  using TUPLEOut = typename PolymorphicConstructorArgs<T>::type;
163  auto& argsIn = *static_cast<const TUPLEIn*>(args);
165  TUPLEOut argsOut = mapArgs(argsIn);
167  return loader(ar, id, argsOut);
168  }
169 };
170 
171 void polyInitError(const char* expected, const char* actual);
172 template<typename Archive, typename T>
174 {
175 public:
176  void init(Archive& ar, void* v, unsigned id) const override
177  {
178  using BaseType = typename PolymorphicBaseClass<T>::type;
179  auto base = static_cast<BaseType*>(v);
180  if (unlikely(dynamic_cast<T*>(base) != static_cast<T*>(base))) {
181  polyInitError(typeid(T).name(), typeid(*base).name());
182  }
183  auto t = static_cast<T*>(base);
184  ClassLoader<T> loader;
185  loader(ar, *t, std::tuple<>(), id);
186  }
187 };
188 
189 
190 template<typename Archive>
192 {
193 public:
196 
198 
199  template<typename T> void registerClass(const char* name)
200  {
201  static_assert(std::is_polymorphic_v<T>,
202  "must be a polymorphic type");
203  static_assert(!std::is_abstract_v<T>,
204  "can't be an abstract type");
205  registerHelper(typeid(T),
206  std::make_unique<PolymorphicSaver<Archive, T>>(name));
207  }
208 
209  template<typename T> static void save(Archive& ar, T* t)
210  {
211  save(ar, t, typeid(*t));
212  }
213  template<typename T> static void save(const char* tag, Archive& ar, T& t)
214  {
215  save(tag, ar, &t, typeid(t));
216  }
217 
218 private:
219  PolymorphicSaverRegistry() = default;
220  ~PolymorphicSaverRegistry() = default;
221 
222  void registerHelper(const std::type_info& type,
223  std::unique_ptr<PolymorphicSaverBase<Archive>> saver);
224  static void save(Archive& ar, const void* t,
225  const std::type_info& typeInfo);
226  static void save(const char* tag, Archive& ar, const void* t,
227  const std::type_info& typeInfo);
228 
229  struct Entry {
230  std::type_index index;
231  std::unique_ptr<PolymorphicSaverBase<Archive>> saver;
232  };
233  std::vector<Entry> saverMap;
234  bool initialized = false;
235 };
236 
237 template<typename Archive>
239 {
240 public:
243 
245 
246  template<typename T> void registerClass(const char* name)
247  {
248  static_assert(std::is_polymorphic_v<T>,
249  "must be a polymorphic type");
250  static_assert(!std::is_abstract_v<T>,
251  "can't be an abstract type");
252  registerHelper(name,
253  std::make_unique<PolymorphicLoader<Archive, T>>());
254  }
255 
256  static void* load(Archive& ar, unsigned id, const void* args);
257 
258 private:
259  PolymorphicLoaderRegistry() = default;
260  ~PolymorphicLoaderRegistry() = default;
261 
262  void registerHelper(
263  const char* name,
264  std::unique_ptr<PolymorphicLoaderBase<Archive>> loader);
265 
267  loaderMap;
268 };
269 
270 template<typename Archive>
272 {
273 public:
276 
278 
279  template<typename T> void registerClass(const char* name)
280  {
281  static_assert(std::is_polymorphic_v<T>,
282  "must be a polymorphic type");
283  static_assert(!std::is_abstract_v<T>,
284  "can't be an abstract type");
285  registerHelper(name,
286  std::make_unique<PolymorphicInitializer<Archive, T>>());
287  }
288 
289  static void init(const char* tag, Archive& ar, void* t);
290 
291 private:
292  PolymorphicInitializerRegistry() = default;
293  ~PolymorphicInitializerRegistry() = default;
294 
295  void registerHelper(
296  const char* name,
297  std::unique_ptr<PolymorphicInitializerBase<Archive>> initializer);
298 
300  initializerMap;
301 };
302 
303 
304 template<typename Archive, typename T> struct RegisterSaverHelper
305 {
306  explicit RegisterSaverHelper(const char* name)
307  {
309  template registerClass<T>(name);
310  }
311 };
312 template<typename Archive, typename T> struct RegisterLoaderHelper
313 {
314  explicit RegisterLoaderHelper(const char* name)
315  {
317  template registerClass<T>(name);
318  }
319 };
320 template<typename Archive, typename T> struct RegisterInitializerHelper
321 {
322  explicit RegisterInitializerHelper(const char* name)
323  {
325  template registerClass<T>(name);
326  }
327 };
328 
329 #define REGISTER_CONSTRUCTOR_ARGS_0(C) \
330 template<> struct PolymorphicConstructorArgs<C> \
331 { using type = std::tuple<>; };
332 
333 #define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
334 template<> struct PolymorphicConstructorArgs<C> \
335 { using type = std::tuple<T1>; };
336 
337 #define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
338 template<> struct PolymorphicConstructorArgs<C> \
339 { using type = std::tuple<T1,T2>; };
340 
341 #define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
342 template<> struct PolymorphicConstructorArgs<C> \
343 { using type = std::tuple<T1,T2,T3>; };
344 
345 class MemInputArchive;
346 class MemOutputArchive;
347 class XmlInputArchive;
348 class XmlOutputArchive;
349 
350 /*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
351 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
352 static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
353 static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
354 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
355 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
356 static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
357 static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
358 #define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
359 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
360 static RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
361 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
362 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
363 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
364 template<> struct PolymorphicBaseClass<C> { using type = B; };
365 
366 #define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
367 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
368 static RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
369 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
370 static RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
371 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
372 template<> struct PolymorphicBaseClass<C> { using type = B; };
373 
374 #define REGISTER_BASE_NAME_HELPER(B,N) \
375 template<> struct BaseClassName<B> \
376 { static const char* getName() { static constexpr const char* const name = N; return name; } };
377 
378 // public macros
379 // these are a more convenient way to define specializations of the
380 // PolymorphicConstructorArgs and PolymorphicBaseClass classes
381 #define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
382  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
383  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
384 
385 #define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
386  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
387  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
388 
389 #define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
390  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
391  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
392 
393 #define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
394  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
395  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
396 
397 #define REGISTER_BASE_CLASS(CLASS,NAME) \
398  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
399  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
400 
401 #define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
402  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
403  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
404 
405 #define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
406  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
407  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
408 
409 #define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
410  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
411  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
412 
413 
414 #define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
415  REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
416 
418 
434 template<typename T> struct SerializeClassVersion
435 {
436  static constexpr unsigned value = 1;
437 };
438 #define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
439 template<> struct SerializeClassVersion<CLASS> \
440 { \
441  static constexpr unsigned value = VERSION; \
442 };
443 
444 } // namespace openmsx
445 
446 #endif
TclObject t
virtual ~PolymorphicInitializerBase()=default
virtual void init(Archive &ar, void *t, unsigned id) const =0
static void init(const char *tag, Archive &ar, void *t)
PolymorphicInitializerRegistry(const PolymorphicInitializerRegistry &)=delete
PolymorphicInitializerRegistry & operator=(const PolymorphicInitializerRegistry &)=delete
static PolymorphicInitializerRegistry & instance()
void init(Archive &ar, void *v, unsigned id) const override
virtual void * load(Archive &ar, unsigned id, const void *args) const =0
virtual ~PolymorphicLoaderBase()=default
static PolymorphicLoaderRegistry & instance()
void registerClass(const char *name)
static void * load(Archive &ar, unsigned id, const void *args)
PolymorphicLoaderRegistry(const PolymorphicLoaderRegistry &)=delete
PolymorphicLoaderRegistry & operator=(const PolymorphicLoaderRegistry &)=delete
void * load(Archive &ar, unsigned id, const void *args) const override
virtual void save(Archive &ar, const void *p) const =0
virtual ~PolymorphicSaverBase()=default
PolymorphicSaverRegistry(const PolymorphicSaverRegistry &)=delete
static PolymorphicSaverRegistry & instance()
PolymorphicSaverRegistry & operator=(const PolymorphicSaverRegistry &)=delete
static void save(const char *tag, Archive &ar, T &t)
void registerClass(const char *name)
static void save(Archive &ar, T *t)
void save(Archive &ar, const void *v) const override
PolymorphicSaver(const char *name_)
#define unlikely(x)
Definition: likely.hh:15
This file implemented 3 utility functions:
Definition: Autofire.cc:9
void polyInitError(const char *expected, const char *actual)
Stores the name of a base class.
Utility to do T* t = new T(...)
std::unique_ptr< T > operator()(TUPLE tuple)
typename PolymorphicConstructorArgs< Base >::type TUPLEIn
TUPLEOut operator()(const TUPLEIn &t)
typename PolymorphicConstructorArgs< Derived >::type TUPLEOut
std::tuple operator()(const TUPLEIn &)
typename PolymorphicConstructorArgs< Base >::type TUPLEIn
Define mapping between constructor arg list of base- and subclass.
Store association between (polymorphic) sub- and baseclass.
Store association between polymorphic class (base- or subclass) and the list of constructor arguments...
RegisterInitializerHelper(const char *name)
RegisterLoaderHelper(const char *name)
RegisterSaverHelper(const char *name)
Store serialization-version number of a class.