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