openMSX
serialize_meta.hh
Go to the documentation of this file.
1 #ifndef SERIALIZE_META_HH
2 #define SERIALIZE_META_HH
3 
4 #include "TypeInfo.hh"
5 #include "StringMap.hh"
6 #include "noncopyable.hh"
7 #include "type_traits.hh"
8 #include "likely.hh"
9 #include "memory.hh"
10 #include <string>
11 #include <tuple>
12 #include <type_traits>
13 #include <map>
14 #include <cassert>
15 
16 namespace openmsx {
17 
32 template<typename T> class Creator
33 {
34 public:
35  template<typename TUPLE>
36  std::unique_ptr<T> operator()(TUPLE args) {
37  DoInstantiate<std::tuple_size<TUPLE>::value, TUPLE> inst;
38  return inst(args);
39  }
40 
41 private:
42  template<int I, typename TUPLE> struct DoInstantiate;
43  template<typename TUPLE> struct DoInstantiate<0, TUPLE> {
44  std::unique_ptr<T> operator()(TUPLE /*args*/) {
45  return make_unique<T>();
46  }
47  };
48  template<typename TUPLE> struct DoInstantiate<1, TUPLE> {
49  std::unique_ptr<T> operator()(TUPLE args) {
50  return make_unique<T>(std::get<0>(args));
51  }
52  };
53  template<typename TUPLE> struct DoInstantiate<2, TUPLE> {
54  std::unique_ptr<T> operator()(TUPLE args) {
55  return make_unique<T>(
56  std::get<0>(args), std::get<1>(args));
57  }
58  };
59  template<typename TUPLE> struct DoInstantiate<3, TUPLE> {
60  std::unique_ptr<T> operator()(TUPLE args) {
61  return make_unique<T>(
62  std::get<0>(args), std::get<1>(args),
63  std::get<2>(args));
64  }
65  };
66 };
67 
69 
70 // Polymorphic class loader/saver
71 
72 // forward declarations
73 // ClassSaver: used to save actually save a class. We also store the name of
74 // the class so that the loader knows which concrete class it should load.
75 template<typename T> struct ClassSaver;
76 // NonPolymorphicPointerLoader: once we know which concrete type to load,
77 // we use the 'normal' class loader to load it.
78 template<typename T> struct NonPolymorphicPointerLoader;
79 // Used by PolymorphicInitializer to initialize a concrete type.
80 template<typename T> struct ClassLoader;
81 
87 template<typename T> struct PolymorphicConstructorArgs;
88 
92 template<typename T> struct PolymorphicBaseClass;
93 
94 template<typename Base> struct MapConstrArgsEmpty
95 {
96  typedef typename PolymorphicConstructorArgs<Base>::type TUPLEIn;
97  std::tuple<> operator()(const TUPLEIn& /*t*/)
98  {
99  return std::make_tuple();
100  }
101 };
102 template<typename Base, typename Derived> struct MapConstrArgsCopy
103 {
104  typedef typename PolymorphicConstructorArgs<Base>::type TUPLEIn;
105  typedef typename PolymorphicConstructorArgs<Derived>::type TUPLEOut;
106  static_assert(std::is_same<TUPLEIn, TUPLEOut>::value,
107  "constructor argument types must match");
109  {
110  return t;
111  }
112 };
113 
126 template<typename Base, typename Derived> struct MapConstructorArguments
127  : if_<std::is_same<std::tuple<>,
128  typename PolymorphicConstructorArgs<Derived>::type>,
129  MapConstrArgsEmpty<Base>,
130  MapConstrArgsCopy<Base, Derived>> {};
131 
138 template<typename Base> struct BaseClassName;
139 
140 template<typename Archive> class PolymorphicSaverBase
141 {
142 public:
144  virtual void save(Archive& ar, const void* p) const = 0;
145 };
146 
147 template<typename Archive> class PolymorphicLoaderBase
148 {
149 public:
151  virtual void* load(Archive& ar, unsigned id, const void* args) const = 0;
152 };
153 
154 template<typename Archive> class PolymorphicInitializerBase
155 {
156 public:
158  virtual void init(Archive& ar, void* t, unsigned id) const = 0;
159 };
160 
161 template<typename Archive, typename T>
162 class PolymorphicSaver : public PolymorphicSaverBase<Archive>
163 {
164 public:
165  PolymorphicSaver(const char* name_)
166  : name(name_)
167  {
168  }
169  virtual void save(Archive& ar, const void* v) const
170  {
171  typedef typename PolymorphicBaseClass<T>::type BaseType;
172  auto base = static_cast<const BaseType*>(v);
173  auto tp = static_cast<const T*>(base);
174  ClassSaver<T> saver;
175  saver(ar, *tp, true, name, true); // save id, type, constr-args
176  }
177 private:
178  const char* name;
179 };
180 
181 template<typename Archive, typename T>
183 {
184 public:
185  virtual void* load(Archive& ar, unsigned id, const void* args) const
186  {
187  typedef typename PolymorphicBaseClass<T>::type BaseType;
188  typedef typename PolymorphicConstructorArgs<BaseType>::type TUPLEIn;
189  typedef typename PolymorphicConstructorArgs<T>::type TUPLEOut;
190  auto& argsIn = *static_cast<const TUPLEIn*>(args);
192  TUPLEOut argsOut = mapArgs(argsIn);
194  return loader(ar, id, argsOut);
195  }
196 };
197 
198 void polyInitError(const char* expected, const char* actual);
199 template<typename Archive, typename T>
201 {
202 public:
203  virtual void init(Archive& ar, void* v, unsigned id) const
204  {
205  typedef typename PolymorphicBaseClass<T>::type BaseType;
206  auto base = static_cast<BaseType*>(v);
207  if (unlikely(dynamic_cast<T*>(base) != static_cast<T*>(base))) {
208  polyInitError(typeid(T).name(), typeid(*base).name());
209  }
210  auto t = static_cast<T*>(base);
211  ClassLoader<T> loader;
212  loader(ar, *t, std::make_tuple(), id);
213  }
214 };
215 
216 
217 template<typename Archive>
219 {
220 public:
222 
223  template<typename T> void registerClass(const char* name)
224  {
225  static_assert(std::is_polymorphic<T>::value,
226  "must be a polymorphic type");
227  static_assert(!std::is_abstract<T>::value,
228  "can't be an abstract type");
229  registerHelper(typeid(T),
231  }
232 
233  template<typename T> static void save(Archive& ar, T* t)
234  {
235  save(ar, t, typeid(*t));
236  }
237  template<typename T> static void save(const char* tag, Archive& ar, T& t)
238  {
239  save(tag, ar, &t, typeid(t));
240  }
241 
242 private:
245  void registerHelper(const std::type_info& type,
246  std::unique_ptr<PolymorphicSaverBase<Archive>> saver);
247  static void save(Archive& ar, const void* t,
248  const std::type_info& typeInfo);
249  static void save(const char* tag, Archive& ar, const void* t,
250  const std::type_info& typeInfo);
251 
252  std::map<TypeInfo, std::unique_ptr<PolymorphicSaverBase<Archive>>>
253  saverMap;
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 };
283 
284 template<typename Archive>
286 {
287 public:
289 
290  template<typename T> void registerClass(const char* name)
291  {
292  static_assert(std::is_polymorphic<T>::value,
293  "must be a polymorphic type");
294  static_assert(!std::is_abstract<T>::value,
295  "can't be an abstract type");
296  registerHelper(name,
298  }
299 
300  static void init(const char* tag, Archive& ar, void* t);
301 
302 private:
305  void registerHelper(
306  const char* name,
307  std::unique_ptr<PolymorphicInitializerBase<Archive>> initializer);
308 
310  initializerMap;
311 };
312 
313 
314 template<typename Archive, typename T> struct RegisterSaverHelper
315 {
316  RegisterSaverHelper(const char* name)
317  {
319  template registerClass<T>(name);
320  }
321 };
322 template<typename Archive, typename T> struct RegisterLoaderHelper
323 {
324  RegisterLoaderHelper(const char* name)
325  {
327  template registerClass<T>(name);
328  }
329 };
330 template<typename Archive, typename T> struct RegisterInitializerHelper
331 {
332  RegisterInitializerHelper(const char* name)
333  {
335  template registerClass<T>(name);
336  }
337 };
338 
339 #define REGISTER_CONSTRUCTOR_ARGS_0(C) \
340 template<> struct PolymorphicConstructorArgs<C> \
341 { typedef std::tuple<> type; };
342 
343 #define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
344 template<> struct PolymorphicConstructorArgs<C> \
345 { typedef std::tuple<T1> type; };
346 
347 #define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
348 template<> struct PolymorphicConstructorArgs<C> \
349 { typedef std::tuple<T1,T2> type; };
350 
351 #define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
352 template<> struct PolymorphicConstructorArgs<C> \
353 { typedef std::tuple<T1,T2,T3> type; };
354 
355 class MemInputArchive;
356 class MemOutputArchive;
357 class XmlInputArchive;
358 class XmlOutputArchive;
359 
360 /*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
361 static_assert(std::is_base_of<B,C>::value, "must be base and sub class"); \
362 static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
363 static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
364 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
365 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
366 static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
367 static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
368 #define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
369 static_assert(std::is_base_of<B,C>::value, "must be base and sub class"); \
370 static RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
371 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
372 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
373 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
374 template<> struct PolymorphicBaseClass<C> { typedef B type; };
375 
376 #define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
377 static_assert(std::is_base_of<B,C>::value, "must be base and sub class"); \
378 static RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
379 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
380 static RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
381 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
382 template<> struct PolymorphicBaseClass<C> { typedef B type; };
383 
384 #define REGISTER_BASE_NAME_HELPER(B,N) \
385 template<> struct BaseClassName<B> \
386 { static const char* getName() { static const char* name = N; return name; } };
387 
388 // public macros
389 // these are a more convenient way to define specializations of the
390 // PolymorphicConstructorArgs and PolymorphicBaseClass classes
391 #define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
392  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
393  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
394 
395 #define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
396  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
397  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
398 
399 #define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
400  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
401  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
402 
403 #define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
404  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
405  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
406 
407 #define REGISTER_BASE_CLASS(CLASS,NAME) \
408  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
409  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
410 
411 #define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
412  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
413  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
414 
415 #define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
416  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
417  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
418 
419 #define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
420  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
421  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
422 
423 
424 #define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
425  REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
426 
428 
444 template<typename T> struct SerializeClassVersion
445 {
446  static const unsigned value = 1;
447 };
448 #define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
449 template<> struct SerializeClassVersion<CLASS> \
450 { \
451  static const unsigned value = VERSION; \
452 };
453 
454 } // namespace openmsx
455 
456 #endif