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:
Stephen Kelly 2013-05-03 16:10:34 +02:00 committed by The Qt Project
parent 3f46b03a66
commit b88b09fb16
4 changed files with 177 additions and 0 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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"