summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2015-01-09 11:55:43 +0100
committerAlex Blasche <alexander.blasche@theqtcompany.com>2015-01-13 12:18:47 +0100
commit0d4485fd78d5a14797c3511ecf808fcfa0768ac9 (patch)
tree0179c758de2113537aed53d601ce7d6425fdfe42
parent8fdd1bb8cb68332db605c9f250c64dd114747c45 (diff)
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>
-rw-r--r--src/corelib/kernel/qmetatype.cpp35
-rw-r--r--src/corelib/kernel/qmetatype.h29
-rw-r--r--src/corelib/kernel/qvariant.cpp2
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp90
4 files changed, 152 insertions, 4 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 294b1fc07c..aae772ffeb 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -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;
}
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 5b8c5a6b3d..2ff695b833 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -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*);
@@ -530,6 +548,16 @@ public:
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()
{
return hasRegisteredComparators(qMetaTypeId<T>());
@@ -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>
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 1e71bb8978..3f958138b3 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -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);
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
index e3ef2b6714..6e2b623a9f 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
@@ -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)