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 void polyInitError(const char* expected, const char* actual);
114 
115 template<typename Archive>
117 {
118 public:
121 
123 
124  template<typename T> void registerClass(const char* name)
125  {
126  static_assert(std::is_polymorphic_v<T>,
127  "must be a polymorphic type");
128  static_assert(!std::is_abstract_v<T>,
129  "can't be an abstract type");
130  registerHelper(typeid(T), [name](Archive& ar, const void* v) {
131  using BaseType = typename PolymorphicBaseClass<T>::type;
132  auto base = static_cast<const BaseType*>(v);
133  auto tp = static_cast<const T*>(base);
134  ClassSaver<T> saver;
135  saver(ar, *tp, true, name, true); // save id, type, constr-args
136  });
137  }
138 
139  template<typename T> static void save(Archive& ar, T* t)
140  {
141  save(ar, t, typeid(*t));
142  }
143  template<typename T> static void save(const char* tag, Archive& ar, T& t)
144  {
145  save(tag, ar, &t, typeid(t));
146  }
147 
148 private:
149  PolymorphicSaverRegistry() = default;
150  ~PolymorphicSaverRegistry() = default;
151 
152  using SaveFunction = std::function<void(Archive&, const void*)>;
153  void registerHelper(const std::type_info& type,
154  SaveFunction saver);
155  static void save(Archive& ar, const void* t,
156  const std::type_info& typeInfo);
157  static void save(const char* tag, Archive& ar, const void* t,
158  const std::type_info& typeInfo);
159 
160  struct Entry {
161  std::type_index index;
162  SaveFunction saver;
163  };
164  std::vector<Entry> saverMap;
165  bool initialized = false;
166 };
167 
168 template<typename Archive>
170 {
171 public:
174 
176 
177  template<typename T> void registerClass(const char* name)
178  {
179  static_assert(std::is_polymorphic_v<T>,
180  "must be a polymorphic type");
181  static_assert(!std::is_abstract_v<T>,
182  "can't be an abstract type");
183  registerHelper(name, [](Archive& ar, unsigned id, const void* args) {
184  using BaseType = typename PolymorphicBaseClass<T>::type;
185  using TUPLEIn = typename PolymorphicConstructorArgs<BaseType>::type;
186  using TUPLEOut = typename PolymorphicConstructorArgs<T>::type;
187  auto& argsIn = *static_cast<const TUPLEIn*>(args);
189  TUPLEOut argsOut = mapArgs(argsIn);
191  return loader(ar, id, argsOut);
192  });
193  }
194 
195  static void* load(Archive& ar, unsigned id, const void* args);
196 
197 private:
198  PolymorphicLoaderRegistry() = default;
199  ~PolymorphicLoaderRegistry() = default;
200 
201  using LoadFunction = std::function<void*(Archive&, unsigned, const void*)>;
202  void registerHelper(const char* name, LoadFunction loader);
203 
205 };
206 
207 template<typename Archive>
209 {
210 public:
213 
215 
216  template<typename T> void registerClass(const char* name)
217  {
218  static_assert(std::is_polymorphic_v<T>,
219  "must be a polymorphic type");
220  static_assert(!std::is_abstract_v<T>,
221  "can't be an abstract type");
222  registerHelper(name, [](Archive& ar, void* v, unsigned id) {
223  using BaseType = typename PolymorphicBaseClass<T>::type;
224  auto base = static_cast<BaseType*>(v);
225  if (unlikely(dynamic_cast<T*>(base) != static_cast<T*>(base))) {
226  polyInitError(typeid(T).name(), typeid(*base).name());
227  }
228  auto t = static_cast<T*>(base);
229  ClassLoader<T> loader;
230  loader(ar, *t, std::tuple<>(), id);
231  });
232  }
233 
234  static void init(const char* tag, Archive& ar, void* t);
235 
236 private:
237  PolymorphicInitializerRegistry() = default;
238  ~PolymorphicInitializerRegistry() = default;
239 
240  using InitFunction = std::function<void(Archive&, void*, unsigned)>;
241  void registerHelper(const char* name, InitFunction initializer);
242 
244 };
245 
246 
247 template<typename Archive, typename T> struct RegisterSaverHelper
248 {
249  explicit RegisterSaverHelper(const char* name)
250  {
252  template registerClass<T>(name);
253  }
254 };
255 template<typename Archive, typename T> struct RegisterLoaderHelper
256 {
257  explicit RegisterLoaderHelper(const char* name)
258  {
260  template registerClass<T>(name);
261  }
262 };
263 template<typename Archive, typename T> struct RegisterInitializerHelper
264 {
265  explicit RegisterInitializerHelper(const char* name)
266  {
268  template registerClass<T>(name);
269  }
270 };
271 
272 #define REGISTER_CONSTRUCTOR_ARGS_0(C) \
273 template<> struct PolymorphicConstructorArgs<C> \
274 { using type = std::tuple<>; };
275 
276 #define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
277 template<> struct PolymorphicConstructorArgs<C> \
278 { using type = std::tuple<T1>; };
279 
280 #define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
281 template<> struct PolymorphicConstructorArgs<C> \
282 { using type = std::tuple<T1,T2>; };
283 
284 #define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
285 template<> struct PolymorphicConstructorArgs<C> \
286 { using type = std::tuple<T1,T2,T3>; };
287 
288 class MemInputArchive;
289 class MemOutputArchive;
290 class XmlInputArchive;
291 class XmlOutputArchive;
292 
293 /*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
294 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
295 static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
296 static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
297 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
298 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
299 static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
300 static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
301 #define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
302 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
303 static RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
304 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
305 static RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
306 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
307 template<> struct PolymorphicBaseClass<C> { using type = B; };
308 
309 #define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
310 static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
311 static RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
312 static RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
313 static RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
314 static RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
315 template<> struct PolymorphicBaseClass<C> { using type = B; };
316 
317 #define REGISTER_BASE_NAME_HELPER(B,N) \
318 template<> struct BaseClassName<B> \
319 { static const char* getName() { static constexpr const char* const name = N; return name; } };
320 
321 // public macros
322 // these are a more convenient way to define specializations of the
323 // PolymorphicConstructorArgs and PolymorphicBaseClass classes
324 #define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
325  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
326  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
327 
328 #define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
329  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
330  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
331 
332 #define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
333  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
334  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
335 
336 #define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
337  REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
338  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
339 
340 #define REGISTER_BASE_CLASS(CLASS,NAME) \
341  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
342  REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
343 
344 #define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
345  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
346  REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
347 
348 #define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
349  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
350  REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
351 
352 #define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
353  REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
354  REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
355 
356 
357 #define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
358  REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
359 
361 
377 template<typename T> struct SerializeClassVersion
378 {
379  static constexpr unsigned value = 1;
380 };
381 #define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
382 template<> struct SerializeClassVersion<CLASS> \
383 { \
384  static constexpr unsigned value = VERSION; \
385 };
386 
387 } // namespace openmsx
388 
389 #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)
#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.