From 99bb364a7b2d07f7c891c8d17e06c99bd8259640 Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Wed, 16 Nov 2022 12:32:06 +0100 Subject: [PATCH] Change the container type of the internal type serializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list of integrated type serializers is predefined and can be initialized statically. Using std::array allows us to avoid extra allocations and gives us clean and simple static initialization. Change-Id: I04290d3b343487d6967341502c893f76a5044139 Reviewed-by: MÃ¥rten Nordheim --- src/protobuf/qprotobufserializer.cpp | 164 ++++++++++++++++++--------- src/protobuf/qprotobufserializer_p.h | 30 +---- 2 files changed, 113 insertions(+), 81 deletions(-) diff --git a/src/protobuf/qprotobufserializer.cpp b/src/protobuf/qprotobufserializer.cpp index 58bcc92c..cca4d927 100644 --- a/src/protobuf/qprotobufserializer.cpp +++ b/src/protobuf/qprotobufserializer.cpp @@ -172,6 +172,101 @@ bool QProtobufSerializerPrivate::deserializeList(QProtobufSelfcheckIter return false; } +template +using SerializerRegistryType = + std::array; + +namespace { +#define QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(Type, WireType) \ + { \ + QMetaType::fromType(), \ + QProtobufSerializerPrivate::serializeWrapper< \ + Type, QProtobufSerializerPrivate::serializeBasic>, \ + QProtobufSerializerPrivate::deserializeBasic, WireType \ + } +#define QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(ListType, Type) \ + { \ + QMetaType::fromType(), \ + QProtobufSerializerPrivate::serializeWrapper< \ + ListType, QProtobufSerializerPrivate::serializeListType>, \ + QProtobufSerializerPrivate::deserializeList, \ + QtProtobuf::WireTypes::LengthDelimited \ + } +constexpr SerializerRegistryType<30> IntegratedTypesSerializers = { { + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(float, QtProtobuf::WireTypes::Fixed32), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(double, QtProtobuf::WireTypes::Fixed64), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int32, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int64, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint32, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint64, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint32, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint64, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed32, + QtProtobuf::WireTypes::Fixed32), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed64, + QtProtobuf::WireTypes::Fixed64), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed32, + QtProtobuf::WireTypes::Fixed32), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed64, + QtProtobuf::WireTypes::Fixed64), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::boolean, + QtProtobuf::WireTypes::Varint), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QString, + QtProtobuf::WireTypes::LengthDelimited), + QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QByteArray, + QtProtobuf::WireTypes::LengthDelimited), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int32List, QtProtobuf::int32), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int64List, QtProtobuf::int64), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint32List, + QtProtobuf::uint32), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint64List, + QtProtobuf::uint64), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint32List, + QtProtobuf::sint32), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint64List, + QtProtobuf::sint64), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed32List, + QtProtobuf::fixed32), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed64List, + QtProtobuf::fixed64), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed32List, + QtProtobuf::sfixed32), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed64List, + QtProtobuf::sfixed64), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::boolList, QtProtobuf::boolean), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QStringList, QString), + QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QByteArrayList, QByteArray), +} }; + +template +std::optional +findIntegratedTypeHandlerImpl(QMetaType metaType, const SerializerRegistryType ®istry) +{ + typename SerializerRegistryType::const_iterator it = std::find_if( + registry.begin(), registry.end(), + [&metaType](const QProtobufSerializerPrivate::ProtobufSerializationHandler &handler) { + return handler.metaType == metaType; + }); + if (it == registry.end()) + return std::nullopt; + return { *it }; +} + +std::optional +findIntegratedTypeHandler(QMetaType metaType) +{ + return findIntegratedTypeHandlerImpl(metaType, IntegratedTypesSerializers); +} +} + /*! Constructs a new serializer instance. */ @@ -404,42 +499,6 @@ bool QProtobufSerializer::deserializeEnumList(QList &value, Q QProtobufSerializerPrivate::QProtobufSerializerPrivate(QProtobufSerializer *q) : q_ptr(q) { - //if handlers is not empty initialization already done - if (handlers.empty()) { - using QtProtobuf::WireTypes; - - wrapSerializer, WireTypes::Fixed32>(); - wrapSerializer, WireTypes::Fixed64>(); - wrapSerializer, WireTypes::Varint>(); - wrapSerializer, WireTypes::Varint>(); - wrapSerializer, WireTypes::Varint>(); - wrapSerializer, WireTypes::Varint>(); - wrapSerializer, WireTypes::Varint>(); - wrapSerializer, WireTypes::Varint>(); - wrapSerializer, WireTypes::Fixed32>(); - wrapSerializer, WireTypes::Fixed64>(); - wrapSerializer, WireTypes::Fixed32>(); - wrapSerializer, WireTypes::Fixed64>(); - wrapSerializer, deserializeBasic, WireTypes::Varint>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - wrapSerializer, deserializeList, WireTypes::LengthDelimited>(); - wrapSerializer, WireTypes::LengthDelimited>(); - } } void QProtobufSerializerPrivate::skipVarint(QProtobufSelfcheckIterator &it) @@ -499,13 +558,13 @@ QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue, QMetaType metaType = propertyValue.metaType(); //TODO: replace with some common function - auto basicIt = handlers.find(metaType); - if (basicIt != handlers.end()) { - type = basicIt->type; + auto basicHandler = findIntegratedTypeHandler(metaType); + if (basicHandler) { + type = basicHandler->wireType; int fieldIndex = fieldInfo.getFieldNumber(); - result.append(basicIt->serializer(propertyValue, fieldIndex)); + result.append(basicHandler->serializer(propertyValue, fieldIndex)); if (fieldIndex != QtProtobufPrivate::NotUsedFieldIndex - && type != QtProtobuf::WireTypes::Unknown) { + && type != QtProtobuf::WireTypes::Unknown) { result.prepend(QProtobufSerializerPrivate::encodeHeader(fieldIndex, type)); } } else { @@ -554,9 +613,9 @@ bool QProtobufSerializerPrivate::deserializeProperty(QObject *object, const QtPr QMetaType metaType = metaProperty.metaType(); //TODO: replace with some common function - auto basicIt = handlers.find(metaType); - if (basicIt != handlers.end()) { - basicIt->deserializer(it, newPropertyValue); + auto basicHandler = findIntegratedTypeHandler(metaType); + if (basicHandler) { + basicHandler->deserializer(it, newPropertyValue); } else { auto handler = QtProtobufPrivate::findHandler(metaType); if (!handler.deserializer) { @@ -597,23 +656,24 @@ bool QProtobufSerializerPrivate::deserializeMapPair(QVariant &key, QVariant &val if (mapIndex == 1) { //Only simple types are supported as keys QMetaType metaType = key.metaType(); - auto basicIt = handlers.find(metaType); - if (basicIt == handlers.end()) { + auto basicHandler = findIntegratedTypeHandler(metaType); + if (!basicHandler) { // clang-format off QString errorStr = QCoreApplication::tr("QtProtobuf", - "Either there is no deserializer for type %1 or it is not a builtin type") + "Either there is no deserializer for type " + "%1 or it is not a builtin type") .arg(QLatin1String(key.typeName())); // clang-format on setDeserializationError(QAbstractProtobufSerializer::NoDeserializerError, errorStr); return false; } - basicIt->deserializer(it, key); + basicHandler->deserializer(it, key); } else { //TODO: replace with some common function QMetaType metaType = value.metaType(); - auto basicIt = handlers.find(metaType); - if (basicIt != handlers.end()) { - basicIt->deserializer(it, value); + auto basicHandler = findIntegratedTypeHandler(metaType); + if (basicHandler) { + basicHandler->deserializer(it, value); } else { auto handler = QtProtobufPrivate::findHandler(metaType); if (!handler.deserializer) { @@ -649,6 +709,4 @@ void QProtobufSerializerPrivate::setDeserializationError( deserializationErrorString = errorString; } -QProtobufSerializerPrivate::ProtobufSerializerRegistry QProtobufSerializerPrivate::handlers = {}; - QT_END_NAMESPACE diff --git a/src/protobuf/qprotobufserializer_p.h b/src/protobuf/qprotobufserializer_p.h index 7635b724..670e23cc 100644 --- a/src/protobuf/qprotobufserializer_p.h +++ b/src/protobuf/qprotobufserializer_p.h @@ -48,13 +48,12 @@ public: // SerializationHandlers contains set of objects that required for class serializaion/deserialization struct ProtobufSerializationHandler { + QMetaType metaType; Serializer serializer; // serializer assigned to class Deserializer deserializer; // deserializer assigned to class - QtProtobuf::WireTypes type; // Serialization WireType + QtProtobuf::WireTypes wireType; // Serialization WireType }; - using ProtobufSerializerRegistry = QHash; - explicit QProtobufSerializerPrivate(QProtobufSerializer *q); ~QProtobufSerializerPrivate() = default; //########################################################################### @@ -463,30 +462,6 @@ public: return s(variantValue.value(), fieldIndex); } - template ::value, int> = 0> - static void wrapSerializer() - { - handlers[QMetaType::fromType()] = { - serializeWrapper, - d, - type - }; - } - - template ::value, int> = 0> - static void wrapSerializer() - { - handlers[QMetaType::fromType()] = { - serializeWrapper, - d, - type - }; - } - // this set of 3 methods is used to skip bytes corresponding to an unexpected property // in a serialized message met while the message being deserialized static qsizetype skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, @@ -512,7 +487,6 @@ public: QString deserializationErrorString; private: - static ProtobufSerializerRegistry handlers; QProtobufSerializer *q_ptr; };