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 "memory.hh"
7 #include "noncopyable.hh"
8 #include "type_traits.hh"
9 #include "xxhash.hh"
10 #include <tuple>
11 #include <typeindex>
12 #include <type_traits>
13 #include <vector>
14 
15 namespace openmsx {
16 
31 template<typename T> class Creator
32 {
33 public:
34  template<typename TUPLE>
35  std::unique_ptr<T> operator()(TUPLE args) {
36  DoInstantiate<std::tuple_size<TUPLE>::value, TUPLE> inst;
37  return inst(args);
38  }
39 
40 private:
41  template<int I, typename TUPLE> struct DoInstantiate;
42  template<typename TUPLE> struct DoInstantiate<0, TUPLE> {
43  std::unique_ptr<T> operator()(TUPLE /*args*/) {
44  return make_unique<T>();
45  }
46  };
47  template<typename TUPLE> struct DoInstantiate<1, TUPLE> {
48  std::unique_ptr<T> operator()(TUPLE args) {
49  return make_unique<T>(std::get<0>(args));
50  }
51  };
52  template<typename TUPLE> struct DoInstantiate<2, TUPLE> {
53  std::unique_ptr<T> operator()(TUPLE args) {
54  return make_unique<T>(
55  std::get<0>(args), std::get<1>(args));
56  }
57  };
58  template<typename TUPLE> struct DoInstantiate<3, TUPLE> {
59  std::unique_ptr<T> operator()(TUPLE args) {
60  return make_unique<T>(
61  std::get<0>(args), std::get<1>(args),
62  std::get<2>(args));
63  }
64  };
65 };
66 
68 
69 // Polymorphic class loader/saver
70 
71 // forward declarations
72 // ClassSaver: used to save actually save a class. We also store the name of
73 // the class so that the loader knows which concrete class it should load.
74 template<typename T> struct ClassSaver;
75 // NonPolymorphicPointerLoader: once we know which concrete type to load,
76 // we use the 'normal' class loader to load it.
77 template<typename T> struct NonPolymorphicPointerLoader;
78 // Used by PolymorphicInitializer to initialize a concrete type.
79 template<typename T> struct ClassLoader;
80 
86 template<typename T> struct PolymorphicConstructorArgs;
87 
91 template<typename T> struct PolymorphicBaseClass;
92 
93 template<typename Base> struct MapConstrArgsEmpty
94 {
96  std::tuple<> operator()(const TUPLEIn& /*t*/)
97  {
98  return std::make_tuple();
99  }
100 };
101 template<typename Base, typename Derived> struct MapConstrArgsCopy
102 {
105  static_assert(std::is_same<TUPLEIn, TUPLEOut>::value,
106  "constructor argument types must match");
108  {
109  return t;
110  }
111 };
112 
125 template<typename Base, typename Derived> struct MapConstructorArguments
126  : if_<std::is_same<std::tuple<>,
127  typename PolymorphicConstructorArgs<Derived>::type>,
128  MapConstrArgsEmpty<Base>,
129  MapConstrArgsCopy<Base, Derived>> {};
130 
137 template<typename Base> struct BaseClassName;
138 
139 template<typename Archive> class PolymorphicSaverBase
140 {
141 public:
143  virtual void save(Archive& ar, const void* p) const = 0;
144 };
145 
146 template<typename Archive> class PolymorphicLoaderBase
147 {
148 public:
150  virtual void* load(Archive& ar, unsigned id, const void* args) const = 0;
151 };
152 
153 template<typename Archive> class PolymorphicInitializerBase
154 {
155 public:
157  virtual void init(Archive& ar, void* t, unsigned id) const = 0;
158 };
159 
160 template<typename Archive, typename T>
161 class PolymorphicSaver : public PolymorphicSaverBase<Archive>
162 {
163 public:
164  PolymorphicSaver(const char* name_)
165  : name(name_)
166  {
167  }
168  void save(Archive& ar, const void* v) const override
169  {
170  using BaseType = typename PolymorphicBaseClass<T>::type;
171  auto base = static_cast<const BaseType*>(v);
172  auto tp = static_cast<const T*>(base);
173  ClassSaver<T> saver;
174  saver(ar, *tp, true, name, true); // save id, type, constr-args
175  }
176 private:
177  const char* name;
178 };
179 
180 template<typename Archive, typename T>
182 {
183 public:
184  void* load(Archive& ar, unsigned id, const void* args) const override
185  {
186  using BaseType = typename PolymorphicBaseClass<T>::type;
187  using TUPLEIn = typename PolymorphicConstructorArgs<BaseType>::type;
188  using TUPLEOut = typename PolymorphicConstructorArgs<T>::type;
189  auto& argsIn = *static_cast<const TUPLEIn*>(args);
191  TUPLEOut argsOut = mapArgs(argsIn);
193  return loader(ar, id, argsOut);
194  }
195 };
196 
197 void polyInitError(const char* expected, const char* actual);
198 template<typename Archive, typename T>
200 {
201 public:
202  void init(Archive& ar, void* v, unsigned id) const override
203  {
204  using BaseType = typename PolymorphicBaseClass<T>::type;
205  auto base = static_cast<BaseType*>(v);
206  if (unlikely(dynamic_cast<T*>(base) != static_cast<T*>(base))) {
207  polyInitError(typeid(T).name(), typeid(*base).name());
208  }
209  auto t = static_cast<T*>(base);
210  ClassLoader<T> loader;
211  loader(ar, *t, std::make_tuple(), id);
212  }
213 };
214 
215 
216 template<typename Archive>
218 {
219 public:
221 
222  template<typename T> void registerClass(const char* name)
223  {
224  static_assert(std::is_polymorphic<T>::value,
225  "must be a polymorphic type");
226  static_assert(!std::is_abstract<T>::value,
227  "can't be an abstract type");
228  registerHelper(typeid(T),
230  }
231 
232  template<typename T> static void save(Archive& ar, T* t)
233  {
234  save(ar, t, typeid(*t));
235  }
236  template<typename T> static void save(const char* tag, Archive& ar, T& t)
237  {
238  save(tag, ar, &t, typeid(t));
239  }
240 
241 private:
244  void registerHelper(const std::type_info& type,
245  std::unique_ptr<PolymorphicSaverBase<Archive>> saver);
246  static void save(Archive& ar, const void* t,
247  const std::type_info& typeInfo);
248  static void save(const char* tag, Archive& ar, const void* t,
249  const std::type_info& typeInfo);
250 
251  std::vector<std::pair<std::type_index,
252  std::unique_ptr<PolymorphicSaverBase<Archive>>>> saverMap;
253  bool initialized;
254 };
255 
256 template<typename Archive>
258 {
259 public:
261 
262  template<typename T> void registerClass(const char* name)
263  {
264  static_assert(std::is_polymorphic<T>::value,
265  "must be a polymorphic type");
266  static_assert(!std::is_abstract<T>::value,
267  "can't be an abstract type");
268  registerHelper(name,
270  }
271 
272  static void* load(Archive& ar, unsigned id, const void* args);
273 
274 private:
277  void registerHelper(
278  const char* name,
279  std::unique_ptr<PolymorphicLoaderBase<Archive>> loader);
280 
282  loaderMap;
283 };
284 
285 template<typename Archive>
287 {
288 public:
290 
291  template<typename T> void registerClass(const char* name)
292  {
293  static_assert(std::is_polymorphic<T>::value,
294  "must be a polymorphic type");
295  static_assert(!std::is_abstract<T>::value,
296  "can't be an abstract type");
297  registerHelper(name,
299  }
300 
301  static void init(const char* tag, Archive& ar, void* t);
302 
303 private:
306  void registerHelper(
307  const char* name,
308  std::unique_ptr<PolymorphicInitializerBase<Archive>> initializer);
309 
311  initializerMap;
312 };
313 
314 
315 template<typename Archive, typename T> struct RegisterSaverHelper
316 {
317  RegisterSaverHelper(const char* name)
318  {
320  template registerClass<T>(name);
321  }
322 };
323 template<typename Archive, typename T> struct RegisterLoaderHelper
324 {
325  RegisterLoaderHelper(const char* name)
326  {
328  template registerClass<T>(name);
329  }
330 };
331 template<typename Archive, typename T> struct RegisterInitializerHelper
332 {
333  RegisterInitializerHelper(const char* name)
334  {
336  template registerClass<T>(name);
337  }
338 };
339 
340 #define REGISTER_CONSTRUCTOR_ARGS_0(C) \
341 template<> struct PolymorphicConstructorArgs<C> \
342 { using type = std::tuple<>; };
343 
344 #define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
345 template<> struct PolymorphicConstructorArgs<C> \
346 { using type = std::tuple<T1>; };
347 
348 #define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
349 template<> struct PolymorphicConstructorArgs<C> \
350 { using type = std::tuple<T1,T2>; };
351 
352 #define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
353 template<> struct PolymorphicConstructorArgs<C> \
354 { using type = std::tuple<T1,T2,T3>; };
355 
356 class MemInputArchive;
357 class MemOutputArchive;
358 class XmlInputArchive;
359 class XmlOutputArchive;
360 
361 /*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
362 static_assert(std::is_base_of<B,C>::value, "must be base and sub class"); \
363 static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
364 static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
365 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
366 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
367 static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
368 static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
369 #define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
370 static_assert(std::is_base_of<B,C>::value, "must be base and sub class"); \
371 static RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
372 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
373 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
374 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
375 template<> struct PolymorphicBaseClass<C> { using type = B; };
376 
377 #define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
378 static_assert(std::is_base_of<B,C>::value, "must be base and sub class"); \
379 static RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
380 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
381 static RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
382 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
383 template<> struct PolymorphicBaseClass<C> { using type = B; };
384 
385 #define REGISTER_BASE_NAME_HELPER(B,N) \
386 template<> struct BaseClassName<B> \
387 { static const char* getName() { static const char* name = N; return name; } };
388 
389 // public macros
390 // these are a more convenient way to define specializations of the
391 // PolymorphicConstructorArgs and PolymorphicBaseClass classes
392 #define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
393  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
394  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
395 
396 #define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
397  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
398  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
399 
400 #define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
401  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
402  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
403 
404 #define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
405  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
406  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
407 
408 #define REGISTER_BASE_CLASS(CLASS,NAME) \
409  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
410  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
411 
412 #define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
413  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
414  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
415 
416 #define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
417  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
418  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
419 
420 #define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
421  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
422  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
423 
424 
425 #define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
426  REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
427 
429 
445 template<typename T> struct SerializeClassVersion
446 {
447  static const unsigned value = 1;
448 };
449 #define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
450 template<> struct SerializeClassVersion<CLASS> \
451 { \
452  static const unsigned value = VERSION; \
453 };
454 
455 } // namespace openmsx
456 
457 #endif
virtual void * load(Archive &ar, unsigned id, const void *args) const =0
typename PolymorphicConstructorArgs< Derived >::type TUPLEOut
std::unique_ptr< T > operator()(TUPLE args)
void polyInitError(const char *expected, const char *actual)
std::tuple operator()(const TUPLEIn &)
#define unlikely(x)
Definition: likely.hh:15
Define mapping between constructor arg list of base- and subclass.
static PolymorphicInitializerRegistry & instance()
virtual void save(Archive &ar, const void *p) const =0
Store association between (polymorphic) sub- and baseclass.
static PolymorphicLoaderRegistry & instance()
Store association between polymorphic class (base- or subclass) and the list of constructor arguments...
Utility to do T* t = new T(...)
static void save(const char *tag, Archive &ar, T &t)
static PolymorphicSaverRegistry & instance()
static void * load(Archive &ar, unsigned id, const void *args)
Stores the name of a base class.
void init(Archive &ar, void *v, unsigned id) const override
PolymorphicSaver(const char *name_)
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
RegisterInitializerHelper(const char *name)
virtual void init(Archive &ar, void *t, unsigned id) const =0
RegisterSaverHelper(const char *name)
void save(Archive &ar, const void *v) const override
typename PolymorphicConstructorArgs< Base >::type TUPLEIn
RegisterLoaderHelper(const char *name)
typename PolymorphicConstructorArgs< Base >::type TUPLEIn
void * load(Archive &ar, unsigned id, const void *args) const override
void registerClass(const char *name)
TUPLEOut operator()(const TUPLEIn &t)
Based on boost::noncopyable, see boost documentation: http://www.boost.org/libs/utility.
Definition: noncopyable.hh:12
void registerClass(const char *name)
std::unique_ptr< T > make_unique()
Definition: memory.hh:27
static void init(const char *tag, Archive &ar, void *t)
static void save(Archive &ar, T *t)