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
13namespace openmsx {
14
29template<typename T> struct Creator
30{
31 template<typename TUPLE>
32 std::unique_ptr<T> operator()(TUPLE tuple) {
33 auto makeT = []<typename... Args>(Args&& ...args) {
34 return std::make_unique<T>(std::forward<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.
47template<typename T> struct ClassSaver;
48// NonPolymorphicPointerLoader: once we know which concrete type to load,
49// we use the 'normal' class loader to load it.
50template<typename T> struct NonPolymorphicPointerLoader;
51// Used by PolymorphicInitializer to initialize a concrete type.
52template<typename T> struct ClassLoader;
53
59template<typename T> struct PolymorphicConstructorArgs;
60
64template<typename T> struct PolymorphicBaseClass;
65
66template<typename Base> struct MapConstrArgsEmpty
67{
69 std::tuple<> operator()(const TUPLEIn& /*t*/) const
70 {
71 return {};
72 }
73};
74template<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
98template<typename Base, typename Derived> struct MapConstructorArguments
99 : std::conditional_t<std::is_same_v<std::tuple<>,
100 typename PolymorphicConstructorArgs<Derived>::type>,
101 MapConstrArgsEmpty<Base>,
102 MapConstrArgsCopy<Base, Derived>> {};
103
110template<typename Base> struct BaseClassName;
111
112[[noreturn]] void polyInitError(const char* expected, const char* actual);
113
114template<typename Archive>
116{
117public:
122
124
125 template<typename T> void registerClass(const char* name)
126 {
127 static_assert(std::is_polymorphic_v<T>,
128 "must be a polymorphic type");
129 static_assert(!std::is_abstract_v<T>,
130 "can't be an abstract type");
131 registerHelper(typeid(T), [name](Archive& ar, const void* v) {
132 using BaseType = typename PolymorphicBaseClass<T>::type;
133 auto base = static_cast<const BaseType*>(v);
134 auto tp = static_cast<const T*>(base);
135 ClassSaver<T> saver;
136 saver(ar, *tp, true, name, true); // save id, type, constr-args
137 });
138 }
139
140 template<typename T> static void save(Archive& ar, T* t)
141 {
142 save(ar, t, typeid(*t));
143 }
144 template<typename T> static void save(const char* tag, Archive& ar, T& t)
145 {
146 save(tag, ar, &t, typeid(t));
147 }
148
149private:
150 PolymorphicSaverRegistry() = default;
151 ~PolymorphicSaverRegistry() = default;
152
153 using SaveFunction = std::function<void(Archive&, const void*)>;
154 void registerHelper(const std::type_info& type,
155 SaveFunction saver);
156 static void save(Archive& ar, const void* t,
157 const std::type_info& typeInfo);
158 static void save(const char* tag, Archive& ar, const void* t,
159 const std::type_info& typeInfo);
160
161 struct Entry {
162 Entry(std::type_index i, SaveFunction s)
163 : index(i), saver(std::move(s)) {} // clang-15 workaround
164
165 std::type_index index;
166 SaveFunction saver;
167 };
168 std::vector<Entry> saverMap;
169 bool initialized = false;
170};
171
172template<typename Archive>
174{
175public:
180
182
183 template<typename T> void registerClass(const char* name)
184 {
185 static_assert(std::is_polymorphic_v<T>,
186 "must be a polymorphic type");
187 static_assert(!std::is_abstract_v<T>,
188 "can't be an abstract type");
189 registerHelper(name, [](Archive& ar, unsigned id, const void* args) {
190 using BaseType = typename PolymorphicBaseClass<T>::type;
191 using TUPLEIn = typename PolymorphicConstructorArgs<BaseType>::type;
192 using TUPLEOut = typename PolymorphicConstructorArgs<T>::type;
193 auto& argsIn = *static_cast<const TUPLEIn*>(args);
195 TUPLEOut argsOut = mapArgs(argsIn);
197 return loader(ar, id, argsOut);
198 });
199 }
200
201 static void* load(Archive& ar, unsigned id, const void* args);
202
203private:
204 PolymorphicLoaderRegistry() = default;
205 ~PolymorphicLoaderRegistry() = default;
206
207 using LoadFunction = std::function<void*(Archive&, unsigned, const void*)>;
208 void registerHelper(const char* name, LoadFunction loader);
209
211};
212
213template<typename Archive>
215{
216public:
221
223
224 template<typename T> void registerClass(const char* name)
225 {
226 static_assert(std::is_polymorphic_v<T>,
227 "must be a polymorphic type");
228 static_assert(!std::is_abstract_v<T>,
229 "can't be an abstract type");
230 registerHelper(name, [](Archive& ar, void* v, unsigned id) {
231 using BaseType = typename PolymorphicBaseClass<T>::type;
232 auto base = static_cast<BaseType*>(v);
233 if (dynamic_cast<T*>(base) != static_cast<T*>(base)) [[unlikely]] {
234 polyInitError(typeid(T).name(), typeid(*base).name());
235 }
236 auto t = static_cast<T*>(base);
237 ClassLoader<T> loader;
238 loader(ar, *t, std::tuple<>(), id);
239 });
240 }
241
242 static void init(const char* tag, Archive& ar, void* t);
243
244private:
247
248 using InitFunction = std::function<void(Archive&, void*, unsigned)>;
249 void registerHelper(const char* name, InitFunction initializer);
250
252};
253
254
255template<typename Archive, typename T> struct RegisterSaverHelper
256{
257 explicit RegisterSaverHelper(const char* name)
258 {
260 template registerClass<T>(name);
261 }
262};
263template<typename Archive, typename T> struct RegisterLoaderHelper
264{
265 explicit RegisterLoaderHelper(const char* name)
266 {
268 template registerClass<T>(name);
269 }
270};
271template<typename Archive, typename T> struct RegisterInitializerHelper
272{
273 explicit RegisterInitializerHelper(const char* name)
274 {
276 template registerClass<T>(name);
277 }
278};
279
280#define REGISTER_CONSTRUCTOR_ARGS_0(C) \
281template<> struct PolymorphicConstructorArgs<C> \
282{ using type = std::tuple<>; };
283
284#define REGISTER_CONSTRUCTOR_ARGS_1(C,T1) \
285template<> struct PolymorphicConstructorArgs<C> \
286{ using type = std::tuple<T1>; };
287
288#define REGISTER_CONSTRUCTOR_ARGS_2(C,T1,T2) \
289template<> struct PolymorphicConstructorArgs<C> \
290{ using type = std::tuple<T1,T2>; };
291
292#define REGISTER_CONSTRUCTOR_ARGS_3(C,T1,T2,T3) \
293template<> struct PolymorphicConstructorArgs<C> \
294{ using type = std::tuple<T1,T2,T3>; };
295
296class MemInputArchive;
297class MemOutputArchive;
298class XmlInputArchive;
299class XmlOutputArchive;
300
301/*#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
302static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
303static RegisterLoaderHelper<TextInputArchive, C> registerHelper1##C(N); \
304static RegisterSaverHelper <TextOutputArchive, C> registerHelper2##C(N); \
305static RegisterLoaderHelper<XmlInputArchive, C> registerHelper3##C(N); \
306static RegisterSaverHelper <XmlOutputArchive, C> registerHelper4##C(N); \
307static RegisterLoaderHelper<MemInputArchive, C> registerHelper5##C(N); \
308static RegisterSaverHelper <MemOutputArchive, C> registerHelper6##C(N); \*/
309#define REGISTER_POLYMORPHIC_CLASS_HELPER(B,C,N) \
310static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
311static const RegisterLoaderHelper<MemInputArchive, C> registerHelper3##C(N); \
312static const RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
313static const RegisterLoaderHelper<XmlInputArchive, C> registerHelper5##C(N); \
314static const RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
315template<> struct PolymorphicBaseClass<C> { using type = B; };
316
317#define REGISTER_POLYMORPHIC_INITIALIZER_HELPER(B,C,N) \
318static_assert(std::is_base_of_v<B,C>, "must be base and sub class"); \
319static const RegisterInitializerHelper<MemInputArchive, C> registerHelper3##C(N); \
320static const RegisterSaverHelper <MemOutputArchive, C> registerHelper4##C(N); \
321static const RegisterInitializerHelper<XmlInputArchive, C> registerHelper5##C(N); \
322static const RegisterSaverHelper <XmlOutputArchive, C> registerHelper6##C(N); \
323template<> struct PolymorphicBaseClass<C> { using type = B; };
324
325#define REGISTER_BASE_NAME_HELPER(B,N) \
326template<> struct BaseClassName<B> \
327{ static const char* getName() { static constexpr const char* const name = N; return name; } };
328
329// public macros
330// these are a more convenient way to define specializations of the
331// PolymorphicConstructorArgs and PolymorphicBaseClass classes
332#define REGISTER_POLYMORPHIC_CLASS(BASE,CLASS,NAME) \
333 REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
334 REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
335
336#define REGISTER_POLYMORPHIC_CLASS_1(BASE,CLASS,NAME,TYPE1) \
337 REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
338 REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
339
340#define REGISTER_POLYMORPHIC_CLASS_2(BASE,CLASS,NAME,TYPE1,TYPE2) \
341 REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
342 REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
343
344#define REGISTER_POLYMORPHIC_CLASS_3(BASE,CLASS,NAME,TYPE1,TYPE2,TYPE3) \
345 REGISTER_POLYMORPHIC_CLASS_HELPER(BASE,CLASS,NAME) \
346 REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
347
348#define REGISTER_BASE_CLASS(CLASS,NAME) \
349 REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
350 REGISTER_CONSTRUCTOR_ARGS_0(CLASS)
351
352#define REGISTER_BASE_CLASS_1(CLASS,NAME,TYPE1) \
353 REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
354 REGISTER_CONSTRUCTOR_ARGS_1(CLASS,TYPE1)
355
356#define REGISTER_BASE_CLASS_2(CLASS,NAME,TYPE1,TYPE2) \
357 REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
358 REGISTER_CONSTRUCTOR_ARGS_2(CLASS,TYPE1,TYPE2)
359
360#define REGISTER_BASE_CLASS_3(CLASS,NAME,TYPE1,TYPE2,TYPE3) \
361 REGISTER_BASE_NAME_HELPER(CLASS,NAME) \
362 REGISTER_CONSTRUCTOR_ARGS_3(CLASS,TYPE1,TYPE2,TYPE3)
363
364
365#define REGISTER_POLYMORPHIC_INITIALIZER(BASE,CLASS,NAME) \
366 REGISTER_POLYMORPHIC_INITIALIZER_HELPER(BASE,CLASS,NAME)
367
369
385template<typename T> struct SerializeClassVersion
386{
387 static constexpr unsigned value = 1;
388};
389#define SERIALIZE_CLASS_VERSION(CLASS, VERSION) \
390template<> struct SerializeClassVersion<CLASS> \
391{ \
392 static constexpr unsigned value = VERSION; \
393};
394
395} // namespace openmsx
396
397#endif
TclObject t
PolymorphicInitializerRegistry & operator=(PolymorphicInitializerRegistry &&)=delete
PolymorphicInitializerRegistry(PolymorphicInitializerRegistry &&)=delete
static void init(const char *tag, Archive &ar, void *t)
PolymorphicInitializerRegistry & operator=(const PolymorphicInitializerRegistry &)=delete
PolymorphicInitializerRegistry(const PolymorphicInitializerRegistry &)=delete
static PolymorphicInitializerRegistry & instance()
static PolymorphicLoaderRegistry & instance()
PolymorphicLoaderRegistry & operator=(PolymorphicLoaderRegistry &&)=delete
void registerClass(const char *name)
PolymorphicLoaderRegistry & operator=(const PolymorphicLoaderRegistry &)=delete
static void * load(Archive &ar, unsigned id, const void *args)
PolymorphicLoaderRegistry(PolymorphicLoaderRegistry &&)=delete
PolymorphicLoaderRegistry(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)
PolymorphicSaverRegistry & operator=(PolymorphicSaverRegistry &&)=delete
void registerClass(const char *name)
static void save(Archive &ar, T *t)
PolymorphicSaverRegistry(PolymorphicSaverRegistry &&)=delete
This file implemented 3 utility functions:
Definition Autofire.cc:11
void polyInitError(const char *expected, const char *actual)
STL namespace.
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
typename PolymorphicConstructorArgs< Base >::type TUPLEIn
std::tuple operator()(const TUPLEIn &) const
Define mapping between constructor arg list of base- and subclass.
Store association between (polymorphic) sub- and base class.
Store association between polymorphic class (base- or subclass) and the list of constructor arguments...
RegisterLoaderHelper(const char *name)
RegisterSaverHelper(const char *name)
Store serialization-version number of a class.