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

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

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

revision 3771 by schoenebeck, Sun May 17 17:14:31 2020 UTC revision 3778 by schoenebeck, Sun May 24 11:20:11 2020 UTC
# Line 28  Line 28 
28  #include "Serialization.h"  #include "Serialization.h"
29    
30  #include <iostream>  #include <iostream>
 #include <assert.h>  
31  #include <string.h> // for memcpy()  #include <string.h> // for memcpy()
32  #include <stdlib.h> // for atof()  #include <stdlib.h> // for atof()
33  #ifdef _MSC_VER  #ifdef _MSC_VER
# Line 102  namespace Serialization { Line 101  namespace Serialization {
101       *                   type in a coarse way, which must be either one of:       *                   type in a coarse way, which must be either one of:
102       *                   "int8", "uint8", "int16", "uint16", "int32", "uint32",       *                   "int8", "uint8", "int16", "uint16", "int32", "uint32",
103       *                   "int64", "uint64", "bool", "real32", "real64",       *                   "int64", "uint64", "bool", "real32", "real64",
104       *                   "String", "enum", "union" or "class"       *                   "String", "Array", "Set", "enum", "union" or "class"
105       * @param customType - this is only used for base types "enum", "union" or       * @param customType1 - this is only used for base types "enum", "union",
106       *                     "class", in which case this identifies the user       *                     "class", "Array", "Set" or "Map", in which case this
107       *                     defined type name (e.g. "Foo" for @c class @c Foo ),       *                      identifies the user defined type name (e.g. "Foo" for
108       *                     for all other types this is empty       *                      @c class @c Foo or e.g. "Bar" for @c Array<Bar>
109         *                      respectively), for all other types this is empty
110         * @param customType2 - this is only used for @c Map<> objects in which case
111         *                      it identifies the map's value type (i.e. 2nd
112         *                      template parameter of map)
113       */       */
114      DataType::DataType(bool isPointer, int size, String baseType, String customType) {      DataType::DataType(bool isPointer, int size, String baseType,
115                           String customType1, String customType2)
116        {
117          m_size = size;          m_size = size;
118          m_isPointer = isPointer;          m_isPointer = isPointer;
119          m_baseTypeName = baseType;          m_baseTypeName = baseType;
120          m_customTypeName = customType;          m_customTypeName = customType1;
121            m_customTypeName2 = customType2;
122      }      }
123    
124      /** @brief Check if this is a valid DataType object.      /** @brief Check if this is a valid DataType object.
# Line 142  namespace Serialization { Line 148  namespace Serialization {
148       *       *
149       * Returns @c true if the respective native C/C++ object, member or variable       * Returns @c true if the respective native C/C++ object, member or variable
150       * (this DataType instance is reflecting) is a C/C++ @c struct or @c class       * (this DataType instance is reflecting) is a C/C++ @c struct or @c class
151       * type, with one exception: @c String objects are handled by this framework       * type.
152       * as if they were a primitive type.       *
153         * @note: Data types which enjoy out of the box serialization support by
154         * this framework, like @c String and @c Array<> are @b NOT handled as class
155         * data types by this framwork. So @c isClass() returns @c false for e.g.
156         * @c String and any @c Array<> based data type.
157       *       *
158       * Note that in the following example:       * Note that in the following example:
159       * @code       * @code
# Line 184  namespace Serialization { Line 194  namespace Serialization {
194       * @see isPointer()       * @see isPointer()
195       */       */
196      bool DataType::isPrimitive() const {      bool DataType::isPrimitive() const {
197          return !isClass();          return !isClass() && !isArray() && !isSet() && !isMap();
198      }      }
199    
200      /** @brief Whether this is a C++ @c String data type.      /** @brief Whether this is a C++ @c String data type.
# Line 266  namespace Serialization { Line 276  namespace Serialization {
276          return m_baseTypeName == "enum";          return m_baseTypeName == "enum";
277      }      }
278    
279        /** @brief Whether this is a C++ @c Array<> object type.
280         *
281         * Returns @c true if the respective native C/C++ object, member or variable
282         * (this DataType instance is reflecting) is a C++ @c Array<> container
283         * object type.
284         *
285         * @note: This framework handles @c Array<> types neither as primitive
286         * types, nor as class types. So @c isPrimitive() and @c isClass() both
287         * return @c false for arrays.
288         *
289         * @see isPointer()
290         */
291        bool DataType::isArray() const {
292            return m_baseTypeName == "Array";
293        }
294    
295        /** @brief Whether this is a C++ @c Set<> object type.
296         *
297         * Returns @c true if the respective native C/C++ object, member or variable
298         * (this DataType instance is reflecting) is a C++ @c Set<> unique container
299         * object type.
300         *
301         * @note: This framework handles @c Set<> types neither as primitive
302         * types, nor as class types. So @c isPrimitive() and @c isClass() both
303         * return @c false for sets.
304         *
305         * @see isPointer()
306         */
307        bool DataType::isSet() const {
308            return m_baseTypeName == "Set";
309        }
310    
311        /** @brief Whether this is a C++ @c Map<> object type.
312         *
313         * Returns @c true if the respective native C/C++ object, member or variable
314         * (this DataType instance is reflecting) is an associative sorted C++
315         * @c Map<> container object type.
316         *
317         * @note: This framework handles @c Map<> types neither as primitive
318         * types, nor as class types. So @c isPrimitive() and @c isClass() both
319         * return @c false for maps.
320         *
321         * @see isPointer()
322         */
323        bool DataType::isMap() const {
324            return m_baseTypeName == "Map";
325        }
326    
327      /** @brief Whether this is a signed integer C/C++ data type.      /** @brief Whether this is a signed integer C/C++ data type.
328       *       *
329       * Returns @c true if the respective native C/C++ object, member or variable       * Returns @c true if the respective native C/C++ object, member or variable
# Line 305  namespace Serialization { Line 363  namespace Serialization {
363      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
364          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
365                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
366                   m_customTypeName2 == other.m_customTypeName2 &&
367                 (m_size == other.m_size || (isClass() && other.isClass())) &&                 (m_size == other.m_size || (isClass() && other.isClass())) &&
368                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
369      }      }
# Line 334  namespace Serialization { Line 393  namespace Serialization {
393                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
394                (m_customTypeName  < other.m_customTypeName ||                (m_customTypeName  < other.m_customTypeName ||
395                (m_customTypeName == other.m_customTypeName &&                (m_customTypeName == other.m_customTypeName &&
396                  (m_customTypeName2  < other.m_customTypeName2 ||
397                  (m_customTypeName2 == other.m_customTypeName2 &&
398                (m_size  < other.m_size ||                (m_size  < other.m_size ||
399                (m_size == other.m_size &&                (m_size == other.m_size &&
400                 m_isPointer < other.m_isPointer)))));                 m_isPointer < other.m_isPointer)))))));
401      }      }
402    
403      /** @brief Greater than comparison.      /** @brief Greater than comparison.
# Line 372  namespace Serialization { Line 433  namespace Serialization {
433          String s = m_baseTypeName;          String s = m_baseTypeName;
434          if (!m_customTypeName.empty())          if (!m_customTypeName.empty())
435              s += " " + customTypeName(true);              s += " " + customTypeName(true);
436            if (!m_customTypeName2.empty())
437                s += " " + customTypeName2(true);
438          if (isPointer())          if (isPointer())
439              s += " pointer";              s += " pointer";
440          return s;          return s;
# Line 404  namespace Serialization { Line 467  namespace Serialization {
467       * @endcode       * @endcode
468       * this method would return for both @c i and @c pi the string @c "uint64" !       * this method would return for both @c i and @c pi the string @c "uint64" !
469       *       *
470       * @see isPointer(), customTypeName()       * @see isPointer(), customTypeName(), customTypeName2()
471       */       */
472      String DataType::baseTypeName() const {      String DataType::baseTypeName() const {
473          return m_baseTypeName;          return m_baseTypeName;
474      }      }
475    
476      /** @brief The user defined C/C++ data type name of this data type.      static String _demangleTypeName(const char* name) {
477    #ifdef _MSC_VER
478            const size_t MAXLENGTH = 1024;
479            char result[MAXLENGTH];
480    
481            //FIXME: calling UnDecorateSymbolName() is not thread safe!
482            //Skip the first char
483            size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
484            if (size)
485            {
486                return result;
487            }
488            return name;
489    #else
490            int status;
491            char* result =
492                abi::__cxa_demangle(name, 0, 0, &status);
493            String sResult = result;
494            free(result);
495            return (status == 0) ? sResult : name;
496    #endif
497        }
498    
499        /** @brief The 1st user defined C/C++ data type name of this data type.
500       *       *
501       * Call this method on user defined C/C++ data types like @c enum, @c struct       * Call this method on user defined C/C++ data types like @c enum,
502       * and @c class types to retrieve the user defined type name portion of       * @c struct, @c class or @c Array<> types to retrieve the user defined type
503       * those data types. Note that this method is only intended for such user       * name portion of those data types. Note that this method is only intended
504       * defined data types. For all fundamental, primitive data types (like i.e.       * for such user defined data types. For all fundamental, primitive data
505       * @c int) this method returns an empty string instead.       * types (like i.e. @c int) this method returns an empty string instead.
506       *       *
507       * This method takes an optional boolean argument @b demangle, which allows       * This method takes an optional boolean argument @b demangle, which allows
508       * you define whether you are interested in the raw C++ type name or rather       * you define whether you are interested in the raw C++ type name or rather
# Line 444  namespace Serialization { Line 530  namespace Serialization {
530       * @b Windows: please note that the current implementation of this method       * @b Windows: please note that the current implementation of this method
531       * on Windows is @b not thread safe!       * on Windows is @b not thread safe!
532       *       *
533       * @see isPointer(), baseTypeName()       * @see baseTypeName(), customTypeName2(), isPointer()
534       */       */
535      String DataType::customTypeName(bool demangle) const {      String DataType::customTypeName(bool demangle) const {
536          if (!demangle) return m_customTypeName;          if (!demangle) return m_customTypeName;
537  #ifdef _MSC_VER          return _demangleTypeName(m_customTypeName.c_str());
538          const size_t MAXLENGTH = 1024;      }
         char result[MAXLENGTH];  
539    
540          //FIXME: calling UnDecorateSymbolName() is not thread safe!      /** @brief The 2nd user defined C/C++ data type name of this data type.
541          //Skip the first char       *
542          size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);       * This is currently only used for @c Map<> data types in which case this
543          if (size)       * method returns the map's value type (i.e. map's 2nd template parameter).
544          {       *
545              return result;       * @see baseTypeName(), customTypeName()
546          }       */
547          return m_customTypeName;      String DataType::customTypeName2(bool demangle) const {
548  #else          if (!demangle) return m_customTypeName2;
549          int status;          return _demangleTypeName(m_customTypeName2.c_str());
         char* result =  
             abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);  
         String sResult = result;  
         free(result);  
         return (status == 0) ? sResult : m_customTypeName;  
 #endif  
550      }      }
551    
552      // *************** Member ***************      // *************** Member ***************
# Line 490  namespace Serialization { Line 569  namespace Serialization {
569          m_offset = 0;          m_offset = 0;
570      }      }
571    
572      Member::Member(String name, UID uid, size_t offset, DataType type) {      Member::Member(String name, UID uid, ssize_t offset, DataType type) {
573          m_name = name;          m_name = name;
574          m_uid  = uid;          m_uid  = uid;
575          m_offset = offset;          m_offset = offset;
# Line 572  namespace Serialization { Line 651  namespace Serialization {
651       * @c b and @c c instead. For most 64 bit architectures this example would       * @c b and @c c instead. For most 64 bit architectures this example would
652       * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16       * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
653       * for member @c c.       * for member @c c.
654         *
655         * @note Offset is intended for native members only, that is member
656         * variables which are memory located directly within the associated parent
657         * data structure. For members allocated on the heap @c offset() always
658         * returns @c -1 instead since there is no constant, static offset
659         * relationship between data on the heap and the parent structure owning
660         * their life-time control.
661       */       */
662      size_t Member::offset() const {      ssize_t Member::offset() const {
663          return m_offset;          return m_offset;
664      }      }
665    
# Line 734  namespace Serialization { Line 820  namespace Serialization {
820          return (index < m_uid.size()) ? m_uid[index] : NO_UID;          return (index < m_uid.size()) ? m_uid[index] : NO_UID;
821      }      }
822    
823        static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
824            if (type.isPrimitive() && !type.isPointer()) {
825                if (type.isInteger() || type.isEnum()) {
826                    if (type.isSigned()) {
827                        if (type.size() == 1)
828                            *(int8_t*)ptr = (int8_t) atoll(s);
829                        else if (type.size() == 2)
830                            *(int16_t*)ptr = (int16_t) atoll(s);
831                        else if (type.size() == 4)
832                            *(int32_t*)ptr = (int32_t) atoll(s);
833                        else if (type.size() == 8)
834                            *(int64_t*)ptr = (int64_t) atoll(s);
835                        else
836                            assert(false /* unknown signed int type size */);
837                    } else {
838                        if (type.size() == 1)
839                            *(uint8_t*)ptr = (uint8_t) atoll(s);
840                        else if (type.size() == 2)
841                            *(uint16_t*)ptr = (uint16_t) atoll(s);
842                        else if (type.size() == 4)
843                            *(uint32_t*)ptr = (uint32_t) atoll(s);
844                        else if (type.size() == 8)
845                            *(uint64_t*)ptr = (uint64_t) atoll(s);
846                        else
847                            assert(false /* unknown unsigned int type size */);
848                    }
849                } else if (type.isReal()) {
850                    if (type.size() == sizeof(float))
851                        *(float*)ptr = (float) atof(s);
852                    else if (type.size() == sizeof(double))
853                        *(double*)ptr = (double) atof(s);
854                    else
855                        assert(false /* unknown floating point type */);
856                } else if (type.isBool()) {
857                    String lower = toLowerCase(s);
858                    const bool b = lower != "0" && lower != "false" && lower != "no";
859                    *(bool*)ptr = b;
860                } else if (type.isString()) {
861                    *(String*)ptr = s;
862                } else {
863                    assert(false /* no built-in cast from string support for this data type */);
864                }
865            }
866        }
867    
868        /** @brief Cast from string to object's data type and assign value natively.
869         *
870         * The passed String @a s is decoded from its string representation to this
871         * object's corresponding native data type, then that casted value is
872         * assigned to the native memory location this Object is referring to.
873         *
874         * Note: This method may only be called for data types which enjoy built-in
875         * support for casting from string to their native data type, which are
876         * basically primitive data types (e.g. @c int, @c bool, @c double, etc.) or
877         * @c String objects. For all other data types calling this method will
878         * cause an assertion fault at runtime.
879         *
880         * @param s - textual string representation of the value to be assigned to
881         *            this object
882         */
883        void Object::setNativeValueFromString(const String& s) {
884            const ID& id = uid().id;
885            void* ptr = (void*)id;
886            _setNativeValueFromString(ptr, m_type, s.c_str());
887        }
888    
889      /** @brief Unique identifier chain of this Object.      /** @brief Unique identifier chain of this Object.
890       *       *
891       * Returns the entire unique identifier chain of this Object.       * Returns the entire unique identifier chain of this Object.
# Line 1194  namespace Serialization { Line 1346  namespace Serialization {
1346    
1347      static String _encode(const DataType& type) {      static String _encode(const DataType& type) {
1348          String s;          String s;
1349    
1350            // Srx v1.0 format (mandatory):
1351          s += _encodeBlob(type.baseTypeName());          s += _encodeBlob(type.baseTypeName());
1352          s += _encodeBlob(type.customTypeName());          s += _encodeBlob(type.customTypeName());
1353          s += _encodeBlob(ToString(type.size()));          s += _encodeBlob(ToString(type.size()));
1354          s += _encodeBlob(ToString(type.isPointer()));          s += _encodeBlob(ToString(type.isPointer()));
1355    
1356            // Srx v1.1 format:
1357            s += _encodeBlob(type.customTypeName2());
1358    
1359          return _encodeBlob(s);          return _encodeBlob(s);
1360      }      }
1361    
# Line 1270  namespace Serialization { Line 1428  namespace Serialization {
1428              } else {              } else {
1429                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1430              }              }
   
1431          }          }
1432          return s;          return s;
1433      }      }
# Line 1377  namespace Serialization { Line 1534  namespace Serialization {
1534      /*      /*
1535       * Srx format history:       * Srx format history:
1536       * - 1.0: Initial version.       * - 1.0: Initial version.
1537       * - 1.1: Adds "String" data type.       * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1538         *        2nd custom type name (e.g. "Map" types which always contain two
1539         *        user defined types).
1540       */       */
1541      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1542      #define ENCODING_FORMAT_MINOR_VERSION 1      #define ENCODING_FORMAT_MINOR_VERSION 1
# Line 1523  namespace Serialization { Line 1682  namespace Serialization {
1682          end = blob.end;          end = blob.end;
1683    
1684          DataType type;          DataType type;
1685    
1686            // Srx v1.0 format (mandatory):
1687          type.m_baseTypeName   = _popStringBlob(p, end);          type.m_baseTypeName   = _popStringBlob(p, end);
1688          type.m_customTypeName = _popStringBlob(p, end);          type.m_customTypeName = _popStringBlob(p, end);
1689          type.m_size           = _popIntBlob<int>(p, end);          type.m_size           = _popIntBlob<int>(p, end);
1690          type.m_isPointer      = _popIntBlob<bool>(p, end);          type.m_isPointer      = _popIntBlob<bool>(p, end);
1691    
1692            // Srx v1.1 format (optional):
1693            if (p < end)
1694                type.m_customTypeName2 = _popStringBlob(p, end);
1695    
1696          return type;          return type;
1697      }      }
1698    
# Line 1568  namespace Serialization { Line 1734  namespace Serialization {
1734          if (p >= end) return m;          if (p >= end) return m;
1735    
1736          m.m_uid    = _popUIDBlob(p, end);          m.m_uid    = _popUIDBlob(p, end);
1737          m.m_offset = _popIntBlob<size_t>(p, end);          m.m_offset = _popIntBlob<ssize_t>(p, end);
1738          m.m_name   = _popStringBlob(p, end);          m.m_name   = _popStringBlob(p, end);
1739          m.m_type   = _popDataTypeBlob(p, end);          m.m_type   = _popDataTypeBlob(p, end);
1740          assert(m.type());          assert(m.type());
# Line 2323  namespace Serialization { Line 2489  namespace Serialization {
2489          return _primitiveObjectValueToNumber<bool>(*pObject);          return _primitiveObjectValueToNumber<bool>(*pObject);
2490      }      }
2491    
2492        Archive::operation_t Archive::operation() const {
2493            return m_operation;
2494        }
2495    
2496      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2497      // *      // *
2498    
# Line 2351  namespace Serialization { Line 2521  namespace Serialization {
2521          *pDst = (String) (const char*) &srcObj.rawData()[0];          *pDst = (String) (const char*) &srcObj.rawData()[0];
2522      }      }
2523    
2524        void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2525            assert(dstObj.type().isArray());
2526            assert(dstObj.type() == srcObj.type());
2527            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2528        }
2529    
2530        void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2531            assert(dstObj.type().isSet());
2532            assert(dstObj.type() == srcObj.type());
2533            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2534        }
2535    
2536        void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2537            assert(dstObj.type().isMap());
2538            assert(dstObj.type() == srcObj.type());
2539            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2540        }
2541    
2542      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2543          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2544          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 2384  namespace Serialization { Line 2572  namespace Serialization {
2572              return; // end of recursion              return; // end of recursion
2573          }          }
2574    
2575            if (dstObj.type().isArray()) {
2576                syncArray(dstObj, srcObj);
2577                return;
2578            }
2579    
2580            if (dstObj.type().isSet()) {
2581                syncSet(dstObj, srcObj);
2582                return;
2583            }
2584    
2585            if (dstObj.type().isMap()) {
2586                syncMap(dstObj, srcObj);
2587                return;
2588            }
2589    
2590          if (dstObj.type().isPointer()) {          if (dstObj.type().isPointer()) {
2591              syncPointer(dstObj, srcObj);              syncPointer(dstObj, srcObj);
2592              return;              return;

Legend:
Removed from v.3771  
changed lines
  Added in v.3778

  ViewVC Help
Powered by ViewVC