From c7ce1bc05c1ec2f63dd2531f23a3e9f6fe866556 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 14 Jul 2020 14:25:18 +0200 Subject: [PATCH] Move conversions to and from *Iterables into QMetaType Those were not yet supported by QMetaType. Change-Id: I9f85476049f200e35939ac58ef7e8b4e7cbe0b77 Reviewed-by: Fabian Kosmale Reviewed-by: Lars Knoll --- src/corelib/kernel/qmetatype.cpp | 198 +++++++++++++++++- src/corelib/kernel/qmetatype.h | 7 +- src/corelib/kernel/qvariant.cpp | 21 -- src/corelib/kernel/qvariant.h | 118 +---------- .../corelib/kernel/qmetatype/tst_qmetatype.h | 4 + 5 files changed, 200 insertions(+), 148 deletions(-) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index e8f359a366..072b27b573 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1152,6 +1152,19 @@ static const struct : QMetaTypeModuleHelper QMETATYPE_CONVERTER_ASSIGN(QPointF, QPoint); #endif + QMETATYPE_CONVERTER(QByteArrayList, QVariantList, + result.reserve(source.size()); + for (auto v: source) + result.append(v.toByteArray()); + return true; + ); + QMETATYPE_CONVERTER(QVariantList, QByteArrayList, + result.reserve(source.size()); + for (auto v: source) + result.append(QVariant(v)); + return true; + ); + QMETATYPE_CONVERTER(QStringList, QVariantList, result.reserve(source.size()); for (auto v: source) @@ -1829,6 +1842,142 @@ static bool convertToEnum(const void *from, int fromTypeId, void *to, const QMet } } +static bool convertIterableToVariantList(const void *from, int fromTypeId, void *to) +{ + const QMetaType::ConverterFunction * const f = + customTypesConversionRegistry()->function(qMakePair(fromTypeId, + qMetaTypeId())); + if (!f) + return false; + + QtMetaTypePrivate::QSequentialIterableImpl iter; + (*f)(from, &iter); + QSequentialIterable list(iter); + QVariantList &l = *static_cast(to); + l.clear(); + l.reserve(list.size()); + auto end = list.end(); + for (auto it = list.begin(); it != end; ++it) + l << *it; + return true; +} + +static bool convertIterableToVariantMap(const void *from, int fromTypeId, void *to) +{ + const QMetaType::ConverterFunction * const f = + customTypesConversionRegistry()->function(qMakePair(fromTypeId, + qMetaTypeId())); + if (!f) + return false; + + QtMetaTypePrivate::QAssociativeIterableImpl iter; + (*f)(from, &iter); + QAssociativeIterable map(iter); + QVariantMap &h = *static_cast(to); + h.clear(); + auto end = map.end(); + for (auto it = map.begin(); it != end; ++it) + h.insert(it.key().toString(), it.value()); + return true; +} + +static bool convertIterableToVariantHash(const void *from, int fromTypeId, void *to) +{ + const QMetaType::ConverterFunction * const f = + customTypesConversionRegistry()->function(qMakePair(fromTypeId, + qMetaTypeId())); + if (!f) + return false; + + QtMetaTypePrivate::QAssociativeIterableImpl iter; + (*f)(from, &iter); + QAssociativeIterable map(iter); + QVariantHash &h = *static_cast(to); + h.clear(); + h.reserve(map.size()); + auto end = map.end(); + for (auto it = map.begin(); it != end; ++it) + h.insert(it.key().toString(), it.value()); + return true; +} + +static bool convertIterableToVariantPair(const void *from, int fromTypeId, void *to) +{ + const QMetaType::ConverterFunction * const f = + customTypesConversionRegistry()->function(qMakePair(fromTypeId, + qMetaTypeId())); + if (!f) + return false; + + QtMetaTypePrivate::QPairVariantInterfaceImpl pi; + (*f)(from, &pi); + + QVariant v1(pi._metaType_first); + void *dataPtr; + if (pi._metaType_first == QMetaType::fromType()) + dataPtr = &v1; + else + dataPtr = v1.data(); + pi.first(dataPtr); + + QVariant v2(pi._metaType_second); + if (pi._metaType_second == QMetaType::fromType()) + dataPtr = &v2; + else + dataPtr = v2.data(); + pi.second(dataPtr); + + *static_cast(to) = QVariantPair(v1, v2); + return true; +} + +static bool convertToSequentialIterable(const void *from, int fromTypeId, void *to) +{ + using namespace QtMetaTypePrivate; + + QSequentialIterable &i = *static_cast(to); + if (fromTypeId == QMetaType::QVariantList) { + i = QSequentialIterable(QSequentialIterableImpl(reinterpret_cast(from))); + return true; + } + if (fromTypeId == QMetaType::QStringList) { + i = QSequentialIterable(QSequentialIterableImpl(reinterpret_cast(from))); + return true; + } + else if (fromTypeId == QMetaType::QByteArrayList) { + i = QSequentialIterable(QSequentialIterableImpl(reinterpret_cast(from))); + return true; + } + QSequentialIterableImpl impl; + if (QMetaType::convert(from, fromTypeId, &impl, qMetaTypeId())) { + i = QSequentialIterable(impl); + return true; + } + return false; +} + +static bool convertToAssociativeIterable(const void *from, int fromTypeId, void *to) +{ + using namespace QtMetaTypePrivate; + + QAssociativeIterable &i = *static_cast(to); + if (fromTypeId == QMetaType::QVariantMap) { + i = QAssociativeIterable(QAssociativeIterableImpl(reinterpret_cast(from))); + return true; + } + if (fromTypeId == QMetaType::QVariantHash) { + i = QAssociativeIterable(QAssociativeIterableImpl(reinterpret_cast(from))); + return true; + } + QAssociativeIterableImpl impl; + if (QMetaType::convert(from, fromTypeId, &impl, qMetaTypeId())) { + i = QAssociativeIterable(impl); + return true; + } + return false; +} + + #ifndef QT_BOOTSTRAPPED static bool canConvertMetaObject(const QMetaType &fromType, const QMetaType &toType) { @@ -1840,7 +1989,6 @@ static bool canConvertMetaObject(const QMetaType &fromType, const QMetaType &toT } #endif - /*! Converts the object at \a from from \a fromTypeId to the preallocated space at \a to typed \a toTypeId. Returns \c true, if the conversion succeeded, otherwise false. @@ -1880,6 +2028,26 @@ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId return true; } } + + // handle iterables + if (toTypeId == QVariantList && convertIterableToVariantList(from, fromTypeId, to)) + return true; + + if (toTypeId == QVariantMap && convertIterableToVariantMap(from, fromTypeId, to)) + return true; + + if (toTypeId == QVariantHash && convertIterableToVariantHash(from, fromTypeId, to)) + return true; + + if (toTypeId == QVariantPair && convertIterableToVariantPair(from, fromTypeId, to)) + return true; + + if (toTypeId == qMetaTypeId()) + return convertToSequentialIterable(from, fromTypeId, to); + + if (toTypeId == qMetaTypeId()) + return convertToAssociativeIterable(from, fromTypeId, to); + return false; } @@ -1969,22 +2137,34 @@ bool QMetaType::canConvert(const QMetaType &fromType, const QMetaType &toType) if (moduleHelper->convert(nullptr, fromTypeId, nullptr, toTypeId)) return true; } - const QMetaType::ConverterFunction * const f = + const ConverterFunction * const f = customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); if (f) return true; - if (fromType.flags() & QMetaType::IsEnumeration) { - if (toTypeId == QMetaType::QString || toTypeId == QMetaType::QByteArray) + if (toTypeId == QVariantList && hasRegisteredConverterFunction( + fromTypeId, qMetaTypeId())) + return true; + + if ((toTypeId == QVariantHash || toTypeId == QVariantMap) && hasRegisteredConverterFunction( + fromTypeId, qMetaTypeId())) + return true; + + if (toTypeId == QVariantPair && hasRegisteredConverterFunction( + fromTypeId, qMetaTypeId())) + return true; + + if (fromType.flags() & IsEnumeration) { + if (toTypeId == QString || toTypeId == QByteArray) return true; - return QMetaType::canConvert(QMetaType(LongLong), toType); + return canConvert(QMetaType(LongLong), toType); } - if (toType.flags() & QMetaType::IsEnumeration) { - if (fromTypeId == QMetaType::QString || fromTypeId == QMetaType::QByteArray) + if (toType.flags() & IsEnumeration) { + if (fromTypeId == QString || fromTypeId == QByteArray) return true; - return QMetaType::canConvert(fromType, QMetaType(LongLong)); + return canConvert(fromType, QMetaType(LongLong)); } - if (toTypeId == Nullptr && fromType.flags() & QMetaType::IsPointer) + if (toTypeId == Nullptr && fromType.flags() & IsPointer) return true; #ifndef QT_BOOTSTRAPPED if (canConvertMetaObject(fromType, toType)) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 4a3ed1affc..62d2fd82a1 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -162,6 +162,7 @@ inline constexpr int qMetaTypeId(); F(QVariantMap, 8, QVariantMap) \ F(QVariantList, 9, QVariantList) \ F(QVariantHash, 28, QVariantHash) \ + F(QVariantPair, 58, QVariantPair) \ F(QByteArrayList, 49, QByteArrayList) \ #if QT_CONFIG(shortcut) @@ -219,6 +220,7 @@ inline constexpr int qMetaTypeId(); F(QVariantList, -1, QVariantList, "QList") \ F(QVariantMap, -1, QVariantMap, "QMap") \ F(QVariantHash, -1, QVariantHash, "QHash") \ + F(QVariantPair, -1, QVariantPair, "QPair") \ F(QByteArrayList, -1, QByteArrayList, "QList") \ #define QT_FOR_EACH_STATIC_TYPE(F)\ @@ -295,7 +297,7 @@ public: QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID) FirstCoreType = Bool, - LastCoreType = Char32, + LastCoreType = QVariantPair, FirstGuiType = QFont, LastGuiType = QColorSpace, FirstWidgetsType = QSizePolicy, @@ -337,7 +339,7 @@ public: // Widget types QSizePolicy = 121, - LastCoreType = QCborMap, + LastCoreType = Char32, LastGuiType = QColorSpace, User = 1024 }; @@ -1704,6 +1706,7 @@ QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER) typedef QList QVariantList; typedef QMap QVariantMap; typedef QHash QVariantHash; +typedef QPair QVariantPair; #ifdef Q_CLANG_QDOC class QByteArrayList; #else diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index c16e4a0e06..6a046dffd3 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1974,27 +1974,6 @@ bool QVariant::canConvert(int targetTypeId) const if (d.typeId() == targetTypeId && targetTypeId != QMetaType::UnknownType) return true; - if (targetTypeId == QMetaType::QVariantList - && (d.typeId() == QMetaType::QVariantList || d.typeId() == QMetaType::QStringList - || d.typeId() == QMetaType::QByteArrayList - || QMetaType::hasRegisteredConverterFunction( - d.typeId(), qMetaTypeId()))) { - return true; - } - - if ((targetTypeId == QMetaType::QVariantHash || targetTypeId == QMetaType::QVariantMap) - && (d.typeId() == QMetaType::QVariantMap || d.typeId() == QMetaType::QVariantHash - || QMetaType::hasRegisteredConverterFunction( - d.typeId(), qMetaTypeId()))) { - return true; - } - - if (targetTypeId == qMetaTypeId>() - && QMetaType::hasRegisteredConverterFunction( - d.typeId(), qMetaTypeId())) { - return true; - } - return QMetaType::canConvert(d.type(), QMetaType(targetTypeId)); } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 258dac3bbc..218b88cb4a 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -655,6 +655,7 @@ public: friend struct const_iterator; explicit QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl); + QSequentialIterable() {} const_iterator begin() const; const_iterator end() const; @@ -709,6 +710,7 @@ public: friend struct const_iterator; explicit QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl); + QAssociativeIterable() {} const_iterator begin() const; const_iterator end() const; @@ -748,122 +750,6 @@ namespace QtPrivate { struct QVariantValueHelperInterface : QVariantValueHelper { }; - - template<> - struct QVariantValueHelperInterface - { - static QSequentialIterable invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId()) { - return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); - } - if (typeId == qMetaTypeId()) { - return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); - } -#ifndef QT_BOOTSTRAPPED - if (typeId == qMetaTypeId()) { - return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); - } -#endif - return QSequentialIterable(qvariant_cast(v)); - } - }; - template<> - struct QVariantValueHelperInterface - { - static QAssociativeIterable invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId()) { - return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast(v.constData()))); - } - if (typeId == qMetaTypeId()) { - return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast(v.constData()))); - } - return QAssociativeIterable(qvariant_cast(v)); - } - }; - template<> - struct QVariantValueHelperInterface - { - static QVariantList invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId() || typeId == qMetaTypeId() || - (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()))) { - QSequentialIterable iter = QVariantValueHelperInterface::invoke(v); - QVariantList l; - l.reserve(iter.size()); - for (QSequentialIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l << *it; - return l; - } - return QVariantValueHelper::invoke(v); - } - }; - template<> - struct QVariantValueHelperInterface - { - static QVariantHash invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId() || ((QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId())) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()))) { - QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); - QVariantHash l; - l.reserve(iter.size()); - for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l.insert(it.key().toString(), it.value()); - return l; - } - return QVariantValueHelper::invoke(v); - } - }; - template<> - struct QVariantValueHelperInterface - { - static QVariantMap invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId() || (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()))) { - QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); - QVariantMap l; - for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l.insert(it.key().toString(), it.value()); - return l; - } - return QVariantValueHelper::invoke(v); - } - }; - template<> - struct QVariantValueHelperInterface > - { - static QPair invoke(const QVariant &v) - { - const int typeId = v.userType(); - - if (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()) && !(typeId == qMetaTypeId >())) { - QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value(); - QVariant v1(pi._metaType_first); - void *dataPtr; - if (pi._metaType_first == QMetaType::fromType()) - dataPtr = &v1; - else - dataPtr = v1.data(); - pi.first(dataPtr); - - QVariant v2(pi._metaType_second); - if (pi._metaType_second == QMetaType::fromType()) - dataPtr = &v2; - else - dataPtr = v2.data(); - pi.second(dataPtr); - - return QPair(v1, v2); - } - return QVariantValueHelper >::invoke(v); - } - }; } template inline T qvariant_cast(const QVariant &v) diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h index 3f00db5519..43a099de17 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h @@ -121,6 +121,10 @@ template<> struct TestValueFactory { template<> struct TestValueFactory { static QVariantHash *create() { return new QVariantHash(); } }; +template<> struct TestValueFactory { + static QVariantPair *create() { return new QVariantPair(); } +}; + template<> struct TestValueFactory { static QVariantList *create() { return new QVariantList(QVariantList() << 123 << "Q" << "Variant" << "List"); } };