openMSX
serialize_core.hh
Go to the documentation of this file.
1 #ifndef SERIALIZE_CORE_HH
2 #define SERIALIZE_CORE_HH
3 
4 #include "serialize_constr.hh"
5 #include "serialize_meta.hh"
6 #include "one_of.hh"
7 #include <string>
8 #include <type_traits>
9 #include <cassert>
10 #include <memory>
11 
12 namespace openmsx {
13 
14 // Type-queries for serialization framework
15 // is_primitive<T>
16 template<typename T> struct is_primitive : std::false_type {};
17 template<> struct is_primitive<bool> : std::true_type {};
18 template<> struct is_primitive<char> : std::true_type {};
19 template<> struct is_primitive<signed char> : std::true_type {};
20 template<> struct is_primitive<signed short> : std::true_type {};
21 template<> struct is_primitive<signed int> : std::true_type {};
22 template<> struct is_primitive<signed long> : std::true_type {};
23 template<> struct is_primitive<unsigned char> : std::true_type {};
24 template<> struct is_primitive<unsigned short> : std::true_type {};
25 template<> struct is_primitive<unsigned int> : std::true_type {};
26 template<> struct is_primitive<unsigned long> : std::true_type {};
27 template<> struct is_primitive<float> : std::true_type {};
28 template<> struct is_primitive<double> : std::true_type {};
29 template<> struct is_primitive<long double> : std::true_type {};
30 template<> struct is_primitive<long long> : std::true_type {};
31 template<> struct is_primitive<unsigned long long> : std::true_type {};
32 template<> struct is_primitive<std::string> : std::true_type {};
33 
34 
35 
36 // Normally to make a class serializable, you have to implement a serialize()
37 // method on the class. For some classes we cannot extend the source code. So
38 // we need an alternative, non-intrusive, way to make those classes
39 // serializable.
40 template <typename Archive, typename T>
41 void serialize(Archive& ar, T& t, unsigned version)
42 {
43  // By default use the serialize() member. But this function can
44  // be overloaded to serialize classes in a non-intrusive way.
45  t.serialize(ar, version);
46 }
47 
48 template <typename Archive, typename T1, typename T2>
49 void serialize(Archive& ar, std::pair<T1, T2>& p, unsigned /*version*/)
50 {
51  ar.serialize("first", p.first,
52  "second", p.second);
53 }
54 template<typename T1, typename T2> struct SerializeClassVersion<std::pair<T1, T2>>
55 {
56  static constexpr unsigned value = 0;
57 };
58 
60 
97 template<typename T> struct serialize_as_enum : std::false_type {};
98 
99 template<typename T> struct enum_string {
100  const char* str;
101  T e;
102 };
103 void enumError(const std::string& str);
104 template<typename T> struct serialize_as_enum_impl : std::true_type {
105  explicit serialize_as_enum_impl(std::initializer_list<enum_string<T>> info_)
106  : info(info_) {}
107  std::string toString(T t) const {
108  for (auto& i : info) {
109  if (i.e == t) return i.str;
110  }
111  assert(false);
112  return "internal-error-unknown-enum-value";
113  }
114  T fromString(const std::string& str) const {
115  for (auto& i : info) {
116  if (i.str == str) return i.e;
117  }
118  enumError(str); // does not return (throws)
119  return T(); // avoid warning
120  }
121 private:
122  std::initializer_list<enum_string<T>> info;
123 };
124 
125 #define SERIALIZE_ENUM(TYPE,INFO) \
126 template<> struct serialize_as_enum< TYPE > : serialize_as_enum_impl< TYPE > { \
127  serialize_as_enum() : serialize_as_enum_impl< TYPE >( INFO ) {} \
128 };
129 
131 
132 // serialize_as_pointer<T>
133 //
134 // Type-trait class that indicates whether a certain type should be serialized
135 // as a pointer or not. There can be multiple pointers to the same object,
136 // only the first such pointer is actually stored, the others are stored as
137 // a reference to this first object.
138 //
139 // By default all pointer types are treated as pointer, but also smart pointer
140 // can be traited as such. Though only unique_ptr<T> is implemented ATM.
141 //
142 // The serialize_as_pointer class has the following members:
143 // - static bool value
144 // True iff this type must be serialized as a pointer.
145 // The fields below are only valid (even only present) if this variable
146 // is true.
147 // - using type = T
148 // The pointed-to type
149 // - T* getPointer(X x)
150 // Get an actual pointer from the abstract pointer x
151 // (X can be a smart pointer type)
152 // - void setPointer(X x, T* p, Archive& ar)
153 // Copy the raw-pointer p to the abstract pointer x
154 // The archive can be used to store per-archive data, this is for example
155 // needed for shared_ptr.
156 
157 template<typename T> struct serialize_as_pointer : std::false_type {};
158 template<typename T> struct serialize_as_pointer_impl : std::true_type
159 {
160  // pointer to primitive types not supported
161  static_assert(!is_primitive<T>::value,
162  "can't serialize ptr to primitive type");
163  using type = T;
164 };
165 template<typename T> struct serialize_as_pointer<T*>
167 {
168  static inline T* getPointer(T* t) { return t; }
169  template<typename Archive>
170  static inline void setPointer(T*& t, T* p, Archive& /*ar*/) {
171  t = p;
172  }
173 };
174 template<typename T> struct serialize_as_pointer<std::unique_ptr<T>>
176 {
177  static inline T* getPointer(const std::unique_ptr<T>& t) { return t.get(); }
178  template<typename Archive>
179  static inline void setPointer(std::unique_ptr<T>& t, T* p, Archive& /*ar*/) {
180  t.reset(p);
181  }
182 };
183 template<typename T> struct serialize_as_pointer<std::shared_ptr<T>>
185 {
186  static T* getPointer(const std::shared_ptr<T>& t) { return t.get(); }
187  template<typename Archive>
188  static void setPointer(std::shared_ptr<T>& t, T* p, Archive& ar) {
189  ar.resetSharedPtr(t, p);
190  }
191 };
192 
194 
195 // serialize_as_collection<T>
196 //
197 // Type-trait class that indicates whether a certain type should be serialized
198 // as a collection or not. The serialization code 'knows' how to serialize
199 // collections, so as a user of the serializer you only need to list the
200 // collection to have it serialized (you don't have to iterate over it
201 // manually).
202 //
203 // By default arrays, std::vector, std::list, std::deque and std::map are
204 // recognized as collections. Though for STL collections you need to add
205 // #include "serialize_stl.hh"
206 //
207 // The serialize_as_collection class has the following members:
208 //
209 // - static bool value
210 // True iff this type must be serialized as a collection.
211 // The fields below are only valid (even only present) if this variable
212 // is true.
213 // - int size
214 // The size of the collection, -1 for variable sized collections.
215 // Fixed sized collections can be serialized slightly more efficient
216 // becuase we don't need to explicitly store the size.
217 // - using value_type = ...
218 // The type stored in the collection (only homogeneous collections are
219 // supported).
220 // - bool loadInPlace
221 // Indicates whether we can directly load the elements in the correct
222 // position in the container, otherwise there will be an extra assignment.
223 // For this to be possible, the output iterator must support a dereference
224 // operator that returns a 'regular' value_type.
225 // - using const_iterator = ...
226 // - const_iterator begin(...)
227 // - const_iterator end(...)
228 // Returns begin/end iterator for the given collection. Used for saving.
229 // - void prepare(..., int n)
230 // - output_iterator output(...)
231 // These are used for loading. The prepare() method should prepare the
232 // collection to receive 'n' elements. The output() method returns an
233 // output_iterator to the beginning of the collection.
234 
235 template<typename T> struct serialize_as_collection : std::false_type {};
236 template<typename T, int N> struct serialize_as_collection<T[N]> : std::true_type
237 {
238  static constexpr int size = N; // fixed size
239  using value_type = T;
240  // save
241  using const_iterator = const T*;
242  static const T* begin(const T (&array)[N]) { return &array[0]; }
243  static const T* end (const T (&array)[N]) { return &array[N]; }
244  // load
245  static constexpr bool loadInPlace = true;
246  static void prepare(T (&/*array*/)[N], int /*n*/) { }
247  static T* output(T (&array)[N]) { return &array[0]; }
248 };
249 
251 
252 // Implementation of the different save-strategies.
253 //
254 // ATM we have
255 // - PrimitiveSaver
256 // Saves primitive values: int, bool, string, ...
257 // Primitive values cannot be versioned.
258 // - EnumSaver
259 // Depending on the archive type, enums are either saved as strings (XML
260 // archive) or as integers (memory archive).
261 // This does not work automatically: it needs a specialization of
262 // serialize_as_enum, see above.
263 // - ClassSaver
264 // From a serialization POV classes are a (heterogeneous) collection of
265 // other to-be-serialized items.
266 // Classes can have a version number, this allows to evolve the class
267 // structure while still being able to load older versions (the load
268 // method receive the version number as parameter, the user still needs
269 // to keep the old loading code in place).
270 // Optionally the name of the (concrete) class is saved in the stream.
271 // This is used to support loading of polymorphic classes.
272 // There is also an (optional) id saved in the stream. This used to
273 // resolve possible multiple pointers to the same class.
274 // - PointerSaver
275 // Saves a pointer to a class (pointers to primitive types are not
276 // supported). See also serialize_as_pointer
277 // - IDSaver
278 // Weaker version of PointerSaver: it can only save pointers to objects
279 // that are already saved before (so it's will be saved by storing a
280 // reference). To only reason to use IDSaver (iso PointerSaver) is that
281 // it will not instantiate the object construction code.
282 // - CollectionSaver
283 // Saves a whole collection. See also serialize_as_collection
284 //
285 // All these strategies have a method:
286 // template<typename Archive> void operator()(Archive& ar, const T& t)
287 // 'ar' is archive where the serialized stream will go
288 // 't' is the to-be-saved object
289 // 'saveId' Should ID be saved
290 
291 template<typename T> struct PrimitiveSaver
292 {
293  template<typename Archive> void operator()(Archive& ar, const T& t,
294  bool /*saveId*/)
295  {
296  static_assert(is_primitive<T>::value, "must be primitive type");
297  ar.save(t);
298  }
299 };
300 template<typename T> struct EnumSaver
301 {
302  template<typename Archive> void operator()(Archive& ar, const T& t,
303  bool /*saveId*/)
304  {
305  if (ar.translateEnumToString()) {
307  std::string str = sae.toString(t);
308  ar.save(str);
309  } else {
310  ar.save(int(t));
311  }
312  }
313 };
314 template<typename T> struct ClassSaver
315 {
316  template<typename Archive> void operator()(
317  Archive& ar, const T& t, bool saveId,
318  const char* type = nullptr, bool saveConstrArgs = false)
319  {
320  // Order is important (for non-xml archives). We use this order:
321  // - id
322  // - type
323  // - version
324  // - constructor args
325  // Rational:
326  // - 'id' must be first: it could be nullptr, in that
327  // case the other fields are not even present.
328  // - 'type' must be before version, because for some types we
329  // might not need to store version (though it's unlikely)
330  // - version must be before constructor args because the
331  // constr args depend on the version
332  if (saveId) {
333  unsigned id = ar.generateId(&t);
334  ar.attribute("id", id);
335  }
336 
337  if (type) {
338  ar.attribute("type", type);
339  }
340 
341  unsigned version = SerializeClassVersion<T>::value;
342  if ((version != 0) && ar.needVersion()) {
343  if (!ar.canHaveOptionalAttributes() ||
344  (version != 1)) {
345  ar.attribute("version", version);
346  }
347  }
348 
349  if (saveConstrArgs) {
350  // save local constructor args (if any)
351  SerializeConstructorArgs<T> constrArgs;
352  constrArgs.save(ar, t);
353  }
354 
355  using TNC = std::remove_const_t<T>;
356  auto& t2 = const_cast<TNC&>(t);
357  serialize(ar, t2, version);
358  }
359 };
360 template<typename TP> struct PointerSaver
361 {
362  // note: we only support pointer to class
363  template<typename Archive> void operator()(Archive& ar, const TP& tp2,
364  bool /*saveId*/)
365  {
366  static_assert(serialize_as_pointer<TP>::value,
367  "must be serialized as pointer");
368  using T = typename serialize_as_pointer<TP>::type;
369  const T* tp = serialize_as_pointer<TP>::getPointer(tp2);
370  if (!tp) {
371  unsigned id = 0;
372  ar.attribute("id_ref", id);
373  return;
374  }
375  if (unsigned id = ar.getId(tp)) {
376  ar.attribute("id_ref", id);
377  } else {
378  if constexpr (std::is_polymorphic_v<T>) {
380  } else {
381  ClassSaver<T> saver;
382  // don't store type
383  // store id, constr-args
384  saver(ar, *tp, true, nullptr, true);
385  }
386  }
387  }
388 };
389 template<typename TP> struct IDSaver
390 {
391  template<typename Archive> void operator()(Archive& ar, const TP& tp2)
392  {
393  static_assert(serialize_as_pointer<TP>::value,
394  "must be serialized as pointer");
396  unsigned id;
397  if (!tp) {
398  id = 0;
399  } else {
400  id = ar.getId(tp);
401  assert(id);
402  }
403  ar.attribute("id_ref", id);
404  }
405 };
406 template<typename TC> struct CollectionSaver
407 {
408  template<typename Archive> void operator()(Archive& ar, const TC& tc,
409  bool saveId)
410  {
411  using sac = serialize_as_collection<TC>;
412  static_assert(sac::value, "must be serialized as collection");
413  auto begin = sac::begin(tc);
414  auto end = sac::end (tc);
415  if ((sac::size < 0) && (!ar.canCountChildren())) {
416  // variable size
417  // e.g. in an XML archive the loader can look-ahead and
418  // count the number of sub-tags, so no need to
419  // explicitly store the size for such archives.
420  int n = int(std::distance(begin, end));
421  ar.serialize("size", n);
422  }
423  for (; begin != end; ++begin) {
424  if (saveId) {
425  ar.serializeWithID("item", *begin);
426  } else {
427  ar.serialize("item", *begin);
428  }
429  }
430  }
431 };
432 
433 // Delegate to a specific Saver class
434 // (implemented as inheriting from a specific baseclass).
435 template<typename T> struct Saver
436  : std::conditional_t<is_primitive<T>::value, PrimitiveSaver<T>,
437  std::conditional_t<serialize_as_enum<T>::value, EnumSaver<T>,
438  std::conditional_t<serialize_as_pointer<T>::value, PointerSaver<T>,
439  std::conditional_t<serialize_as_collection<T>::value, CollectionSaver<T>,
440  ClassSaver<T>>>>> {};
441 
443 
444 // Implementation of the different load-strategies.
445 //
446 // This matches very closely with the save-strategies above.
447 //
448 // All these strategies have a method:
449 // template<typename Archive, typename TUPLE>
450 // void operator()(Archive& ar, const T& t, TUPLE args)
451 // 'ar' Is archive where the serialized stream will go
452 // 't' Is the object that has to be restored.
453 // In case of a class (not a pointer to a class) the actual object
454 // is already constructed, but it still needs to be filled in with
455 // the correct data.
456 // 'args' (Only used by PointerLoader) holds extra parameters used
457 // to construct objects.
458 // 'id' Used to skip loading an ID, see comment in ClassLoader
459 
460 template<typename T> struct PrimitiveLoader
461 {
462  template<typename Archive, typename TUPLE>
463  void operator()(Archive& ar, T& t, TUPLE /*args*/, int /*id*/)
464  {
465  static_assert(std::tuple_size_v<TUPLE> == 0,
466  "can't have constructor arguments");
467  ar.load(t);
468  }
469 };
470 template<typename T> struct EnumLoader
471 {
472  template<typename Archive, typename TUPLE>
473  void operator()(Archive& ar, T& t, TUPLE /*args*/, int /*id*/)
474  {
475  static_assert(std::tuple_size_v<TUPLE> == 0,
476  "can't have constructor arguments");
477  if (ar.translateEnumToString()) {
478  std::string str;
479  ar.load(str);
481  t = sae.fromString(str);
482  } else {
483  int i;
484  ar.load(i);
485  t = T(i);
486  }
487  }
488 };
489 
490 unsigned loadVersionHelper(MemInputArchive& ar, const char* className,
491  unsigned latestVersion);
492 unsigned loadVersionHelper(XmlInputArchive& ar, const char* className,
493  unsigned latestVersion);
494 template<typename T, typename Archive> unsigned loadVersion(Archive& ar)
495 {
496  unsigned latestVersion = SerializeClassVersion<T>::value;
497  if ((latestVersion != 0) && ar.needVersion()) {
498  return loadVersionHelper(ar, typeid(T).name(), latestVersion);
499  } else {
500  return latestVersion;
501  }
502 }
503 template<typename T> struct ClassLoader
504 {
505  template<typename Archive, typename TUPLE>
506  void operator()(Archive& ar, T& t, TUPLE /*args*/, int id = 0,
507  int version = -1)
508  {
509  static_assert(std::tuple_size_v<TUPLE> == 0,
510  "can't have constructor arguments");
511 
512  // id == -1: don't load id, don't addPointer
513  // id == 0: load id from archive, addPointer
514  // id == N: id already loaded, still addPointer
515  if (id != -1) {
516  if (id == 0) {
517  ar.attribute("id", id);
518  }
519  ar.addPointer(id, &t);
520  }
521 
522  // version == -1: load version
523  // version == N: version already loaded
524  if (version == -1) {
525  version = loadVersion<T>(ar);
526  }
527 
528  using TNC = std::remove_const_t<T>;
529  auto& t2 = const_cast<TNC&>(t);
530  serialize(ar, t2, version);
531  }
532 };
533 template<typename T> struct NonPolymorphicPointerLoader
534 {
535  template<typename Archive, typename GlobalTuple>
536  T* operator()(Archive& ar, unsigned id, GlobalTuple globalArgs)
537  {
538  int version = loadVersion<T>(ar);
539 
540  // load (local) constructor args (if any)
541  using TNC = std::remove_const_t<T>;
542  using ConstrArgs = SerializeConstructorArgs<TNC>;
543  ConstrArgs constrArgs;
544  auto localArgs = constrArgs.load(ar, version);
545 
546  // combine global and local constr args
547  auto args = std::tuple_cat(globalArgs, localArgs);
548  // TODO make combining global/local constr args configurable
549 
550  Creator<T> creator;
551  auto tp = creator(args);
552  ClassLoader<T> loader;
553  loader(ar, *tp, std::tuple<>(), id, version);
554  return tp.release();
555  }
556 };
557 template<typename T> struct PolymorphicPointerLoader
558 {
559  template<typename Archive, typename TUPLE>
560  T* operator()(Archive& ar, unsigned id, TUPLE args)
561  {
562  using ArgsType = typename PolymorphicConstructorArgs<T>::type;
563  static_assert(std::is_same_v<TUPLE, ArgsType>,
564  "constructor arguments types must match");
565  return static_cast<T*>(
567  }
568 };
569 template<typename T> struct PointerLoader2
570  // extra indirection needed because inlining the body of
571  // NonPolymorphicPointerLoader in PointerLoader does not compile
572  // for abstract types
573  : std::conditional_t<std::is_polymorphic_v<T>,
574  PolymorphicPointerLoader<T>,
575  NonPolymorphicPointerLoader<T>> {};
576 
577 template<typename TP> struct PointerLoader
578 {
579  template<typename Archive, typename GlobalTuple>
580  void operator()(Archive& ar, TP& tp2, GlobalTuple globalArgs, int /*id*/)
581  {
582  static_assert(serialize_as_pointer<TP>::value,
583  "must be serialized as a pointer");
584  // in XML archives we use 'id_ref' or 'id', in other archives
585  // we don't care about the name
586  unsigned id;
587  if (ar.canHaveOptionalAttributes() &&
588  ar.findAttribute("id_ref", id)) {
589  // nothing, 'id' already filled in
590  } else {
591  ar.attribute("id", id);
592  }
593 
594  using T = typename serialize_as_pointer<TP>::type;
595  T* tp;
596  if (id == 0) {
597  tp = nullptr;
598  } else {
599  if (void* p = ar.getPointer(id)) {
600  tp = static_cast<T*>(p);
601  } else {
602  PointerLoader2<T> loader;
603  tp = loader(ar, id, globalArgs);
604  }
605  }
607  }
608 };
609 void pointerError(unsigned id);
610 template<typename TP> struct IDLoader
611 {
612  template<typename Archive>
613  void operator()(Archive& ar, TP& tp2)
614  {
615  static_assert(serialize_as_pointer<TP>::value,
616  "must be serialized as a pointer");
617  unsigned id;
618  ar.attribute("id_ref", id);
619 
620  using T = typename serialize_as_pointer<TP>::type;
621  T* tp;
622  if (id == 0) {
623  tp = nullptr;
624  } else {
625  void* p = ar.getPointer(id);
626  if (!p) {
627  pointerError(id);
628  }
629  tp = static_cast<T*>(p);
630  }
632  }
633 };
634 
635 template<typename sac, bool IN_PLACE = sac::loadInPlace> struct CollectionLoaderHelper;
636 template<typename sac> struct CollectionLoaderHelper<sac, true>
637 {
638  // used for array and vector
639  template<typename Archive, typename TUPLE, typename OUT_ITER>
640  void operator()(Archive& ar, TUPLE args, OUT_ITER it, int id)
641  {
642  ar.doSerialize("item", *it, args, id);
643  }
644 };
645 template<typename sac> struct CollectionLoaderHelper<sac, false>
646 {
647  // We can't directly load the element in the correct position:
648  // This screws-up id/pointer management because the element is still
649  // copied after construction (and pointer value of initial object is
650  // stored).
651  template<typename Archive, typename TUPLE, typename OUT_ITER>
652  void operator()(Archive& ar, TUPLE args, OUT_ITER it, int id)
653  {
654  typename sac::value_type elem;
655  ar.doSerialize("item", elem, args, id);
656  *it = std::move(elem);
657  }
658 };
659 template<typename TC> struct CollectionLoader
660 {
661  template<typename Archive, typename TUPLE>
662  void operator()(Archive& ar, TC& tc, TUPLE args, int id = 0)
663  {
664  assert(id == one_of(0, -1));
665  using sac = serialize_as_collection<TC>;
666  static_assert(sac::value, "must be serialized as a collection");
667  int n = sac::size;
668  if (n < 0) {
669  // variable size
670  if (ar.canCountChildren()) {
671  n = ar.countChildren();
672  } else {
673  ar.serialize("size", n);
674  }
675  }
676  sac::prepare(tc, n);
677  auto it = sac::output(tc);
678  CollectionLoaderHelper<sac> loadOneElement;
679  for (int i = 0; i < n; ++i, ++it) {
680  loadOneElement(ar, args, it, id);
681  }
682  }
683 };
684 template<typename T> struct Loader
685  : std::conditional_t<is_primitive<T>::value, PrimitiveLoader<T>,
686  std::conditional_t<serialize_as_enum<T>::value, EnumLoader<T>,
687  std::conditional_t<serialize_as_pointer<T>::value, PointerLoader<T>,
688  std::conditional_t<serialize_as_collection<T>::value, CollectionLoader<T>,
689  ClassLoader<T>>>>> {};
690 
691 } // namespace openmsx
692 
693 #endif
openmsx::SerializeClassVersion
Store serialization-version number of a class.
Definition: serialize.hh:36
openmsx::PolymorphicLoaderRegistry::load
static void * load(Archive &ar, unsigned id, const void *args)
Definition: serialize_meta.cc:76
one_of.hh
openmsx::PrimitiveSaver::operator()
void operator()(Archive &ar, const T &t, bool)
Definition: serialize_core.hh:293
openmsx::EnumSaver::operator()
void operator()(Archive &ar, const T &t, bool)
Definition: serialize_core.hh:302
openmsx::pointerError
void pointerError(unsigned id)
Definition: serialize_core.cc:13
openmsx::serialize_as_enum_impl::serialize_as_enum_impl
serialize_as_enum_impl(std::initializer_list< enum_string< T >> info_)
Definition: serialize_core.hh:105
openmsx::ClassSaver::operator()
void operator()(Archive &ar, const T &t, bool saveId, const char *type=nullptr, bool saveConstrArgs=false)
Definition: serialize_core.hh:316
openmsx::IDSaver
Definition: serialize_core.hh:389
openmsx::Saver
Definition: serialize_core.hh:435
openmsx::enum_string::str
const char * str
Definition: serialize_core.hh:100
openmsx::ClassLoader
Definition: serialize_core.hh:503
openmsx::serialize_as_enum_impl
Definition: serialize_core.hh:104
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
serialize_meta.hh
openmsx::serialize_as_pointer< std::shared_ptr< T > >::setPointer
static void setPointer(std::shared_ptr< T > &t, T *p, Archive &ar)
Definition: serialize_core.hh:188
openmsx::PointerLoader2
Definition: serialize_core.hh:569
openmsx::serialize_as_enum
serialize_as_enum<T>
Definition: serialize_core.hh:97
openmsx::serialize_as_enum_impl::toString
std::string toString(T t) const
Definition: serialize_core.hh:107
openmsx::CollectionLoaderHelper< sac, false >::operator()
void operator()(Archive &ar, TUPLE args, OUT_ITER it, int id)
Definition: serialize_core.hh:652
t
TclObject t
Definition: TclObject_test.cc:264
openmsx::serialize_as_collection< T[N]>::end
static const T * end(const T(&array)[N])
Definition: serialize_core.hh:243
openmsx::PrimitiveSaver
Definition: serialize_core.hh:291
openmsx::serialize_as_pointer_impl::type
T type
Definition: serialize_core.hh:163
openmsx::CollectionSaver::operator()
void operator()(Archive &ar, const TC &tc, bool saveId)
Definition: serialize_core.hh:408
openmsx::IDSaver::operator()
void operator()(Archive &ar, const TP &tp2)
Definition: serialize_core.hh:391
openmsx::PrimitiveLoader
Definition: serialize_core.hh:460
openmsx::SerializeClassVersion::value
static constexpr unsigned value
Definition: serialize_meta.hh:421
openmsx::EnumLoader
Definition: serialize_core.hh:470
openmsx::serialize_as_pointer< std::unique_ptr< T > >::getPointer
static T * getPointer(const std::unique_ptr< T > &t)
Definition: serialize_core.hh:177
openmsx::CollectionLoaderHelper
Definition: serialize_core.hh:635
openmsx::serialize_as_pointer< std::shared_ptr< T > >::getPointer
static T * getPointer(const std::shared_ptr< T > &t)
Definition: serialize_core.hh:186
openmsx::serialize_as_enum_impl::fromString
T fromString(const std::string &str) const
Definition: serialize_core.hh:114
openmsx::serialize_as_pointer< std::unique_ptr< T > >::setPointer
static void setPointer(std::unique_ptr< T > &t, T *p, Archive &)
Definition: serialize_core.hh:179
openmsx::PolymorphicPointerLoader::operator()
T * operator()(Archive &ar, unsigned id, TUPLE args)
Definition: serialize_core.hh:560
openmsx::PrimitiveLoader::operator()
void operator()(Archive &ar, T &t, TUPLE, int)
Definition: serialize_core.hh:463
openmsx::CollectionLoaderHelper< sac, true >::operator()
void operator()(Archive &ar, TUPLE args, OUT_ITER it, int id)
Definition: serialize_core.hh:640
openmsx::loadVersion
unsigned loadVersion(Archive &ar)
Definition: serialize_core.hh:494
openmsx::enum_string
Definition: serialize_core.hh:99
openmsx::SerializeConstructorArgs::load
type load(Archive &, unsigned)
Definition: serialize_constr.hh:37
openmsx::enumError
void enumError(const std::string &str)
Definition: serialize_core.cc:8
openmsx::PointerLoader
Definition: serialize_core.hh:577
openmsx::loadVersionHelper
unsigned loadVersionHelper(MemInputArchive &, const char *, unsigned)
Definition: serialize_core.cc:30
one_of
Definition: one_of.hh:7
openmsx::serialize_as_collection< T[N]>::output
static T * output(T(&array)[N])
Definition: serialize_core.hh:247
openmsx::serialize_as_collection< T[N]>::prepare
static void prepare(T(&)[N], int)
Definition: serialize_core.hh:246
openmsx::IDLoader::operator()
void operator()(Archive &ar, TP &tp2)
Definition: serialize_core.hh:613
utf8::distance
auto distance(octet_iterator first, octet_iterator last)
Definition: utf8_checked.hh:194
openmsx::serialize_as_pointer< T * >::setPointer
static void setPointer(T *&t, T *p, Archive &)
Definition: serialize_core.hh:170
openmsx::serialize_as_collection< T[N]>::const_iterator
const T * const_iterator
Definition: serialize_core.hh:241
openmsx::CollectionLoader
Definition: serialize_core.hh:659
openmsx::ClassLoader::operator()
void operator()(Archive &ar, T &t, TUPLE, int id=0, int version=-1)
Definition: serialize_core.hh:506
openmsx::N
constexpr unsigned N
Definition: ResampleHQ.cc:224
openmsx::EnumSaver
Definition: serialize_core.hh:300
openmsx::ClassSaver
Definition: serialize_core.hh:314
openmsx::SerializeConstructorArgs::save
void save(Archive &, const T &)
Definition: serialize_constr.hh:35
openmsx::enum_string::e
T e
Definition: serialize_core.hh:101
openmsx::IDLoader
Definition: serialize_core.hh:610
openmsx::EnumLoader::operator()
void operator()(Archive &ar, T &t, TUPLE, int)
Definition: serialize_core.hh:473
openmsx::PointerSaver
Definition: serialize_core.hh:360
openmsx::CollectionSaver
Definition: serialize_core.hh:406
openmsx::serialize_as_collection< T[N]>::begin
static const T * begin(const T(&array)[N])
Definition: serialize_core.hh:242
openmsx::Creator
Utility to do T* t = new T(...)
Definition: serialize_meta.hh:30
openmsx::serialize_as_pointer_impl
Definition: serialize_core.hh:158
openmsx::NonPolymorphicPointerLoader
Definition: serialize_core.hh:533
openmsx::PointerSaver::operator()
void operator()(Archive &ar, const TP &tp2, bool)
Definition: serialize_core.hh:363
openmsx::serialize_as_collection< T[N]>::value_type
T value_type
Definition: serialize_core.hh:239
openmsx::Loader
Definition: serialize_core.hh:684
openmsx::CollectionLoader::operator()
void operator()(Archive &ar, TC &tc, TUPLE args, int id=0)
Definition: serialize_core.hh:662
openmsx::PolymorphicPointerLoader
Definition: serialize_core.hh:557
openmsx::is_primitive
Definition: serialize_core.hh:16
openmsx::SerializeConstructorArgs
Serialize (local) constructor arguments.
Definition: serialize_constr.hh:31
openmsx::serialize
void serialize(Archive &ar, T &t, unsigned version)
Definition: serialize_core.hh:41
openmsx::NonPolymorphicPointerLoader::operator()
T * operator()(Archive &ar, unsigned id, GlobalTuple globalArgs)
Definition: serialize_core.hh:536
openmsx::serialize_as_pointer
Definition: serialize_core.hh:157
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::PolymorphicSaverRegistry::save
static void save(Archive &ar, T *t)
Definition: serialize_meta.hh:206
openmsx::PointerLoader::operator()
void operator()(Archive &ar, TP &tp2, GlobalTuple globalArgs, int)
Definition: serialize_core.hh:580
openmsx::serialize_as_pointer< T * >::getPointer
static T * getPointer(T *t)
Definition: serialize_core.hh:168
serialize_constr.hh
openmsx::serialize_as_collection
Definition: serialize_core.hh:235
openmsx::PolymorphicConstructorArgs
Store association between polymorphic class (base- or subclass) and the list of constructor arguments...
Definition: serialize_meta.hh:60