Parcourir la source

Migrate to sign depend ZigZag serialization

Alexey Edelev il y a 6 ans
Parent
commit
421cccdc6f
2 fichiers modifiés avec 86 ajouts et 49 suppressions
  1. 70 33
      src/lib/protobufobject.h
  2. 16 16
      tests/serializationtest.cpp

+ 70 - 33
src/lib/protobufobject.h

@@ -161,31 +161,35 @@ public:
         qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex;
         int userType = propertyValue.userType();
 
+        //First looking type serializer in registred serializers
         auto it = serializers.find(userType);
         if (it != std::end(serializers)) {
             return (it->second).serializer(this, propertyValue, fieldIndex);
         }
 
+        //Check if it's special list
         if (userType == qMetaTypeId<IntList>()) {
             return serializeListType(propertyValue.value<IntList>(), fieldIndex);
-        } else if(userType == qMetaTypeId<FloatList>()) {
+        }
+
+        if(userType == qMetaTypeId<FloatList>()) {
             return serializeListType(propertyValue.value<FloatList>(), fieldIndex);
-        } else if(userType == qMetaTypeId<DoubleList>()) {
+        }
+
+        if(userType == qMetaTypeId<DoubleList>()) {
             return serializeListType(propertyValue.value<DoubleList>(), fieldIndex);
-        } else {
-            const void *src = propertyValue.constData();
-            //TODO: each time huge objects will make own copies
-            //Probably generate fields reflection is better solution
-            auto value = std::unique_ptr<ProtobufObjectPrivate>(reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType, src)));
-            return serializeLengthDelimited(value->serializePrivate());
         }
-        Q_ASSERT_X(QMetaType::UnknownType == userType, staticMetaObject.className(), "Serialization of unknown user type");
-        return QByteArray();
+
+        //Otherwise it's user type
+        const void *src = propertyValue.constData();
+        //TODO: each time huge objects will make own copies
+        //Probably generate fields reflection is better solution
+        auto value = std::unique_ptr<ProtobufObjectPrivate>(reinterpret_cast<ProtobufObjectPrivate *>(QMetaType::create(userType, src)));
+        return serializeLengthDelimited(value->serializePrivate());
     }
 
     template<typename V,
-             typename std::enable_if_t<std::is_integral<V>::value
-                                       || std::is_floating_point<V>::value, int> = 0>
+             typename std::enable_if_t<std::is_integral<V>::value, int> = 0>
     QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) const {
         qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
         if (listValue.count() <= 0) {
@@ -195,7 +199,25 @@ public:
 
         QByteArray serializedList;
         for(auto& value : listValue) {
-            serializedList.append(serializeValue(value, NotUsedFieldIndex));
+            serializedList.append(serializeVarintZZ(value));
+        }
+        //If internal field type is not LengthDelimited, exact amount of fields to be specified
+        serializedList.prepend(serializeVarint(static_cast<unsigned int>(serializedList.size())));
+        return serializedList;
+    }
+
+    template<typename V,
+             typename std::enable_if_t<std::is_floating_point<V>::value, int> = 0>
+    QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) const {
+        qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
+        if (listValue.count() <= 0) {
+            outFieldIndex = NotUsedFieldIndex;
+            return QByteArray();
+        }
+
+        QByteArray serializedList;
+        for(auto& value : listValue) {
+            serializedList.append(serializeFixed(value));
         }
         //If internal field type is not LengthDelimited, exact amount of fields to be specified
         serializedList.prepend(serializeVarint(static_cast<unsigned int>(serializedList.size())));
@@ -254,14 +276,30 @@ public:
         return result;
     }
 
-    template <typename V,
+    template <typename V, typename UV = typename std::make_unsigned<V>::type,
               typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
     QByteArray serializeVarint(V value) const {
         qProtoDebug() << __func__ << "value" << value;
-        using UV = typename std::make_unsigned<V>::type;
+        UV uValue = 0;
+        //Use ZigZag convertion first and apply unsigned variant next
+        if (value < 0) {
+            value = (value << 1) ^ (value >> (sizeof(UV) * 8 - 1));
+            uValue = *(UV *)&value;
+        } else {
+            uValue = static_cast<UV>(value);
+        }
+        return serializeVarint(uValue);
+    }
+
+    template <typename V, typename UV = typename std::make_unsigned<V>::type,
+              typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
+    QByteArray serializeVarintZZ(V value) const {
+        qProtoDebug() << __func__ << "value" << value;
+        UV uValue = 0;
+
         //Use ZigZag convertion first and apply unsigned variant next
         value = (value << 1) ^ (value >> (sizeof(UV) * 8 - 1));
-        UV uValue = *(UV *)&value;
+        uValue = *(UV *)&value;
         return serializeVarint(uValue);
     }
 
@@ -294,7 +332,7 @@ public:
 //####################################################
     void deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
     {
-        qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName() << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << metaProperty.typeName() << "currentByte:" << QString::number((*it), 16);
         QVariant newPropertyValue;
         int type = metaProperty.type();
         switch(type) {
@@ -333,13 +371,13 @@ public:
             break;
         case QMetaType::QByteArrayList: {
             QByteArrayList currentValue = metaProperty.read(this).value<QByteArrayList>();
-            currentValue.append(deserializeListType<QByteArray>(it));
+            currentValue.append(deserializeLengthDelimited(it));
             metaProperty.write(this, QVariant::fromValue<QByteArrayList>(currentValue));
         }
             return;
         case QMetaType::QStringList: {
             QStringList currentValue = metaProperty.read(this).value<QStringList>();
-            currentValue.append(QString::fromUtf8(deserializeListType<QString>(it)));
+            currentValue.append(QString::fromUtf8(deserializeLengthDelimited(it)));
             metaProperty.write(this, currentValue);
         }
             return;
@@ -354,7 +392,7 @@ public:
                                         || std::is_same<V, unsigned int>::value
                                         || std::is_same<V, qulonglong>::value, int> = 0>
     QVariant deserializeFixed(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         QVariant newPropertyValue(QVariant::fromValue(*(V*)it));
         it += sizeof(V);
         return newPropertyValue;
@@ -363,15 +401,14 @@ public:
     template <typename V,
               typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
     QVariant deserializeVarint(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         return QVariant::fromValue(deserializeVarintCommon<V>(it));
     }
 
-    template <typename V,
+    template <typename V, typename UV = typename std::make_unsigned<V>::type,
               typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
     QVariant deserializeVarint(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
-        using UV = typename std::make_unsigned<V>::type;
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         UV unsignedValue = deserializeVarintCommon<UV>(it);
         V value = (unsignedValue >> 1) ^ (-(unsignedValue & 1));
 
@@ -380,7 +417,7 @@ public:
 
     template <typename V>
     V deserializeVarintCommon(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         V value = 0;
         int k = 0;
         while((*it) & 0x80) {
@@ -394,7 +431,7 @@ public:
     }
 
     QByteArray deserializeLengthDelimited(QByteArray::const_iterator &it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         unsigned int length = deserializeVarint<unsigned int>(it).toUInt();
         QByteArray result(it, length);
         it += length;
@@ -403,7 +440,7 @@ public:
 
     void deserializeUserType(int userType, QByteArray::const_iterator& it, QVariant &newValue)
     {
-        qProtoDebug() << __func__ << "userType" << userType << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "userType" << userType << "currentByte:" << QString::number((*it), 16);
 
         auto serializerIt = serializers.find(userType);
         if (serializerIt != std::end(serializers)) {
@@ -428,14 +465,14 @@ public:
               typename std::enable_if_t<std::is_same<V, QString>::value
                                         || std::is_same<V, QByteArray>::value, int> = 0>
     QByteArray deserializeListType(QByteArray::const_iterator& it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         return deserializeLengthDelimited(it);
     }
 
     template <typename V,
               typename std::enable_if_t<std::is_base_of<ProtobufObjectPrivate, V>::value, int> = 0>
     QVariant deserializeListType(QByteArray::const_iterator& it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         int metaTypeId = qMetaTypeId<V>();
         QVariant variant;
         deserializeUserType(metaTypeId, it, variant);
@@ -447,7 +484,7 @@ public:
                                         || std::is_same<V, unsigned int>::value
                                         || std::is_same<V, qulonglong>::value, int> = 0>
     QVariant deserializeListType(QByteArray::const_iterator& it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         QList<V> out;
         unsigned int count = deserializeVarint<unsigned int>(it).toUInt() / sizeof(V);
         for (unsigned int i = 0; i < count; i++) {
@@ -460,11 +497,11 @@ public:
     template <typename V,
               typename std::enable_if_t<std::is_same<V, int>::value, int> = 0>
     QVariant deserializeVarintListType(QByteArray::const_iterator& it) {
-        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it),16);
+        qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
         QList<V> out;
         unsigned int count = deserializeVarint<unsigned int>(it).toUInt();
         QByteArray::const_iterator lastVarint = it + count;
-        while(it != lastVarint) {
+        while (it != lastVarint) {
             QVariant variant = deserializeVarint<V>(it);
             out.append(variant.value<V>());
         }
@@ -537,7 +574,7 @@ public:
         qProtoDebug() << T::staticMetaObject.className() << "deserialize";
         //T *instance = dynamic_cast<T *>(this);
 
-        for(QByteArray::const_iterator it = array.begin(); it != array.end();) {
+        for (QByteArray::const_iterator it = array.begin(); it != array.end();) {
             //Each iteration we expect iterator is setup to beginning of next chunk
             int fieldNumber = NotUsedFieldIndex;
             WireTypes wireType = UnknownWireType;

Fichier diff supprimé car celui-ci est trop grand
+ 16 - 16
tests/serializationtest.cpp


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff