Support QMetaType::equals()
This avoids having to define operator< for types where operator== is required but operator< doesn't make any sense (e.g. QGeoCoordinate). Change-Id: I81f6a9d8fc0009a4514c974b5e02b446c50d1e31 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
parent
8fdd1bb8cb
commit
0d4485fd78
@ -577,11 +577,19 @@ Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
|
||||
/*!
|
||||
\fn bool QMetaType::registerComparators()
|
||||
\since 5.2
|
||||
Registers comparison operetarors for the user-registered type T. This requires T to have
|
||||
Registers comparison operators for the user-registered type T. This requires T to have
|
||||
both an operator== and an operator<.
|
||||
Returns \c true if the registration succeeded, otherwise false.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::registerEqualsComparator()
|
||||
\since 5.5
|
||||
Registers equals operator for the user-registered type T. This requires T to have
|
||||
an operator==.
|
||||
Returns \c true if the registration succeeded, otherwise false.
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
/*!
|
||||
\fn bool QMetaType::registerDebugStreamOperator()
|
||||
@ -687,7 +695,7 @@ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId
|
||||
/*!
|
||||
Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId.
|
||||
\a result is set to less than, equal to or greater than zero, if \a lhs is less than, equal to
|
||||
or greater than \a rhs. Returns \c true, if the comparison succeeded, otherwiess false.
|
||||
or greater than \a rhs. Returns \c true, if the comparison succeeded, otherwise \c false.
|
||||
\since 5.2
|
||||
*/
|
||||
bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result)
|
||||
@ -698,8 +706,29 @@ bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* resul
|
||||
return false;
|
||||
if (f->equals(f, lhs, rhs))
|
||||
*result = 0;
|
||||
else
|
||||
else if (f->lessThan)
|
||||
*result = f->lessThan(f, lhs, rhs) ? -1 : 1;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId.
|
||||
\a result is set to zero, if \a lhs equals to rhs. Returns \c true, if the comparison
|
||||
succeeded, otherwise \c false.
|
||||
\since 5.5
|
||||
*/
|
||||
bool QMetaType::equals(const void *lhs, const void *rhs, int typeId, int *result)
|
||||
{
|
||||
const QtPrivate::AbstractComparatorFunction * const f
|
||||
= customTypesComparatorRegistry()->function(typeId);
|
||||
if (!f)
|
||||
return false;
|
||||
if (f->equals(f, lhs, rhs))
|
||||
*result = 0;
|
||||
else
|
||||
*result = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,24 @@ struct BuiltInComparatorFunction : public AbstractComparatorFunction
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct BuiltInEqualsComparatorFunction : public AbstractComparatorFunction
|
||||
{
|
||||
BuiltInEqualsComparatorFunction()
|
||||
: AbstractComparatorFunction(0, equals, destroy) {}
|
||||
static bool equals(const AbstractComparatorFunction *, const void *l, const void *r)
|
||||
{
|
||||
const T *lhs = static_cast<const T *>(l);
|
||||
const T *rhs = static_cast<const T *>(r);
|
||||
return *lhs == *rhs;
|
||||
}
|
||||
|
||||
static void destroy(AbstractComparatorFunction *_this)
|
||||
{
|
||||
delete static_cast<BuiltInEqualsComparatorFunction *>(_this);
|
||||
}
|
||||
};
|
||||
|
||||
struct AbstractConverterFunction
|
||||
{
|
||||
typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*);
|
||||
@ -529,6 +547,16 @@ public:
|
||||
static const QtPrivate::BuiltInComparatorFunction<T> f;
|
||||
return registerComparatorFunction( &f, typeId);
|
||||
}
|
||||
template<typename T>
|
||||
static bool registerEqualsComparator()
|
||||
{
|
||||
Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn),
|
||||
"QMetaType::registerEqualsComparator: The type must be a custom type.");
|
||||
const int typeId = qMetaTypeId<T>();
|
||||
static const QtPrivate::BuiltInEqualsComparatorFunction<T> f;
|
||||
return registerComparatorFunction( &f, typeId);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool hasRegisteredComparators()
|
||||
{
|
||||
@ -610,6 +638,7 @@ public:
|
||||
|
||||
static bool convert(const void *from, int fromTypeId, void *to, int toTypeId);
|
||||
static bool compare(const void *lhs, const void *rhs, int typeId, int* result);
|
||||
static bool equals(const void *lhs, const void *rhs, int typeId, int* result);
|
||||
static bool debugStream(QDebug& dbg, const void *rhs, int typeId);
|
||||
|
||||
template<typename From, typename To>
|
||||
|
@ -3313,7 +3313,7 @@ bool QVariant::cmp(const QVariant &v) const
|
||||
}
|
||||
if (v1.d.type >= QMetaType::User) {
|
||||
int result;
|
||||
if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result))
|
||||
if (QMetaType::equals(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result))
|
||||
return result == 0;
|
||||
}
|
||||
return handlerManager[v1.d.type]->compare(&v1.d, &v2.d);
|
||||
|
@ -121,6 +121,7 @@ private slots:
|
||||
void convertCustomType();
|
||||
void compareCustomType_data();
|
||||
void compareCustomType();
|
||||
void compareCustomEqualOnlyType();
|
||||
void customDebugStream();
|
||||
};
|
||||
|
||||
@ -2003,9 +2004,23 @@ bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2
|
||||
bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
|
||||
{ return !operator==(lhs, rhs); }
|
||||
|
||||
|
||||
struct CustomEqualsOnlyType
|
||||
{
|
||||
explicit CustomEqualsOnlyType(int value = 0) : val(value) {}
|
||||
virtual ~CustomEqualsOnlyType() {}
|
||||
|
||||
int val;
|
||||
};
|
||||
bool operator==(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs)
|
||||
{ return lhs.val == rhs.val;}
|
||||
bool operator!=(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs)
|
||||
{ return !operator==(lhs, rhs); }
|
||||
|
||||
Q_DECLARE_METATYPE(CustomConvertibleType);
|
||||
Q_DECLARE_METATYPE(CustomConvertibleType2);
|
||||
Q_DECLARE_METATYPE(CustomDebugStreamableType);
|
||||
Q_DECLARE_METATYPE(CustomEqualsOnlyType);
|
||||
|
||||
template<typename T, typename U>
|
||||
U convert(const T &t)
|
||||
@ -2282,6 +2297,81 @@ void tst_QMetaType::compareCustomType()
|
||||
QCOMPARE(unsorted, sorted);
|
||||
}
|
||||
|
||||
void tst_QMetaType::compareCustomEqualOnlyType()
|
||||
{
|
||||
int metaTypeId = qRegisterMetaType<CustomEqualsOnlyType>();
|
||||
QMetaType::registerEqualsComparator<CustomEqualsOnlyType>();
|
||||
int result;
|
||||
|
||||
CustomEqualsOnlyType val50(50);
|
||||
CustomEqualsOnlyType val100(100);
|
||||
CustomEqualsOnlyType val100x(100);
|
||||
|
||||
QVariant variant50 = QVariant::fromValue(val50);
|
||||
QVariant variant100 = QVariant::fromValue(val100);
|
||||
QVariant variant100x = QVariant::fromValue(val100x);
|
||||
|
||||
QVERIFY(variant50 != variant100);
|
||||
QVERIFY(variant50 != variant100x);
|
||||
QVERIFY(variant100 != variant50);
|
||||
QVERIFY(variant100x != variant50);
|
||||
QVERIFY(variant100 == variant100x);
|
||||
QVERIFY(variant100 == variant100);
|
||||
|
||||
// compare always fails
|
||||
QVERIFY(!(variant50 < variant50));
|
||||
QVERIFY(!(variant50 < variant100));
|
||||
QVERIFY(!(variant100 < variant50));
|
||||
|
||||
// check QMetaType::compare works/doesn't crash for equals only comparators
|
||||
bool wasSuccess = QMetaType::compare(variant50.constData(), variant50.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, 0);
|
||||
QVERIFY(wasSuccess);
|
||||
wasSuccess = QMetaType::compare(variant100.constData(), variant100x.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, 0);
|
||||
QVERIFY(wasSuccess);
|
||||
|
||||
wasSuccess = QMetaType::compare(variant50.constData(), variant100.constData(),
|
||||
metaTypeId, &result);
|
||||
QVERIFY(!wasSuccess);
|
||||
|
||||
// check QMetaType::equals works for equals only comparator
|
||||
wasSuccess = QMetaType::equals(variant50.constData(), variant50.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, 0);
|
||||
QVERIFY(wasSuccess);
|
||||
wasSuccess = QMetaType::equals(variant100.constData(), variant100.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, 0);
|
||||
QVERIFY(wasSuccess);
|
||||
wasSuccess = QMetaType::equals(variant100x.constData(), variant100x.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, 0);
|
||||
QVERIFY(wasSuccess);
|
||||
wasSuccess = QMetaType::equals(variant100.constData(), variant100x.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, 0);
|
||||
QVERIFY(wasSuccess);
|
||||
wasSuccess = QMetaType::equals(variant50.constData(), variant100.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, -1);
|
||||
QVERIFY(wasSuccess);
|
||||
wasSuccess = QMetaType::equals(variant50.constData(), variant100x.constData(),
|
||||
metaTypeId, &result);
|
||||
QCOMPARE(result, -1);
|
||||
QVERIFY(wasSuccess);
|
||||
|
||||
//check QMetaType::equals for type w/o equals comparator being registered
|
||||
CustomMovable movable1;
|
||||
CustomMovable movable2;
|
||||
wasSuccess = QMetaType::equals(&movable1, &movable2,
|
||||
qRegisterMetaType<CustomMovable>(), &result);
|
||||
QVERIFY(!wasSuccess);
|
||||
|
||||
}
|
||||
|
||||
struct MessageHandlerCustom : public MessageHandler
|
||||
{
|
||||
MessageHandlerCustom(const int typeId)
|
||||
|
Loading…
x
Reference in New Issue
Block a user