/[svn]/libgig/trunk/src/Serialization.h
ViewVC logotype

Diff of /libgig/trunk/src/Serialization.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3168 by schoenebeck, Tue May 9 19:12:32 2017 UTC revision 3185 by schoenebeck, Wed May 17 15:42:58 2017 UTC
# Line 35  Line 35 
35  #include <vector>  #include <vector>
36  #include <map>  #include <map>
37  #include <time.h>  #include <time.h>
38  #if __cplusplus < 201103L  
39    #ifndef __has_extension
40    # define __has_extension(x) 0
41    #endif
42    
43    #ifndef HAS_BUILTIN_TYPE_TRAITS
44    # if __cplusplus >= 201103L
45    #  define HAS_BUILTIN_TYPE_TRAITS 1
46    # elif ( __has_extension(is_class) && __has_extension(is_enum) )
47    #  define HAS_BUILTIN_TYPE_TRAITS 1
48    # elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
49    #  define HAS_BUILTIN_TYPE_TRAITS 1
50    # elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
51    #  define HAS_BUILTIN_TYPE_TRAITS 1
52    # elif __INTEL_COMPILER >= 1100
53    #  define HAS_BUILTIN_TYPE_TRAITS 1
54    # else
55    #  define HAS_BUILTIN_TYPE_TRAITS 0
56    # endif
57    #endif
58    
59    #if !HAS_BUILTIN_TYPE_TRAITS
60  # include <tr1/type_traits>  # include <tr1/type_traits>
61  # define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class  # define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
62  #else  #else
# Line 97  namespace Serialization { Line 118  namespace Serialization {
118    
119      typedef std::string String;      typedef std::string String;
120    
121        /** @brief Raw data stream of serialized C++ objects.
122         *
123         * This data type is used for the data stream as a result of serializing
124         * your C++ objects with Archive::serialize(), and for native raw data
125         * representation of individual serialized C/C++ objects, members and variables.
126         *
127         * @see Archive::rawData(), Object::rawData()
128         */
129      typedef std::vector<uint8_t> RawData;      typedef std::vector<uint8_t> RawData;
130    
131        /** @brief Abstract identifier for serialized C++ objects.
132         *
133         * This data type is used for identifying serialized C++ objects and members
134         * of your C++ objects. It is important to know that such an ID might not
135         * necessarily be unique. For example the ID of one C++ object might often
136         * be identical to the ID of the first member of that particular C++ object.
137         * That's why there is additionally the concept of an UID in this framework.
138         *
139         * @see UID
140         */
141      typedef void* ID;      typedef void* ID;
142    
143        /** @brief Version number data type.
144         *
145         * This data type is used for maintaining version number information of
146         * your C++ class implementations.
147         *
148         * @see Archive::setVersion() and Archive::setMinVersion()
149         */
150      typedef uint32_t Version;      typedef uint32_t Version;
151    
152      enum operation_t {      /** @brief To which time zone a certain timing information relates to.
153          OPERATION_NONE,       *
154          OPERATION_SERIALIZE,       * The constants in this enum type are used to define to which precise time
155          OPERATION_DESERIALIZE       * zone a time stamp relates to.
156      };       */
   
157      enum time_base_t {      enum time_base_t {
158          LOCAL_TIME,          LOCAL_TIME, ///< The time stamp relates to the machine's local time zone. Request a time stamp in local time if you want to present that time stamp to the end user.
159          UTC_TIME          UTC_TIME ///< The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time". Request time stamp with UTC if you want to compare that time stamp with other time stamps.
160      };      };
161    
162        /** @brief Check whether data is a C/C++ @c enum type.
163         *
164         * Returns true if the supplied C++ variable or object is of a C/C++ @c enum
165         * type.
166         *
167         * @param data - the variable or object whose data type shall be checked
168         */
169      template<typename T>      template<typename T>
170      bool IsEnum(const T& data) {      bool IsEnum(const T& data) {
171          #if __cplusplus < 201103L          #if !HAS_BUILTIN_TYPE_TRAITS
172          return std::tr1::is_enum<T>::value;          return std::tr1::is_enum<T>::value;
173          #else          #else
174          return __is_enum(T);          return __is_enum(T);
175          #endif          #endif
176      }      }
177    
178        /** @brief Check whether data is a C++ @c union type.
179         *
180         * Returns true if the supplied C++ variable or object is of a C/C++ @c union
181         * type. Note that the result of this function is only reliable if the C++
182         * compiler you are using has support for built-in type traits. If your C++
183         * compiler does not have built-in type traits support, then this function
184         * will simply return @c false on all your calls.
185         *
186         * @param data - the variable or object whose data type shall be checked
187         */
188      template<typename T>      template<typename T>
189      bool IsUnion(const T& data) {      bool IsUnion(const T& data) {
190          #if __cplusplus < 201103L          #if !HAS_BUILTIN_TYPE_TRAITS
191          return false; // without compiler support we cannot distinguish union from class          return false; // without compiler support we cannot distinguish union from class
192          #else          #else
193          return __is_union(T);          return __is_union(T);
194          #endif          #endif
195      }      }
196    
197        /** @brief Check whether data is a C/C++ @c struct or C++ @c class type.
198         *
199         * Returns true if the supplied C++ variable or object is of C/C++ @c struct
200         * or C++ @c class type. Note that if you are using a C++ compiler which
201         * does have built-in type traits support, then this function will also
202         * return @c true on C/C++ @c union types.
203         *
204         * @param data - the variable or object whose data type shall be checked
205         */
206      template<typename T>      template<typename T>
207      bool IsClass(const T& data) {      bool IsClass(const T& data) {
208          #if __cplusplus < 201103L          #if !HAS_BUILTIN_TYPE_TRAITS
209          return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class          return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
210          #else          #else
211          return __is_class(T);          return __is_class(T);
# Line 151  namespace Serialization { Line 222  namespace Serialization {
222          return __is_pod(T);          return __is_pod(T);
223      }*/      }*/
224    
225      /** @brief Unique identifier for one specific C++ object, member or fundamental variable.      /** @brief Unique identifier referring to one specific native C++ object, member, fundamental variable, or any other native C++ data.
226         *
227         * Reflects a unique identifier for one specific serialized C++ data, i.e.
228         * C++ class instance, C/C++ struct instance, member, primitive pointer,
229         * fundamental variables, or any other native C/C++ data originally being
230         * serialized.
231       *       *
232       * Reflects a unique identifier for one specific serialized C++ class       * A unique identifier is composed of an id (an identifier which is not
233       * instance, struct instance, member, primitive pointer, or fundamental       * necessarily unique) and a size. Since the underlying ID is derived from
234       * variables.       * the original C++ object's memory location, such an ID is not sufficient
235         * to distinguish a particular C++ object from the first member of that C++
236         * object, since both typically share the same memory address. So
237         * additionally the memory size of the respective object or member is
238         * bundled with UID objects to make them unique and distinguishable.
239       */       */
240      class UID {      class UID {
241      public:      public:
242          ID id;          ID id; ///< Abstract non-unique ID of the object or member in question.
243          size_t size;          size_t size; ///< Memory size of the object or member in question.
244    
245          bool isValid() const;          bool isValid() const;
246          operator bool() const { return isValid(); }          operator bool() const { return isValid(); } ///< Same as calling isValid().
247          //bool operator()() const { return isValid(); }          //bool operator()() const { return isValid(); }
248          bool operator==(const UID& other) const { return id == other.id && size == other.size; }          bool operator==(const UID& other) const { return id == other.id && size == other.size; }
249          bool operator!=(const UID& other) const { return id != other.id || size != other.size; }          bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
250          bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }          bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
251          bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }          bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
252    
253            /** @brief Create an unique indentifier for a native C++ object/member/variable.
254             *
255             * Creates and returns an unique identifier for the passed native C++
256             * object, object member or variable. For the same C++ object/member/variable
257             * this function will always return the same UID. For all other ones,
258             * this function is guaranteed to return a different UID.
259             */
260          template<typename T>          template<typename T>
261          static UID from(const T& obj) {          static UID from(const T& obj) {
262              return Resolver<T>::resolve(obj);              return Resolver<T>::resolve(obj);
# Line 197  namespace Serialization { Line 284  namespace Serialization {
284    
285      /**      /**
286       * Reflects an invalid UID and behaves similar to NULL as invalid value for       * Reflects an invalid UID and behaves similar to NULL as invalid value for
287       * pointer types.       * pointer types. All UID objects are first initialized with this value,
288         * and it essentially an all zero object.
289       */       */
290      extern const UID NO_UID;      extern const UID NO_UID;
291    
292        /** @brief Chain of UIDs.
293         *
294         * This data type is used for native C++ pointers. The first member of the
295         * UID chain is the unique identifier of the C++ pointer itself, then the
296         * following UIDs are the respective objects or variables the pointer is
297         * pointing to. The size (the amount of elements) of the UIDChain depends
298         * solely on the degree of the pointer type. For example the following C/C++
299         * pointer:
300         * @code
301         * int* pNumber;
302         * @endcode
303         * is an integer pointer of first degree. Such a pointer would have a
304         * UIDChain with 2 members: the first element would be the UID of the
305         * pointer itself, the second element of the chain would be the integer data
306         * that pointer is pointing to. In the following example:
307         * @code
308         * bool*** pppSomeFlag;
309         * @endcode
310         * That boolean pointer would be of third degree, and thus its UIDChain
311         * would have a size of 4 (elements).
312         *
313         * Accordingly a non pointer type like:
314         * @code
315         * float f;
316         * @endcode
317         * would yield in a UIDChain of size 1.
318         *
319         * Since however this serialization framework currently only supports
320         * pointers of first degree yet, all UIDChains are currently either of
321         * size 1 or 2, which might change in future though.
322         */
323      typedef std::vector<UID> UIDChain;      typedef std::vector<UID> UIDChain;
324    
325      // prototyping of private internal friend functions      // prototyping of private internal friend functions
# Line 210  namespace Serialization { Line 329  namespace Serialization {
329      static Object _popObjectBlob(const char*& p, const char* end);      static Object _popObjectBlob(const char*& p, const char* end);
330      static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);      static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
331      static String _primitiveObjectValueToString(const Object& obj);      static String _primitiveObjectValueToString(const Object& obj);
332        //  |
333        template<typename T>
334        static T _primitiveObjectValueToNumber(const Object& obj);
335    
336      /** @brief Abstract reflection of a native C++ data type.      /** @brief Abstract reflection of a native C++ data type.
337       *       *
338       * Provides detailed information about a C++ data type, whether it is a       * Provides detailed information about a serialized C++ data type, whether
339       * fundamental C/C++ data type (like int, float, char, etc.) or custom       * it is a fundamental C/C++ data type (like @c int, @c float, @c char,
340       * defined data type like a C++ class, struct, enum, as well as other       * etc.) or custom defined data types like a C++ @c class, C/C++ @c struct,
341       * features of the data type like its native memory size and more.       * @c enum, as well as other features of the respective data type like its
342         * native memory size and more.
343         *
344         * All informations provided by this class are retrieved from the
345         * respective individual C++ objects, their members and other data when
346         * they are serialized, and all those information are stored with the
347         * serialized archive and its resulting data stream. Due to the availability
348         * of these extensive data type information within serialized archives, this
349         * framework is capable to use them in order to adapt its deserialization
350         * process upon subsequent changes to your individual C++ classes.
351       */       */
352      class DataType {      class DataType {
353      public:      public:
354          DataType();          DataType();
355          size_t size() const { return m_size; }          size_t size() const { return m_size; } ///< Returns native memory size of the respective C++ object or variable.
356          bool isValid() const;          bool isValid() const;
357          bool isPointer() const;          bool isPointer() const;
358          bool isClass() const;          bool isClass() const;
# Line 231  namespace Serialization { Line 362  namespace Serialization {
362          bool isBool() const;          bool isBool() const;
363          bool isEnum() const;          bool isEnum() const;
364          bool isSigned() const;          bool isSigned() const;
365          operator bool() const { return isValid(); }          operator bool() const { return isValid(); } ///< Same as calling isValid().
366          //bool operator()() const { return isValid(); }          //bool operator()() const { return isValid(); }
367          bool operator==(const DataType& other) const;          bool operator==(const DataType& other) const;
368          bool operator!=(const DataType& other) const;          bool operator!=(const DataType& other) const;
369          bool operator<(const DataType& other) const;          bool operator<(const DataType& other) const;
370          bool operator>(const DataType& other) const;          bool operator>(const DataType& other) const;
371          String asLongDescr() const;          String asLongDescr() const;
372          String baseTypeName() const { return m_baseTypeName; }          String baseTypeName() const;
373          String customTypeName() const { return m_customTypeName; }          String customTypeName(bool demangle = false) const;
374    
375            /** @brief Construct a DataType object for the given native C++ data.
376             *
377             * Use this function to create corresponding DataType objects for
378             * native C/C++ objects, members and variables.
379             *
380             * @param data - native C/C++ object/member/variable a DataType object
381             *               shall be created for
382             * @returns corresponding DataType object for the supplied native C/C++
383             *          object/member/variable
384             */
385          template<typename T>          template<typename T>
386          static DataType dataTypeOf(const T& data) {          static DataType dataTypeOf(const T& data) {
387              return Resolver<T>::resolve(data);              return Resolver<T>::resolve(data);
# Line 323  namespace Serialization { Line 464  namespace Serialization {
464       * serialized C++ object, like its C++ data type, offset of this member       * serialized C++ object, like its C++ data type, offset of this member
465       * within its containing data structure/class, its C++ member variable name       * within its containing data structure/class, its C++ member variable name
466       * and more.       * and more.
467         *
468         * Consider you defined the following user defined C/C++ @c struct type in
469         * your application:
470         * @code
471         * struct Foo {
472         *     int  a;
473         *     bool b;
474         *     double someValue;
475         * };
476         * @endcode
477         * Then @c a, @c b and @c someValue are "members" of @c struct @c Foo for
478         * instance. So that @c struct would have 3 members in the latter example.
479         *
480         * @see Object::members()
481       */       */
482      class Member {      class Member {
483      public:      public:
484          Member();          Member();
485          UID uid() const { return m_uid; }          UID uid() const;
486          String name() const { return m_name; }          String name() const;
487          size_t offset() const { return m_offset; }          size_t offset() const;
488          const DataType& type() const { return m_type; }          const DataType& type() const;
489          bool isValid() const;          bool isValid() const;
490          operator bool() const { return isValid(); }          operator bool() const { return isValid(); } ///< Same as calling isValid().
491          //bool operator()() const { return isValid(); }          //bool operator()() const { return isValid(); }
492          bool operator==(const Member& other) const;          bool operator==(const Member& other) const;
493          bool operator!=(const Member& other) const;          bool operator!=(const Member& other) const;
# Line 352  namespace Serialization { Line 507  namespace Serialization {
507          friend Member _popMemberBlob(const char*& p, const char* end);          friend Member _popMemberBlob(const char*& p, const char* end);
508      };      };
509    
510      /** @brief Abstract reflection of a native C++ class/struct instance.      /** @brief Abstract reflection of some native serialized C/C++ data.
511         *
512         * When your native C++ objects are serialized, all native data is
513         * translated and reflected by such an Object reflection. So each instance
514         * of your serialized native C++ class objects become available as an
515         * Object, but also each member variable of your C++ objects is translated
516         * into an Object, and any other native C/C++ data. So essentially every
517         * native data is turned into its own Object and accessible by this API.
518       *       *
519       * Provides detailed information about a specific serialized C++ object,       * For each one of those Object reflections, this class provides detailed
520       * like its C++ member variables, its C++ class/struct name, its native       * information about their native origin. For example if an Object
521       * memory size and more.       * represents a native C++ class instante, then it provides access to its
522         * C++ class/struct name, to its C++ member variables, its native memory
523         * size and much more.
524         *
525         * Even though this framework allows you to adjust abstract Object instances
526         * to a certain extent, most of the methods of this Object class are
527         * read-only though and the actual modifyable methods are made available
528         * not as part of this Object class, but as part of the Archive class
529         * instead. This design decision was made for performance and safety
530         * reasons.
531         *
532         * @see Archive::setIntValue() as an example for modifying Object instances.
533       */       */
534      class Object {      class Object {
535      public:      public:
536          Object();          Object();
537          Object(UIDChain uidChain, DataType type);          Object(UIDChain uidChain, DataType type);
538    
539          UID uid(int index = 0) const {          UID uid(int index = 0) const;
540              return (index < m_uid.size()) ? m_uid[index] : NO_UID;          const UIDChain& uidChain() const;
541          }          const DataType& type() const;
542            const RawData& rawData() const;
543          const UIDChain& uidChain() const { return m_uid; }          Version version() const;
544          const DataType& type() const { return m_type; }          Version minVersion() const;
         const RawData& rawData() const { return m_data; }  
   
         Version version() const { return m_version; }  
   
         void setVersion(Version v) {  
             m_version = v;  
         }  
   
         Version minVersion() const { return m_minVersion; }  
   
         void setMinVersion(Version v) {  
             m_minVersion = v;  
         }  
   
545          bool isVersionCompatibleTo(const Object& other) const;          bool isVersionCompatibleTo(const Object& other) const;
546            std::vector<Member>& members();
547          std::vector<Member>& members() { return m_members; }          const std::vector<Member>& members() const;
         const std::vector<Member>& members() const { return m_members; }  
548          Member memberNamed(String name) const;          Member memberNamed(String name) const;
549          Member memberByUID(const UID& uid) const;          Member memberByUID(const UID& uid) const;
550          std::vector<Member> membersOfType(const DataType& type) const;          std::vector<Member> membersOfType(const DataType& type) const;
551          int sequenceIndexOf(const Member& member) const;          int sequenceIndexOf(const Member& member) const;
552          bool isValid() const;          bool isValid() const;
553          operator bool() const { return isValid(); }          operator bool() const { return isValid(); } ///< Same as calling isValid().
554          //bool operator()() const { return isValid(); }          //bool operator()() const { return isValid(); }
555          bool operator==(const Object& other) const;          bool operator==(const Object& other) const;
556          bool operator!=(const Object& other) const;          bool operator!=(const Object& other) const;
# Line 401  namespace Serialization { Line 559  namespace Serialization {
559    
560      protected:      protected:
561          void remove(const Member& member);          void remove(const Member& member);
562            void setVersion(Version v);
563            void setMinVersion(Version v);
564    
565      private:      private:
566          DataType m_type;          DataType m_type;
# Line 414  namespace Serialization { Line 574  namespace Serialization {
574          friend Object _popObjectBlob(const char*& p, const char* end);          friend Object _popObjectBlob(const char*& p, const char* end);
575          friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);          friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
576          friend String _primitiveObjectValueToString(const Object& obj);          friend String _primitiveObjectValueToString(const Object& obj);
577    
578            template<typename T>
579            friend T _primitiveObjectValueToNumber(const Object& obj);
580    
581          friend class Archive;          friend class Archive;
582      };      };
583    
# Line 529  namespace Serialization { Line 693  namespace Serialization {
693       * Note that there is only one method that you need to implement. So the       * Note that there is only one method that you need to implement. So the
694       * respective serialize() method implementation of your classes/structs are       * respective serialize() method implementation of your classes/structs are
695       * both called for serialization, as well as for deserialization!       * both called for serialization, as well as for deserialization!
696         *
697         * In case you need to enforce backward incompatiblity for one of your C++
698         * classes, you can do so by setting a version and minimum version for your
699         * class (see @c setVersion() and @c setMinVersion() for details).
700       */       */
701      class Archive {      class Archive {
702      public:      public:
# Line 537  namespace Serialization { Line 705  namespace Serialization {
705          Archive(const uint8_t* data, size_t size);          Archive(const uint8_t* data, size_t size);
706          virtual ~Archive();          virtual ~Archive();
707    
708            /** @brief Initiate serialization.
709             *
710             * Initiates serialization of all native C++ objects, which means
711             * capturing and storing the current data of all your C++ objects as
712             * content of this Archive.
713             *
714             * This framework has a concept of a "root" object which you must pass
715             * to this method. The root object is the starting point for
716             * serialization of your C++ objects. The framework will then
717             * recursively serialize all members of that C++ object an continue to
718             * serialize all other C++ objects that it might contain or point to.
719             *
720             * After this method returned, you might traverse all serialized objects
721             * by walking them starting from the rootObject(). You might then modify
722             * that abstract reflection of your C++ objects and finally you might
723             * call rawData() to get an encoded raw data stream which you might use
724             * for sending it "over wire" to somewhere where it is going to be
725             * deserialized later on.
726             *
727             * Note that whenever you call this method, the previous content of this
728             * Archive will first be cleared.
729             *
730             * @param obj - native C++ root object where serialization shall start
731             * @see Archive::operator<<()
732             */
733          template<typename T>          template<typename T>
734          void serialize(const T* obj) {          void serialize(const T* obj) {
735              m_operation = OPERATION_SERIALIZE;              m_operation = OPERATION_SERIALIZE;
# Line 548  namespace Serialization { Line 741  namespace Serialization {
741              m_operation = OPERATION_NONE;              m_operation = OPERATION_NONE;
742          }          }
743    
744            /** @brief Initiate deserialization.
745             *
746             * Initiates deserialization of all native C++ objects, which means all
747             * your C++ objects will be restored with the values contained in this
748             * Archive. So that also means calling deserialize() only makes sense if
749             * this a non-empty Archive, which i.e. is the case if you either called
750             * serialize() with this Archive object before or if you passed a
751             * previously serialized raw data stream to the constructor of this
752             * Archive object.
753             *
754             * This framework has a concept of a "root" object which you must pass
755             * to this method. The root object is the starting point for
756             * deserialization of your C++ objects. The framework will then
757             * recursively deserialize all members of that C++ object an continue to
758             * deserialize all other C++ objects that it might contain or point to,
759             * according to the values stored in this Archive.
760             *
761             * @param obj - native C++ root object where deserialization shall start
762             * @see Archive::operator>>()
763             *
764             * @throws Exception if the data stored in this Archive cannot be
765             *         restored to the C++ objects passed to this method, i.e.
766             *         because of version or type incompatibilities.
767             */
768          template<typename T>          template<typename T>
769          void deserialize(T* obj) {          void deserialize(T* obj) {
770              Archive a;              Archive a;
# Line 558  namespace Serialization { Line 775  namespace Serialization {
775              m_operation = OPERATION_NONE;              m_operation = OPERATION_NONE;
776          }          }
777    
778            /** @brief Initiate serialization of your C++ objects.
779             *
780             * Same as calling @c serialize(), this is just meant if you prefer
781             * to use operator based code instead, which you might find to be more
782             * intuitive.
783             *
784             * Example:
785             * @code
786             * Archive a;
787             * a << myRootObject;
788             * @endcode
789             *
790             * @see Archive::serialize() for more details.
791             */
792          template<typename T>          template<typename T>
793          void operator<<(const T& obj) {          void operator<<(const T& obj) {
794              serialize(&obj);              serialize(&obj);
795          }          }
796    
797            /** @brief Initiate deserialization of your C++ objects.
798             *
799             * Same as calling @c deserialize(), this is just meant if you prefer
800             * to use operator based code instead, which you might find to be more
801             * intuitive.
802             *
803             * Example:
804             * @code
805             * Archive a(rawDataStream);
806             * a >> myRootObject;
807             * @endcode
808             *
809             * @throws Exception if the data stored in this Archive cannot be
810             *         restored to the C++ objects passed to this method, i.e.
811             *         because of version or type incompatibilities.
812             *
813             * @see Archive::deserialize() for more details.
814             */
815          template<typename T>          template<typename T>
816          void operator>>(T& obj) {          void operator>>(T& obj) {
817              deserialize(&obj);              deserialize(&obj);
# Line 571  namespace Serialization { Line 820  namespace Serialization {
820          const RawData& rawData();          const RawData& rawData();
821          virtual String rawDataFormat() const;          virtual String rawDataFormat() const;
822    
823            /** @brief Serialize a native C/C++ member variable.
824             *
825             * This method is usually called by the serialize() method
826             * implementation of your C/C++ structs and classes, for each of the
827             * member variables that shall be serialized and deserialized
828             * automatically with this framework. It is recommend that you are not
829             * using this method name directly, but rather define a short hand C
830             * macro in your .cpp file like:
831             * @code
832             * #define SRLZ(member) \
833             *   archive->serializeMember(*this, member, #member);
834             *
835             * void Foo::serialize(Serialization::Archive* archive) {
836             *     SRLZ(a);
837             *     SRLZ(b);
838             *     SRLZ(c);
839             * }
840             * @endcode
841             * As you can see, using such a macro makes your code more readable and
842             * less error prone.
843             *
844             * It is completely up to you to decide which ones of your member
845             * variables shall automatically be serialized and deserialized with
846             * this framework. Only those member variables which are registered by
847             * calling this method will be serialized and deserialized. It does not
848             * really matter in which order you register your individiual member
849             * variables by calling this method, but the sequence is actually stored
850             * as meta information with the resulting archive and the resulting raw
851             * data stream. That meta information might then be used by this
852             * framework to automatically correct and adapt deserializing that
853             * archive later on for a future (or older) and potentially heavily
854             * modified version of your software. So it is recommended, even though
855             * also not required, that you may retain the sequence of your
856             * serializeMember() calls for your individual C++ classes' members over
857             * all your software versions, to retain backward compatibility of older
858             * archives as much as possible.
859             *
860             * @param nativeObject - native C++ object to be registered for
861             *                       serialization / deserialization
862             * @param nativeMember - native C++ member variable of @a nativeObject
863             *                       to be registered for serialization /
864             *                       deserialization
865             * @param memberName - name of @a nativeMember to be stored with this
866             *                     archive
867             */
868          template<typename T_classType, typename T_memberType>          template<typename T_classType, typename T_memberType>
869          void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {          void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
870              const size_t offset =              const size_t offset =
871              ((const uint8_t*)(const void*)&nativeMember) -                  ((const uint8_t*)(const void*)&nativeMember) -
872              ((const uint8_t*)(const void*)&nativeObject);                  ((const uint8_t*)(const void*)&nativeObject);
873              const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);              const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
874              const DataType type = DataType::dataTypeOf(nativeMember);              const DataType type = DataType::dataTypeOf(nativeMember);
875              const Member member(memberName, uids[0], offset, type);              const Member member(memberName, uids[0], offset, type);
# Line 599  namespace Serialization { Line 893  namespace Serialization {
893              }              }
894          }          }
895    
896            /** @brief Set current version number for your C++ class.
897             *
898             * By calling this method you can define a version number for your
899             * current C++ class (that is a version for its current data structure
900             * layout and method implementations) that is going to be stored along
901             * with the serialized archive. Only call this method if you really want
902             * to constrain compatibility of your C++ class.
903             *
904             * Along with calling @c setMinVersion() this provides a way for you
905             * to constrain backward compatibility regarding serialization and
906             * deserialization of your C++ class which the Archive class will obey
907             * to. If required, then typically you might do so in your
908             * @c serialize() method implementation like:
909             * @code
910             * #define SRLZ(member) \
911             *   archive->serializeMember(*this, member, #member);
912             *
913             * void Foo::serialize(Serialization::Archive* archive) {
914             *     // when serializing: the current version of this class that is
915             *     // going to be stored with the serialized archive
916             *     archive->setVersion(*this, 6);
917             *     // when deserializing: the minimum version this C++ class is
918             *     // compatible with
919             *     archive->setMinVersion(*this, 3);
920             *     // actual data mebers to serialize / deserialize
921             *     SRLZ(a);
922             *     SRLZ(b);
923             *     SRLZ(c);
924             * }
925             * @endcode
926             * In this example above, the C++ class "Foo" would be serialized along
927             * with the version number @c 6 and minimum version @c 3 as additional
928             * meta information in the resulting archive (and its raw data stream
929             * respectively).
930             *
931             * When deserializing archives with the example C++ class code above,
932             * the Archive object would check whether your originally serialized
933             * C++ "Foo" object had at least version number @c 3, if not the
934             * deserialization process would automatically be stopped with a
935             * @c Serialization::Exception, claiming that the classes are version
936             * incompatible.
937             *
938             * But also consider the other way around: you might have serialized
939             * your latest version of your C++ class, and might deserialize that
940             * archive with an older version of your C++ class. In that case it will
941             * likewise be checked whether the version of that old C++ class is at
942             * least as high as the minimum version set with the already seralized
943             * bleeding edge C++ class.
944             *
945             * Since this Serialization / deserialization framework is designed to
946             * be robust on changes to your C++ classes and aims trying to
947             * deserialize all your C++ objects correctly even if your C++ classes
948             * have seen substantial software changes in the meantime; you might
949             * sometimes see it as necessary to constrain backward compatibility
950             * this way. Because obviously there are certain things this framework
951             * can cope with, like for example that you renamed a data member while
952             * keeping the layout consistent, or that you have added new members to
953             * your C++ class or simply changed the order of your members in your
954             * C++ class. But what this framework cannot detect is for example if
955             * you changed the semantics of the values stored with your members, or
956             * even substantially changed the algorithms in your class methods such
957             * that they would not handle the data of your C++ members in the same
958             * and correct way anymore.
959             *
960             * @param nativeObject - your C++ object you want to set a version for
961             * @param v - the version number to set for your C++ class (by default,
962             *            that is if you do not explicitly call this method, then
963             *            your C++ object will be stored with version number @c 0 ).
964             */
965            template<typename T_classType>
966            void setVersion(const T_classType& nativeObject, Version v) {
967                const UID uid = UID::from(nativeObject);
968                Object& obj = m_allObjects[uid];
969                if (!obj) {
970                    const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
971                    const DataType type = DataType::dataTypeOf(nativeObject);
972                    obj = Object(uids, type);
973                }
974                setVersion(obj, v);
975            }
976    
977            /** @brief Set a minimum version number for your C++ class.
978             *
979             * Call this method to define a minimum version that your current C++
980             * class implementation would be compatible with when it comes to
981             * deserialization of an archive containing an object of your C++ class.
982             * Like the version information, the minimum version will also be stored
983             * for objects of your C++ class with the resulting archive (and its
984             * resulting raw data stream respectively).
985             *
986             * When you start to constrain version compatibility of your C++ class
987             * you usually start by using 1 as version and 1 as minimum version.
988             * So it is eligible to set the same number to both version and minimum
989             * version. However you must @b not set a minimum version higher than
990             * version. Doing so would not raise an exception, but the resulting
991             * behavior would be undefined.
992             *
993             * It is not relevant whether you first set version and then minimum
994             * version or vice versa. It is also not relevant when exactly you set
995             * those two numbers, even though usually you would set both in your
996             * serialize() method implementation.
997             *
998             * @see @c setVersion() for more details about this overall topic.
999             *
1000             * @param nativeObject - your C++ object you want to set a version for
1001             * @param v - the minimum version you want to define for your C++ class
1002             *            (by default, that is if you do not explicitly call this
1003             *            method, then a minium version of @c 0 is assumed for your
1004             *            C++ class instead).
1005             */
1006            template<typename T_classType>
1007            void setMinVersion(const T_classType& nativeObject, Version v) {
1008                const UID uid = UID::from(nativeObject);
1009                Object& obj = m_allObjects[uid];
1010                if (!obj) {
1011                    const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1012                    const DataType type = DataType::dataTypeOf(nativeObject);
1013                    obj = Object(uids, type);
1014                }
1015                setMinVersion(obj, v);
1016            }
1017    
1018          virtual void decode(const RawData& data);          virtual void decode(const RawData& data);
1019          virtual void decode(const uint8_t* data, size_t size);          virtual void decode(const uint8_t* data, size_t size);
1020          void clear();          void clear();
# Line 613  namespace Serialization { Line 1029  namespace Serialization {
1029          void setBoolValue(Object& object, bool value);          void setBoolValue(Object& object, bool value);
1030          void setEnumValue(Object& object, uint64_t value);          void setEnumValue(Object& object, uint64_t value);
1031          String valueAsString(const Object& object);          String valueAsString(const Object& object);
1032            int64_t valueAsInt(const Object& object);
1033            double valueAsReal(const Object& object);
1034            bool valueAsBool(const Object& object);
1035            void setVersion(Object& object, Version v);
1036            void setMinVersion(Object& object, Version v);
1037          String name() const;          String name() const;
1038          void setName(String name);          void setName(String name);
1039          String comment() const;          String comment() const;
# Line 725  namespace Serialization { Line 1146  namespace Serialization {
1146              Archive& m_src;              Archive& m_src;
1147          };          };
1148    
1149            enum operation_t {
1150                OPERATION_NONE,
1151                OPERATION_SERIALIZE,
1152                OPERATION_DESERIALIZE
1153            };
1154    
1155          virtual void encode();          virtual void encode();
1156    
1157          ObjectPool m_allObjects;          ObjectPool m_allObjects;

Legend:
Removed from v.3168  
changed lines
  Added in v.3185

  ViewVC Help
Powered by ViewVC