diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index ef741aeff9d..a6e87bdb120 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -298,6 +298,8 @@ struct ConverterFunctor : public AbstractConverterFunction struct ValueTypeIsMetaType; template struct AssociativeValueTypeIsMetaType; + template + struct IsMetaTypePair; } class Q_CORE_EXPORT QMetaType { @@ -536,6 +538,7 @@ private: template friend bool qRegisterAssociativeConverter(); template friend struct QtPrivate::AssociativeValueTypeIsMetaType; + template friend struct QtPrivate::IsMetaTypePair; #endif #else public: @@ -1046,6 +1049,75 @@ struct QAssociativeIterableConvertFunctor return QAssociativeIterableImpl(&f); } }; + +class QPairVariantInterfaceImpl +{ + const void *_pair; + int _metaType_id_first; + uint _metaType_flags_first; + int _metaType_id_second; + uint _metaType_flags_second; + + typedef VariantData (*getFunc)(const void * const *p, int metaTypeId, uint flags); + + getFunc _getFirst; + getFunc _getSecond; + + template + static VariantData getFirstImpl(const void * const *pair, int metaTypeId, uint flags) + { return VariantData(metaTypeId, &static_cast(*pair)->first, flags); } + template + static VariantData getSecondImpl(const void * const *pair, int metaTypeId, uint flags) + { return VariantData(metaTypeId, &static_cast(*pair)->second, flags); } + +public: + template QPairVariantInterfaceImpl(const T*p) + : _pair(p) + , _metaType_id_first(qMetaTypeId()) + , _metaType_flags_first(QTypeInfo::isPointer) + , _metaType_id_second(qMetaTypeId()) + , _metaType_flags_second(QTypeInfo::isPointer) + , _getFirst(getFirstImpl) + , _getSecond(getSecondImpl) + { + } + + QPairVariantInterfaceImpl() + : _pair(0) + , _getFirst(0) + , _getSecond(0) + { + } + + inline VariantData first() const { return _getFirst(&_pair, _metaType_id_first, _metaType_flags_first); } + inline VariantData second() const { return _getSecond(&_pair, _metaType_id_second, _metaType_flags_second); } +}; + +template +struct QPairVariantInterfaceConvertFunctor; + +template +struct QPairVariantInterfaceConvertFunctor > +{ + QPairVariantInterfaceConvertFunctor() {} + + QPairVariantInterfaceImpl operator()(const QPair& f) const + { + return QPairVariantInterfaceImpl(&f); + } +}; + +template +struct QPairVariantInterfaceConvertFunctor > +{ + QPairVariantInterfaceConvertFunctor() {} + + QPairVariantInterfaceImpl operator()(const std::pair& f) const + { + return QPairVariantInterfaceImpl(&f); + } +}; + } class QObject; @@ -1261,6 +1333,49 @@ namespace QtPrivate { }; + template::Defined + && QMetaTypeId2::Defined> + struct IsMetaTypePair + { + static bool registerConverter(int) + { + return false; + } + }; + + template + struct IsMetaTypePair + { + static bool registerConverter(int id) + { + const int toId = qMetaTypeId(); + if (!QMetaType::hasRegisteredConverterFunction(id, toId)) { + static const QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor o; + static const QtPrivate::ConverterFunctor > f(o); + return QMetaType::registerConverterFunction(&f, id, toId); + } + return true; + } + }; + + template + struct IsPair + { + static bool registerConverter(int) + { + return false; + } + }; + template + struct IsPair > : IsMetaTypePair > {}; + template + struct IsPair > : IsMetaTypePair > {}; + + template + struct MetaTypePairHelper : IsPair {}; + Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type); } // namespace QtPrivate @@ -1362,6 +1477,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz if (id > 0) { QtPrivate::SequentialContainerConverterHelper::registerConverter(id); QtPrivate::AssociativeContainerConverterHelper::registerConverter(id); + QtPrivate::MetaTypePairHelper::registerConverter(id); } return id; @@ -1746,6 +1862,7 @@ QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE) Q_DECLARE_METATYPE(QtMetaTypePrivate::QSequentialIterableImpl) Q_DECLARE_METATYPE(QtMetaTypePrivate::QAssociativeIterableImpl) +Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl) QT_BEGIN_NAMESPACE diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 37b89b82f05..f747eb45ab0 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2782,6 +2782,12 @@ bool QVariant::canConvert(int targetTypeId) const return true; } + if (targetTypeId == qMetaTypeId >() && + QMetaType::hasRegisteredConverterFunction(d.type, + qMetaTypeId())) { + return true; + } + if ((d.type >= QMetaType::User || targetTypeId >= QMetaType::User) && QMetaType::hasRegisteredConverterFunction(d.type, targetTypeId)) { return true; diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 271aaf13cec..4832a633f85 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -832,6 +832,32 @@ namespace QtPrivate { return QVariantValueHelper::invoke(v); } }; + template<> + struct QVariantValueHelperInterface > + { + static QPair invoke(const QVariant &v) + { + if (v.userType() == qMetaTypeId >()) + return QVariantValueHelper >::invoke(v); + + if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId())) { + QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value(); + + const QtMetaTypePrivate::VariantData d1 = pi.first(); + QVariant v1(d1.metaTypeId, d1.data, d1.flags); + if (d1.metaTypeId == qMetaTypeId()) + v1 = *reinterpret_cast(d1.data); + + const QtMetaTypePrivate::VariantData d2 = pi.second(); + QVariant v2(d2.metaTypeId, d2.data, d2.flags); + if (d2.metaTypeId == qMetaTypeId()) + v2 = *reinterpret_cast(d2.data); + + return QPair(v1, v2); + } + return QVariantValueHelper >::invoke(v); + } + }; } template inline T qvariant_cast(const QVariant &v) diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 546b90e164d..eceeed51e74 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -241,6 +241,7 @@ private slots: void implicitConstruction(); void iterateContainerElements(); + void pairElements(); private: void dataStream_data(QDataStream::Version version); void loadQVariantFromDataStream(QDataStream::Version version); @@ -3632,5 +3633,32 @@ void tst_QVariant::iterateContainerElements() #endif } +void tst_QVariant::pairElements() +{ + typedef QPair QVariantPair; + +#define TEST_PAIR_ELEMENT_ACCESS(PAIR, T1, T2, VALUE1, VALUE2) \ + { \ + PAIR p(VALUE1, VALUE2); \ + QVariant v = QVariant::fromValue(p); \ + \ + QVERIFY(v.canConvert()); \ + QVariantPair pi = v.value(); \ + QCOMPARE(pi.first, QVariant::fromValue(VALUE1)); \ + QCOMPARE(pi.second, QVariant::fromValue(VALUE2)); \ + } + + TEST_PAIR_ELEMENT_ACCESS(QPair, int, int, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(std::pair, int, int, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(QPair, QString, QString, QStringLiteral("one"), QStringLiteral("two")) + TEST_PAIR_ELEMENT_ACCESS(std::pair, QString, QString, QStringLiteral("one"), QStringLiteral("two")) + TEST_PAIR_ELEMENT_ACCESS(QPair, QVariant, QVariant, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(std::pair, QVariant, QVariant, 4, 5) + TEST_PAIR_ELEMENT_ACCESS(QPair, QVariant, int, 41, 15) + TEST_PAIR_ELEMENT_ACCESS(std::pair, QVariant, int, 34, 65) + TEST_PAIR_ELEMENT_ACCESS(QPair, int, QVariant, 24, 25) + TEST_PAIR_ELEMENT_ACCESS(std::pair, int, QVariant, 44, 15) +} + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc"