openMSX
serialize.hh
Go to the documentation of this file.
1 #ifndef SERIALIZE_HH
2 #define SERIALIZE_HH
3 
4 #include "serialize_core.hh"
5 #include "SerializeBuffer.hh"
6 #include "XMLElement.hh"
7 #include "MemBuffer.hh"
8 #include "StringOp.hh"
9 #include "inline.hh"
10 #include "unreachable.hh"
11 #include <zlib.h>
12 #include <string>
13 #include <typeindex>
14 #include <type_traits>
15 #include <vector>
16 #include <map>
17 #include <sstream>
18 #include <cassert>
19 #include <memory>
20 
21 namespace openmsx {
22 
23 template<typename T> struct SerializeClassVersion;
24 
25 // In this section, the archive classes are defined.
26 //
27 // Archives can be categorized in two ways:
28 // - backing stream they use
29 // - input or output (each backing stream has exactly one input and one
30 // output variant)
31 //
32 // ATM these backing streams implemented:
33 // - Mem
34 // Stores stream in memory. Is meant to be very compact and very fast.
35 // It does not support versioning (it's not possible to load this stream
36 // in a newer version of openMSX). It is also not platform independent
37 // (e.g. integers are stored using native platform endianess).
38 // The main use case for this archive format is regular in memory
39 // snapshots, for example to support replay/rewind.
40 // - XML
41 // Stores the stream in a XML file. These files are meant to be portable
42 // to different architectures (e.g. little/big endian, 32/64 bit system).
43 // There is version information in the stream, so it should be possible
44 // to load streams created with older openMSX versions a newer openMSX.
45 // The XML files are meant to be human readable. Having editable XML files
46 // is not a design goal (e.g. simply changing a value will probably work,
47 // but swapping the position of two tag or adding or removing tags can
48 // easily break the stream).
49 // - Text
50 // This stores to stream in a flat ascii file (one item per line). This
51 // format is only written as a proof-of-concept to test the design. It's
52 // not meant to be used in practice.
53 //
54 // Archive code is heavily templatized. It uses the CRTP (curiously recuring
55 // template pattern ; a base class templatized on it's derived class). To
56 // implement static polymorphism. This means there is practically no run-time
57 // overhead of using this mechansim compared to 6 seperatly handcoded functions
58 // (Mem/XML/Text x input/output).
59 // TODO At least in theory, still need to verify this in practice.
60 // Though my experience is that gcc is generally very good in this.
61 
62 template<typename Derived> class ArchiveBase
63 {
64 public:
73  template<typename Base, typename T>
74  void serializeBase(T& t)
75  {
76  const char* tag = BaseClassName<Base>::getName();
77  self().serialize(tag, static_cast<Base&>(t));
78  }
79 
96  template<typename Base, typename T>
97  void serializeInlinedBase(T& t, unsigned version)
98  {
99  ::openmsx::serialize(self(), static_cast<Base&>(t), version);
100  }
101 
102  // Each concrete archive class also has the following methods:
103  // Because of the implementation with static polymorphism, this
104  // interface is not explictly visible in the base class.
105  //
106  //
107  // template<typename T> void serializeWithID(const char* tag, const T& t, ...)
108  //
109  // This is _the_most_important_ method of the serialization
110  // framework. Depending on the concrete archive type (loader/saver)
111  // this method will load or save the given type 't'. In case of an XML
112  // archive the 'tag' parameter will be used as tagname.
113  //
114  // At the end there are still a number of optional parameters (in the
115  // current implementation there can be between 0 and 3, but can be
116  // extened when needed). These are 'global' constructor parameters,
117  // constructor parameters that are not stored in the stream, but that
118  // are needed to reconstruct the object (for example can be references
119  // to structures that were already stored in the stream). So these
120  // parameters are only actually used while loading.
121  // TODO document this in more detail in some section where the
122  // (polymorphic) constructors are also described.
123  //
124  //
125  // void serialize_blob(const char* tag, const void* data, size_t len)
126  //
127  // Serialize the given data as a binary blob.
128  // This cannot be part of the serialize() method above because we
129  // cannot know whether a byte-array should be serialized as a blob
130  // or as a collection of bytes (IOW we cannot decide it based on the
131  // type).
132  //
133  //
134  // template<typename T> void serialize(const char* tag, const T& t)
135  //
136  // This is much like the serializeWithID() method above, but it doesn't
137  // store an ID with this element. This means that it's not possible,
138  // later on in the stream, to refer to this element. For many elements
139  // you know this will not happen. This method results in a slightly
140  // more compact stream.
141  //
142  // Note that for primitive types we already don't store an ID, because
143  // pointers to primitive types are not supported (at least not ATM).
144  //
145  //
146  // template<typename T> void serializePointerID(const char* tag, const T& t)
147  //
148  // Serialize a pointer by storing the ID of the object it points to.
149  // This only works if the object was already serialized. The only
150  // reason to use this method instead of the more general serialize()
151  // method is that this one does not instantiate the object
152  // construction code. (So in some cases you can avoid having to
153  // provide specializations of SerializeConstructorArgs.)
154  //
155  //
156  // template<typename T> void serializePolymorphic(const char* tag, const T& t)
157  //
158  // Serialize a value-type whose concrete type is not yet known at
159  // compile-time (polymorphic pointers are already handled by the
160  // generic serialize() method).
161  //
162  // The difference between pointer and value-types is that for
163  // pointers, the de-serialize code also needs to construct the
164  // object, while for value-types, the object (with the correct
165  // concrete type) is already constructed, it only needs to be
166  // initialized.
167  //
168  //
169  // bool versionAtLeast(unsigned actual, unsigned required) const
170  // bool versionBelow (unsigned actual, unsigned required) const
171  //
172  // Checks whether the actual version is respective 'bigger or equal'
173  // or 'strictly lower' than the required version. So in fact these are
174  // equivalent to respectively:
175  // return actual >= required;
176  // return actual < required;
177  // Note that these two methods are the exact opposite of each other.
178  // Though for memory-archives and output-archives we know that the
179  // actual version is always equal to the latest class version and the
180  // required version can never be bigger than this latest version, so
181  // in these cases the methods can be optimized to respectively:
182  // return true;
183  // return false;
184  // By using these methods instead of direct comparisons, the compiler
185  // is able to perform more dead-code-elimination.
186 
187 /*internal*/
188  // These must be public for technical reasons, but they should only
189  // be used by the serialization framework.
190 
192  bool needVersion() const { return true; }
193 
197  bool translateEnumToString() const { return false; }
198 
205  template<typename T> void attribute(const char* name, T& t)
206  {
207  self().serialize(name, t);
208  }
209  void attribute(const char* name, const char* value);
210 
216  bool canHaveOptionalAttributes() const { return false; }
217 
222  bool hasAttribute(const char* /*name*/)
223  {
224  UNREACHABLE; return false;
225  }
226 
230  bool findAttribute(const char* /*name*/, unsigned& /*value*/)
231  {
232  UNREACHABLE; return false;
233  }
234 
243  bool canCountChildren() const { return false; }
244 
249  int countChildren() const
250  {
251  UNREACHABLE; return 0;
252  }
253 
262  void beginTag(const char* /*tag*/)
263  {
264  // nothing
265  }
272  void endTag(const char* /*tag*/)
273  {
274  // nothing
275  }
276 
277  // These (internal) methods should be implemented in the concrete
278  // archive classes.
279  //
280  // template<typename T> void save(const T& t)
281  //
282  // Should only be implemented for OuputArchives. Is called to
283  // store primitive types in the stream. In the end all structures
284  // are broken down to primitive types, so all data that ends up
285  // in the stream passes via this method (ok, depending on how
286  // attribute() and serialize_blob() is implemented, that data may
287  // not pass via save()).
288  //
289  // Often this method will be overloaded to handle certain types in a
290  // specific way.
291  //
292  //
293  // template<typename T> void load(T& t)
294  //
295  // Should only be implemented for InputArchives. This is similar (but
296  // opposite) to the save() method above. Loading of primitive types
297  // is done via this method.
298 
299  // void beginSection()
300  // void endSection()
301  // void skipSection(bool skip)
302  // The methods beginSection() and endSection() can only be used in
303  // output archives. These mark the location of a section that can
304  // later be skipped during loading.
305  // The method skipSection() can only be used in input archives. It
306  // optionally skips a section that was marked during saving.
307  // For every beginSection() call in the output, there must be a
308  // corresponding skipSection() call in the input (even if you don't
309  // actually want to skip the section).
310 
311 protected:
315  inline Derived& self()
316  {
317  return static_cast<Derived&>(*this);
318  }
319 };
320 
321 // The part of OutputArchiveBase that doesn't depend on the template parameter
323 {
324 public:
325  inline bool isLoader() const { return false; }
326  inline bool versionAtLeast(unsigned /*actual*/, unsigned /*required*/) const
327  {
328  return true;
329  }
330  inline bool versionBelow(unsigned /*actual*/, unsigned /*required*/) const
331  {
332  return false;
333  }
334 
335  void skipSection(bool /*skip*/)
336  {
337  UNREACHABLE;
338  }
339 
340 /*internal*/
341  #ifdef linux
342  // This routine is not portable, for example it breaks in
343  // windows (mingw) because there the location of the stack
344  // is _below_ the heap.
345  // But this is anyway only used to check assertions. So for now
346  // only do that in linux.
347  static NEVER_INLINE bool addressOnStack(const void* p)
348  {
349  // This is not portable, it assumes:
350  // - stack grows downwards
351  // - heap is at lower address than stack
352  // Also in c++ comparison between pointers is only defined when
353  // the two pointers point to objects in the same array.
354  int dummy;
355  return &dummy < p;
356  }
357  #endif
358 
359  // Generate a new ID for the given pointer and store this association
360  // for later (see getId()).
361  template<typename T> unsigned generateId(const T* p)
362  {
363  // For composed structures, for example
364  // struct A { ... };
365  // struct B { A a; ... };
366  // The pointer to the outer and inner structure can be the
367  // same while we still want a different ID to refer to these
368  // two. That's why we use a std::pair<void*, type_index> as key
369  // in the map.
370  // For polymorphic types you do sometimes use a base pointer
371  // to refer to a subtype. So there we only use the pointer
372  // value as key in the map.
373  if (std::is_polymorphic<T>::value) {
374  return generateID1(p);
375  } else {
376  return generateID2(p, typeid(T));
377  }
378  }
379 
380  template<typename T> unsigned getId(const T* p)
381  {
382  if (std::is_polymorphic<T>::value) {
383  return getID1(p);
384  } else {
385  return getID2(p, typeid(T));
386  }
387  }
388 
389 protected:
391 
392 private:
393  unsigned generateID1(const void* p);
394  unsigned generateID2(const void* p, const std::type_info& typeInfo);
395  unsigned getID1(const void* p);
396  unsigned getID2(const void* p, const std::type_info& typeInfo);
397 
398  std::map<std::pair<const void*, std::type_index>, unsigned> idMap;
399  std::map<const void*, unsigned> polyIdMap;
400  unsigned lastId;
401 };
402 
403 template<typename Derived>
404 class OutputArchiveBase : public ArchiveBase<Derived>, public OutputArchiveBase2
405 {
406 public:
407  template<typename Base, typename T>
408  void serializeInlinedBase(T& t, unsigned version)
409  {
410  // same implementation as base class, but with extra check
411  static_assert(SerializeClassVersion<Base>::value ==
413  "base and derived must have same version when "
414  "using serializeInlinedBase()");
415  ArchiveBase<Derived>::template serializeInlinedBase<Base>(t, version);
416  }
417  // Main saver method. Heavy lifting is done in the Saver class.
418  // The 'global constructor arguments' parameters are ignored because
419  // the saver archives also completely ignore those extra parameters.
420  // But we need to provide them because the same (templatized) code path
421  // is used both for saving and loading.
422  template<typename T, typename... Args>
423  void serializeWithID(const char* tag, const T& t, Args... /*globalConstrArgs*/)
424  {
425  this->self().beginTag(tag);
426  Saver<T> saver;
427  saver(this->self(), t, true);
428  this->self().endTag(tag);
429  }
430 
431  // Default implementation is to base64-encode the blob and serialize
432  // the resulting string. But memory archives will memcpy the blob.
433  void serialize_blob(const char* tag, const void* data, size_t len);
434 
435  template<typename T> void serialize(const char* tag, const T& t)
436  {
437  this->self().beginTag(tag);
438  Saver<T> saver;
439  saver(this->self(), t, false);
440  this->self().endTag(tag);
441  }
442  template<typename T> void serializePointerID(const char* tag, const T& t)
443  {
444  this->self().beginTag(tag);
445  IDSaver<T> saver;
446  saver(this->self(), t);
447  this->self().endTag(tag);
448  }
449  template<typename T> void serializePolymorphic(const char* tag, const T& t)
450  {
451  static_assert(std::is_polymorphic<T>::value,
452  "must be a polymorphic type");
453  PolymorphicSaverRegistry<Derived>::save(tag, this->self(), t);
454  }
455 
456  // You shouldn't use this, it only exists for backwards compatibility
457  void serializeChar(const char* tag, char c)
458  {
459  this->self().beginTag(tag);
460  this->self().saveChar(c);
461  this->self().endTag(tag);
462  }
463 
464 protected:
466 };
467 
468 
469 // Part of InputArchiveBase that doesn't depend on the template parameter
471 {
472 public:
473  inline bool isLoader() const { return true; }
474 
476  {
477  UNREACHABLE;
478  }
479  void endSection()
480  {
481  UNREACHABLE;
482  }
483 
484 /*internal*/
485  void* getPointer(unsigned id);
486  void addPointer(unsigned id, const void* p);
487 
488  template<typename T> void resetSharedPtr(std::shared_ptr<T>& s, T* r)
489  {
490  if (!r) {
491  s.reset();
492  return;
493  }
494  auto it = sharedPtrMap.find(r);
495  if (it == end(sharedPtrMap)) {
496  s.reset(r);
497  sharedPtrMap[r] = s;
498  } else {
499  s = std::static_pointer_cast<T>(it->second);
500  }
501  }
502 
503 protected:
505 
506 private:
507  std::map<unsigned, void*> idMap;
508  std::map<void*, std::shared_ptr<void>> sharedPtrMap;
509 };
510 
511 template<typename Derived>
512 class InputArchiveBase : public ArchiveBase<Derived>, public InputArchiveBase2
513 {
514 public:
515  template<typename T, typename... Args>
516  void serializeWithID(const char* tag, T& t, Args... args)
517  {
518  doSerialize(tag, t, std::tuple<Args...>(args...));
519  }
520  void serialize_blob(const char* tag, void* data, size_t len);
521 
522  template<typename T>
523  void serialize(const char* tag, T& t)
524  {
525  this->self().beginTag(tag);
526  typedef typename std::remove_const<T>::type TNC;
527  auto& tnc = const_cast<TNC&>(t);
528  Loader<TNC> loader;
529  loader(this->self(), tnc, std::make_tuple(), -1); // don't load id
530  this->self().endTag(tag);
531  }
532  template<typename T> void serializePointerID(const char* tag, const T& t)
533  {
534  this->self().beginTag(tag);
535  typedef typename std::remove_const<T>::type TNC;
536  auto& tnc = const_cast<TNC&>(t);
537  IDLoader<TNC> loader;
538  loader(this->self(), tnc);
539  this->self().endTag(tag);
540  }
541  template<typename T> void serializePolymorphic(const char* tag, T& t)
542  {
543  static_assert(std::is_polymorphic<T>::value,
544  "must be a polymorphic type");
545  PolymorphicInitializerRegistry<Derived>::init(tag, this->self(), &t);
546  }
547 
548  // You shouldn't use this, it only exists for backwards compatibility
549  void serializeChar(const char* tag, char& c)
550  {
551  this->self().beginTag(tag);
552  this->self().loadChar(c);
553  this->self().endTag(tag);
554  }
555 
556 /*internal*/
557  // Actual loader method. Heavy lifting is done in the Loader class.
558  template<typename T, typename TUPLE>
559  void doSerialize(const char* tag, T& t, TUPLE args, int id = 0)
560  {
561  this->self().beginTag(tag);
562  typedef typename std::remove_const<T>::type TNC;
563  auto& tnc = const_cast<TNC&>(t);
564  Loader<TNC> loader;
565  loader(this->self(), tnc, args, id);
566  this->self().endTag(tag);
567  }
568 
569 protected:
571 };
572 
573 
574 class MemOutputArchive : public OutputArchiveBase<MemOutputArchive>
575 {
576 public:
578  {
579  }
580 
582  {
583  assert(openSections.empty());
584  }
585 
586  bool needVersion() const { return false; }
587 
588  template <typename T> void save(const T& t)
589  {
590  put(&t, sizeof(t));
591  }
592  inline void saveChar(char c)
593  {
594  save(c);
595  }
596  void save(const std::string& s);
597  void serialize_blob(const char*, const void* data, size_t len);
598 
600  {
601  size_t skip = 0; // filled in later
602  save(skip);
603  size_t beginPos = buffer.getPosition();
604  openSections.push_back(beginPos);
605  }
606  void endSection()
607  {
608  assert(!openSections.empty());
609  size_t endPos = buffer.getPosition();
610  size_t beginPos = openSections.back();
611  openSections.pop_back();
612  size_t skip = endPos - beginPos;
613  buffer.insertAt(beginPos - sizeof(skip),
614  &skip, sizeof(skip));
615  }
616 
618 
619 private:
620  void put(const void* data, size_t len)
621  {
622  if (len) {
623  buffer.insert(data, len);
624  }
625  }
626 
627  OutputBuffer buffer;
628  std::vector<size_t> openSections;
629 };
630 
631 class MemInputArchive : public InputArchiveBase<MemInputArchive>
632 {
633 public:
634  MemInputArchive(const byte* data, size_t size)
635  : buffer(data, size)
636  {
637  }
638 
639  bool needVersion() const { return false; }
640  inline bool versionAtLeast(unsigned /*actual*/, unsigned /*required*/) const
641  {
642  return true;
643  }
644  inline bool versionBelow(unsigned /*actual*/, unsigned /*required*/) const
645  {
646  return false;
647  }
648 
649  template<typename T> void load(T& t)
650  {
651  get(&t, sizeof(t));
652  }
653  inline void loadChar(char& c)
654  {
655  load(c);
656  }
657  void load(std::string& s);
658  void serialize_blob(const char*, void* data, size_t len);
659 
660  void skipSection(bool skip)
661  {
662  size_t num;
663  load(num);
664  if (skip) {
665  buffer.skip(num);
666  }
667  }
668 
669 private:
670  void get(void* data, size_t len)
671  {
672  if (len) {
673  buffer.read(data, len);
674  }
675  }
676 
677  InputBuffer buffer;
678 };
679 
681 
682 class XmlOutputArchive : public OutputArchiveBase<XmlOutputArchive>
683 {
684 public:
685  XmlOutputArchive(const std::string& filename);
687 
688  template <typename T> void saveImpl(const T& t)
689  {
690  // TODO make sure floating point is printed with enough digits
691  // maybe print as hex?
693  }
694  template <typename T> void save(const T& t)
695  {
696  saveImpl(t);
697  }
698  void saveChar(char c);
699  void save(const std::string& str);
700  void save(bool b);
701  void save(unsigned char b);
702  void save(signed char c);
703  void save(char c);
704  void save(int i); // these 3 are not strictly needed
705  void save(unsigned u); // but having them non-inline
706  void save(unsigned long long ull); // saves quite a bit of code
707 
708  void beginSection() { /*nothing*/ }
709  void endSection() { /*nothing*/ }
710 
711 //internal:
712  inline bool translateEnumToString() const { return true; }
713  inline bool canHaveOptionalAttributes() const { return true; }
714  inline bool canCountChildren() const { return true; }
715 
716  void beginTag(const char* tag);
717  void endTag(const char* tag);
718 
719  template<typename T> void attributeImpl(const char* name, const T& t)
720  {
721  attribute(name, StringOp::toString(t));
722  }
723  template<typename T> void attribute(const char* name, const T& t)
724  {
725  attributeImpl(name, t);
726  }
727  void attribute(const char* name, const std::string& str);
728  void attribute(const char* name, int i);
729  void attribute(const char* name, unsigned u);
730 
731 private:
732  gzFile file;
733  XMLElement root;
734  std::vector<XMLElement*> current;
735 };
736 
737 class XmlInputArchive : public InputArchiveBase<XmlInputArchive>
738 {
739 public:
740  XmlInputArchive(const std::string& filename);
741 
742  inline bool versionAtLeast(unsigned actual, unsigned required) const
743  {
744  return actual >= required;
745  }
746  inline bool versionBelow(unsigned actual, unsigned required) const
747  {
748  return actual < required;
749  }
750 
751  template<typename T> void load(T& t)
752  {
753  std::string str;
754  load(str);
755  std::istringstream is(str);
756  is >> t;
757  }
758  void loadChar(char& c);
759  void load(std::string& t);
760  void load(bool& b);
761  void load(unsigned char& b);
762  void load(signed char& c);
763  void load(char& c);
764  void load(int& i); // these 3 are not strictly needed
765  void load(unsigned& u); // but having them non-inline
766  void load(unsigned long long& ull); // saves quite a bit of code
767 
768  void skipSection(bool /*skip*/) { /*nothing*/ }
769 
770 //internal:
771  inline bool translateEnumToString() const { return true; }
772  inline bool canHaveOptionalAttributes() const { return true; }
773  inline bool canCountChildren() const { return true; }
774 
775  void beginTag(const char* tag);
776  void endTag(const char* tag);
777 
778  template<typename T> void attributeImpl(const char* name, T& t)
779  {
780  std::string str;
781  attribute(name, str);
782  std::istringstream is(str);
783  is >> t;
784  }
785  template<typename T> void attribute(const char* name, T& t)
786  {
787  attributeImpl(name, t);
788  }
789  void attribute(const char* name, std::string& t);
790  void attribute(const char* name, int& i);
791  void attribute(const char* name, unsigned& u);
792 
793  bool hasAttribute(const char* name);
794  bool findAttribute(const char* name, unsigned& value);
795  int countChildren() const;
796 
797 private:
798  XMLElement elem;
799  std::vector<std::pair<const XMLElement*, size_t>> elems;
800 };
801 
802 #define INSTANTIATE_SERIALIZE_METHODS(CLASS) \
803 template void CLASS::serialize(MemInputArchive&, unsigned); \
804 template void CLASS::serialize(MemOutputArchive&, unsigned); \
805 template void CLASS::serialize(XmlInputArchive&, unsigned); \
806 template void CLASS::serialize(XmlOutputArchive&, unsigned);
807 
808 } // namespace openmsx
809 
810 #endif
void serializeInlinedBase(T &t, unsigned version)
Serialize the base class of this classtype.
Definition: serialize.hh:97
unsigned getId(const T *p)
Definition: serialize.hh:380
void attribute(const char *name, T &t)
Definition: serialize.hh:785
bool needVersion() const
Does this archive store version information.
Definition: serialize.hh:192
void beginTag(const char *)
Indicate begin of a tag.
Definition: serialize.hh:262
bool canHaveOptionalAttributes() const
Some archives (like XML archives) can store optional attributes.
Definition: serialize.hh:216
void insertAt(size_t pos, const void *data, size_t len)
Insert data at a given position.
bool versionAtLeast(unsigned, unsigned) const
Definition: serialize.hh:326
bool findAttribute(const char *name, unsigned &value)
Definition: serialize.cc:521
void serialize_blob(const char *tag, void *data, size_t len)
Definition: serialize.cc:126
string_ref::const_iterator end(const string_ref &x)
Definition: string_ref.hh:135
void serializeWithID(const char *tag, const T &t, Args...)
Definition: serialize.hh:423
bool needVersion() const
Definition: serialize.hh:586
void serialize(const char *tag, T &t)
Definition: serialize.hh:523
#define NEVER_INLINE
Definition: inline.hh:17
bool canCountChildren() const
Definition: serialize.hh:773
void serializePointerID(const char *tag, const T &t)
Definition: serialize.hh:532
void loadChar(char &c)
Definition: serialize.cc:355
XmlInputArchive(const std::string &filename)
Definition: serialize.cc:349
void serializeInlinedBase(T &t, unsigned version)
Definition: serialize.hh:408
void * getPointer(unsigned id)
Definition: serialize.cc:113
void save(const T &t)
Definition: serialize.hh:588
string toString(long long a)
Definition: StringOp.cc:155
void resetSharedPtr(std::shared_ptr< T > &s, T *r)
Definition: serialize.hh:488
unsigned char byte
8 bit unsigned integer
Definition: openmsx.hh:33
void doSerialize(const char *tag, T &t, TUPLE args, int id=0)
Definition: serialize.hh:559
void read(void *result, size_t len)
Read the given number of bytes.
bool versionAtLeast(unsigned actual, unsigned required) const
Definition: serialize.hh:742
void skipSection(bool skip)
Definition: serialize.hh:660
bool needVersion() const
Definition: serialize.hh:639
bool translateEnumToString() const
Does this archive store enums as strings.
Definition: serialize.hh:197
void insert(const void *data, size_t len)
Insert data at the end of this buffer.
void serializePointerID(const char *tag, const T &t)
Definition: serialize.hh:442
void loadChar(char &c)
Definition: serialize.hh:653
void endTag(const char *tag)
Definition: serialize.cc:489
void serialize_blob(const char *, void *data, size_t len)
Definition: serialize.cc:233
void serializePolymorphic(const char *tag, T &t)
Definition: serialize.hh:541
void addPointer(unsigned id, const void *p)
Definition: serialize.cc:119
bool canHaveOptionalAttributes() const
Definition: serialize.hh:713
bool hasAttribute(const char *name)
Definition: serialize.cc:517
void attribute(const char *name, const T &t)
Definition: serialize.hh:723
void serializeWithID(const char *tag, T &t, Args...args)
Definition: serialize.hh:516
void attributeImpl(const char *name, const T &t)
Definition: serialize.hh:719
void endTag(const char *tag)
Definition: serialize.cc:340
void attribute(const char *name, T &t)
Load/store an attribute from/in the archive.
Definition: serialize.hh:205
void serializeBase(T &t)
Is this archive a loader or a saver.
Definition: serialize.hh:74
void serialize_blob(const char *, const void *data, size_t len)
Definition: serialize.cc:204
void save(const T &t)
Definition: serialize.hh:694
bool findAttribute(const char *, unsigned &)
Optimization: combination of hasAttribute() and getAttribute().
Definition: serialize.hh:230
bool versionBelow(unsigned actual, unsigned required) const
Definition: serialize.hh:746
bool versionBelow(unsigned, unsigned) const
Definition: serialize.hh:330
bool translateEnumToString() const
Definition: serialize.hh:771
bool canCountChildren() const
Definition: serialize.hh:714
unsigned generateId(const T *p)
Definition: serialize.hh:361
bool versionBelow(unsigned, unsigned) const
Definition: serialize.hh:644
MemInputArchive(const byte *data, size_t size)
Definition: serialize.hh:634
MemBuffer< byte > releaseBuffer()
Definition: serialize.cc:177
bool translateEnumToString() const
Definition: serialize.hh:712
void beginTag(const char *tag)
Definition: serialize.cc:474
int countChildren() const
Definition: serialize.cc:525
uint8_t * data()
bool canCountChildren() const
Some archives (like XML archives) can count the number of subtags that belong to the current tag...
Definition: serialize.hh:243
size_t size() const
void serializePolymorphic(const char *tag, const T &t)
Definition: serialize.hh:449
void saveImpl(const T &t)
Definition: serialize.hh:688
XmlOutputArchive(const std::string &filename)
Definition: serialize.cc:248
const string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:363
Store serialization-version number of a class.
Definition: serialize.hh:23
void beginTag(const char *tag)
Definition: serialize.cc:334
void endTag(const char *)
Indicate begin of a tag.
Definition: serialize.hh:272
void serializeChar(const char *tag, char &c)
Definition: serialize.hh:549
void serialize_blob(const char *tag, const void *data, size_t len)
Definition: serialize.cc:76
bool hasAttribute(const char *)
Check the presence of a (optional) attribute.
Definition: serialize.hh:222
bool versionAtLeast(unsigned, unsigned) const
Definition: serialize.hh:640
void serialize(const char *tag, const T &t)
Definition: serialize.hh:435
void serializeChar(const char *tag, char c)
Definition: serialize.hh:457
int countChildren() const
Count the number of child tags.
Definition: serialize.hh:249
void serialize(Archive &ar, T &t, unsigned version)
static void init(const char *tag, Archive &ar, void *t)
void skip(size_t len)
Skip the given number of bytes.
void attributeImpl(const char *name, T &t)
Definition: serialize.hh:778
size_t getPosition() const
Get the current size of the buffer.
#define UNREACHABLE
Definition: unreachable.hh:56
static void save(Archive &ar, T *t)
bool canHaveOptionalAttributes() const
Definition: serialize.hh:772