Make it possible to access QPair and std::pair elements from a QVariant.
Change-Id: I9dc73748073d0d1e43bdadbce73339dfcc1bc647 Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
This commit is contained in:
parent
3f46b03a66
commit
b88b09fb16
@ -298,6 +298,8 @@ struct ConverterFunctor : public AbstractConverterFunction
|
||||
struct ValueTypeIsMetaType;
|
||||
template<typename T, bool>
|
||||
struct AssociativeValueTypeIsMetaType;
|
||||
template<typename T, bool>
|
||||
struct IsMetaTypePair;
|
||||
}
|
||||
|
||||
class Q_CORE_EXPORT QMetaType {
|
||||
@ -536,6 +538,7 @@ private:
|
||||
template<typename T>
|
||||
friend bool qRegisterAssociativeConverter();
|
||||
template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType;
|
||||
template<typename, bool> 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<class T>
|
||||
static VariantData getFirstImpl(const void * const *pair, int metaTypeId, uint flags)
|
||||
{ return VariantData(metaTypeId, &static_cast<const T*>(*pair)->first, flags); }
|
||||
template<class T>
|
||||
static VariantData getSecondImpl(const void * const *pair, int metaTypeId, uint flags)
|
||||
{ return VariantData(metaTypeId, &static_cast<const T*>(*pair)->second, flags); }
|
||||
|
||||
public:
|
||||
template<class T> QPairVariantInterfaceImpl(const T*p)
|
||||
: _pair(p)
|
||||
, _metaType_id_first(qMetaTypeId<typename T::first_type>())
|
||||
, _metaType_flags_first(QTypeInfo<typename T::first_type>::isPointer)
|
||||
, _metaType_id_second(qMetaTypeId<typename T::second_type>())
|
||||
, _metaType_flags_second(QTypeInfo<typename T::second_type>::isPointer)
|
||||
, _getFirst(getFirstImpl<T>)
|
||||
, _getSecond(getSecondImpl<T>)
|
||||
{
|
||||
}
|
||||
|
||||
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<typename From>
|
||||
struct QPairVariantInterfaceConvertFunctor;
|
||||
|
||||
template<typename T, typename U>
|
||||
struct QPairVariantInterfaceConvertFunctor<QPair<T, U> >
|
||||
{
|
||||
QPairVariantInterfaceConvertFunctor() {}
|
||||
|
||||
QPairVariantInterfaceImpl operator()(const QPair<T, U>& f) const
|
||||
{
|
||||
return QPairVariantInterfaceImpl(&f);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct QPairVariantInterfaceConvertFunctor<std::pair<T, U> >
|
||||
{
|
||||
QPairVariantInterfaceConvertFunctor() {}
|
||||
|
||||
QPairVariantInterfaceImpl operator()(const std::pair<T, U>& f) const
|
||||
{
|
||||
return QPairVariantInterfaceImpl(&f);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class QObject;
|
||||
@ -1261,6 +1333,49 @@ namespace QtPrivate
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T, bool = QMetaTypeId2<typename T::first_type>::Defined
|
||||
&& QMetaTypeId2<typename T::second_type>::Defined>
|
||||
struct IsMetaTypePair
|
||||
{
|
||||
static bool registerConverter(int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsMetaTypePair<T, true>
|
||||
{
|
||||
static bool registerConverter(int id)
|
||||
{
|
||||
const int toId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
|
||||
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
|
||||
static const QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
|
||||
static const QtPrivate::ConverterFunctor<T,
|
||||
QtMetaTypePrivate::QPairVariantInterfaceImpl,
|
||||
QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> > f(o);
|
||||
return QMetaType::registerConverterFunction(&f, id, toId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsPair
|
||||
{
|
||||
static bool registerConverter(int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
template<typename T, typename U>
|
||||
struct IsPair<QPair<T, U> > : IsMetaTypePair<QPair<T, U> > {};
|
||||
template<typename T, typename U>
|
||||
struct IsPair<std::pair<T, U> > : IsMetaTypePair<std::pair<T, U> > {};
|
||||
|
||||
template<typename T>
|
||||
struct MetaTypePairHelper : IsPair<T> {};
|
||||
|
||||
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<T>::registerConverter(id);
|
||||
QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id);
|
||||
QtPrivate::MetaTypePairHelper<T>::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
|
||||
|
||||
|
@ -2782,6 +2782,12 @@ bool QVariant::canConvert(int targetTypeId) const
|
||||
return true;
|
||||
}
|
||||
|
||||
if (targetTypeId == qMetaTypeId<QPair<QVariant, QVariant> >() &&
|
||||
QMetaType::hasRegisteredConverterFunction(d.type,
|
||||
qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((d.type >= QMetaType::User || targetTypeId >= QMetaType::User)
|
||||
&& QMetaType::hasRegisteredConverterFunction(d.type, targetTypeId)) {
|
||||
return true;
|
||||
|
@ -832,6 +832,32 @@ namespace QtPrivate {
|
||||
return QVariantValueHelper<QVariantMap>::invoke(v);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct QVariantValueHelperInterface<QPair<QVariant, QVariant> >
|
||||
{
|
||||
static QPair<QVariant, QVariant> invoke(const QVariant &v)
|
||||
{
|
||||
if (v.userType() == qMetaTypeId<QPair<QVariant, QVariant> >())
|
||||
return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v);
|
||||
|
||||
if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) {
|
||||
QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
|
||||
|
||||
const QtMetaTypePrivate::VariantData d1 = pi.first();
|
||||
QVariant v1(d1.metaTypeId, d1.data, d1.flags);
|
||||
if (d1.metaTypeId == qMetaTypeId<QVariant>())
|
||||
v1 = *reinterpret_cast<const QVariant*>(d1.data);
|
||||
|
||||
const QtMetaTypePrivate::VariantData d2 = pi.second();
|
||||
QVariant v2(d2.metaTypeId, d2.data, d2.flags);
|
||||
if (d2.metaTypeId == qMetaTypeId<QVariant>())
|
||||
v2 = *reinterpret_cast<const QVariant*>(d2.data);
|
||||
|
||||
return QPair<QVariant, QVariant>(v1, v2);
|
||||
}
|
||||
return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T> inline T qvariant_cast(const QVariant &v)
|
||||
|
@ -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<QVariant, QVariant> QVariantPair;
|
||||
|
||||
#define TEST_PAIR_ELEMENT_ACCESS(PAIR, T1, T2, VALUE1, VALUE2) \
|
||||
{ \
|
||||
PAIR<T1, T2> p(VALUE1, VALUE2); \
|
||||
QVariant v = QVariant::fromValue(p); \
|
||||
\
|
||||
QVERIFY(v.canConvert<QVariantPair>()); \
|
||||
QVariantPair pi = v.value<QVariantPair>(); \
|
||||
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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user