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 "xxhash.hh"
6 #include <memory>
7 #include <tuple>
8 #include <typeindex>
9 #include <type_traits>
10 #include <utility>
11 #include <vector>
12 
13 namespace openmsx {
14 
29 template<typename T> struct Creator
30 {
31  template<typename TUPLE>
32  std::unique_ptr<T> operator()(TUPLE tuple) {
33  auto makeT = [](auto&& ...args) {
34  return std::make_unique<T>(std::forward<decltype(args)>(args)...);
35  };
36  return std::apply(makeT, tuple);
37  }
38 };
39 
41 
42 // Polymorphic class loader/saver
43 
44 // forward declarations
45 // ClassSaver: used to actually save a class. We also store the name of
46 // the class so that the loader knows which concrete class it should load.
47 template<typename T> struct ClassSaver;
48 // NonPolymorphicPointerLoader: once we know which concrete type to load,
49 // we use the 'normal' class loader to load it.
50 template<typename T> struct NonPolymorphicPointerLoader;
51 // Used by PolymorphicInitializer to initialize a concrete type.
52 template<typename T> struct ClassLoader;
53 
59 template<typename T> struct PolymorphicConstructorArgs;
60 
64 template<typename T> struct PolymorphicBaseClass;
65 
66 template<typename Base> struct MapConstrArgsEmpty
67 {
69  std::tuple<> operator()(const TUPLEIn& /*t*/)
70  {
71  return std::tuple<>();
72  }
73 };
74 template<typename Base, typename Derived> struct MapConstrArgsCopy
75 {
78  static_assert(std::is_same_v<TUPLEIn, TUPLEOut>,
79  "constructor argument types must match");
81  {
82  return t;
83  }
84 };
85 
98 template<typename Base, typename Derived> struct MapConstructorArguments
99  : std::conditional_t<std::is_same<std::tuple<>,
100  typename PolymorphicConstructorArgs<Derived>::type>::value,
101  MapConstrArgsEmpty<Base>,
102  MapConstrArgsCopy<Base, Derived>> {};
103 
110 template<typename Base> struct BaseClassName;
111 
112 void polyInitError(const char* expected, const char* actual);
113 
114 template<typename Archive>
116 {
117 public:
120 
122 
123  template<typename T> void registerClass(const char* name)
124  {
125  static_assert(std::is_polymorphic_v<T>,
126  "must be a polymorphic type");
127  static_assert(!std::is_abstract_v<T>,
128  "can't be an abstract type");
129  registerHelper(typeid(T), [name](Archive& ar, const void* v) {
130  using BaseType = typename PolymorphicBaseClass<T>::type;
131  auto base = static_cast<const BaseType*>(v);
132  auto tp = static_cast<const T*>(base);
133  ClassSaver<T> saver;
134  saver(ar, *tp, true, name, true); // save id, type, constr-args
135  });
136  }
137 
138  template<typename T> static void save(Archive& ar, T* t)
139  {
140  save(ar, t, typeid(*t));
141  }
142  template<typename T> static void save(const char* tag, Archive& ar, T& t)
143  {
144  save(tag, ar, &t, typeid(t));
145  }
146 
147 private:
148  PolymorphicSaverRegistry() = default;
149  ~PolymorphicSaverRegistry() = default;
150 
151  using SaveFunction = std::function<void(Archive&, const void*)>;
152  void registerHelper(const std::type_info& type,
153  SaveFunction saver);
154  static void save(Archive& ar, const void* t,
155  const std::type_info& typeInfo);
156  static void save(const char* tag, Archive& ar, const void* t,
157  const std::type_info& typeInfo);
158 
159  struct Entry {
160  std::type_index index;
161  SaveFunction saver;
162  };
163  std::vector<Entry> saverMap;
164  bool initialized = false;
165 };
166 
167 template<typename Archive>
169 {
170 public:
173 
175 
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(name, [](Archive& ar, unsigned id, const void* args) {
183  using BaseType = typename PolymorphicBaseClass<T>::type;
184  using TUPLEIn = typename PolymorphicConstructorArgs<BaseType>::type;
185  using TUPLEOut = typename PolymorphicConstructorArgs<T>::type;
186  auto& argsIn = *static_cast<const TUPLEIn*>(args);
188  TUPLEOut argsOut = mapArgs(argsIn);
190  return loader(ar, id, argsOut);
191  });
192  }
193 
194  static void* load(Archive& ar, unsigned id, const void* args);
195 
196 private:
197  PolymorphicLoaderRegistry() = default;
198  ~PolymorphicLoaderRegistry() = default;
199 
200  using LoadFunction = std::function<void*(Archive&, unsigned, const void*)>;
201  void registerHelper(const char* name, LoadFunction loader);
202 
204 };
205 
206 template<typename Archive>
208 {
209 public:
212 
214 
215  template<typename T> void registerClass(const char* name)
216  {
217  static_assert(std::is_polymorphic_v<T>,
218  "must be a polymorphic type");
219  static_assert(!std::is_abstract_v<T>,
220  "can't be an abstract type");
221  registerHelper(name, [](Archive& ar, void* v, unsigned id) {
222  using BaseType = typename PolymorphicBaseClass<T>::type;
223  auto base = static_cast<BaseType*>(v);
224  if (dynamic_cast<T*>(base) != static_cast<T*>(base)) [[unlikely]] {
225  polyInitError(typeid(T).name(), typeid(*base).name());
226  }
227  auto t = static_cast<T*>(base);
228  ClassLoader<T> loader;
229  loader(ar, *t, std::tuple<>(), id);
230  });
231  }
232 
233  static void init(const char* tag, Archive& ar, void* t);
234 
235 private:
236  PolymorphicInitializerRegistry() = default;
237  ~PolymorphicInitializerRegistry() = default;
238 
239  using InitFunction = std::function<void(Archive&, void*, unsigned)>;
240  void registerHelper(const char* name, InitFunction initializer);
241 
243 };
244 
245 
246 template<typename Archive, typename T> struct RegisterSaverHelper
247 {
248  explicit RegisterSaverHelper(const char* name)
249  {
251  template registerClass<T>(name);
252  }
253 };
254 template<typename Archive, typename T> struct RegisterLoaderHelper
255 {
256  explicit RegisterLoaderHelper(const char* name)
257  {
259  template registerClass<T>(name);
260  }
261 };
262 template<typename Archive, typename T> struct RegisterInitializerHelper
263 {
264  explicit RegisterInitializerHelper(const char* name)
265  {
267  template registerClass<T>(name);
268  }
269 };
270 
271 #define REGISTER_CONSTRUCTOR_ARGS_0(C) \
272 template<> struct PolymorphicConstructorArgs<C> \
273 { using type = std::tuple<>; };
274 
275 #define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
276 template<> struct PolymorphicConstructorArgs<C> \
277 { using type = std::tuple<T1>; };
278 
279 #define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
280 template<> struct PolymorphicConstructorArgs<C> \
281 { using type = std::tuple<T1,T2>; };
282 
283 #define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
284 template<> struct PolymorphicConstructorArgs<C> \
285 { using type = std::tuple<T1,T2,T3>; };
286 
287 class MemInputArchive;
288 class MemOutputArchive;
289 class XmlInputArchive;
290 class XmlOutputArchive;
291 
292 /*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
293 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
294 static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
295 static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
296 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
297 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
298 static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
299 static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
300 #define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
301 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
302 static RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
303 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
304 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
305 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
306 template<> struct PolymorphicBaseClass<C> { using type = B; };
307 
308 #define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
309 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
310 static RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
311 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
312 static RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
313 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
314 template<> struct PolymorphicBaseClass<C> { using type = B; };
315 
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 
320 // public macros
321 // these are a more convenient way to define specializations of the
322 // PolymorphicConstructorArgs and PolymorphicBaseClass classes
323 #define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
324  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
325  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
326 
327 #define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
328  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
329  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
330 
331 #define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
332  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
333  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
334 
335 #define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
336  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
337  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
338 
339 #define REGISTER_BASE_CLASS(CLASS,NAME) \
340  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
341  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
342 
343 #define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
344  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
345  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
346 
347 #define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
348  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
349  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
350 
351 #define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
352  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
353  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
354 
355 
356 #define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
357  REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
358 
360 
376 template<typename T> struct SerializeClassVersion
377 {
378  static constexpr unsigned value = 1;
379 };
380 #define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
381 template<> struct SerializeClassVersion<CLASS> \
382 { \
383  static constexpr unsigned value = VERSION; \
384 };
385 
386 } // namespace openmsx
387 
388 #endif
TclObject t
static void init(const char *tag, Archive &ar, void *t)
PolymorphicInitializerRegistry(const PolymorphicInitializerRegistry &)=delete
PolymorphicInitializerRegistry & operator=(const PolymorphicInitializerRegistry &)=delete
static PolymorphicInitializerRegistry & instance()
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
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)
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.