summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-06-29 14:26:36 +0200
committerLars Knoll <lars.knoll@qt.io>2020-07-08 14:13:59 +0200
commit986d89c2eefd37ee0da8e07d7794716000608610 (patch)
tree5e709f713cacdf0bfac7ddb95d14e1ed8553a9f3 /src
parent0e2cfdedf261a9d29d7466bd26545549479d9f8a (diff)
Automatically register comparison operators in QMetaType
This removes the fully manual registration of comparison operators in QMetaType and replaces it with an automatic registration through Q_DECLARE_METATYPE(). [ChangeLog][QMetaType] The QMetaType::registerComparator() and QMetaType::registerEqualsComparator() have been removed. Q_DECLARE_METATYPE() now automatically registers any operator==() and/or operator<() for a type visible where it is used on that type, as part of declaring its meta-type. Change-Id: I3df451b652b735c093533838bf32f3cc785439f8 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/kernel/qmetatype.cpp167
-rw-r--r--src/corelib/kernel/qmetatype.h150
-rw-r--r--src/corelib/kernel/qpropertybinding.cpp3
-rw-r--r--src/corelib/kernel/qvariant.cpp26
-rw-r--r--src/dbus/qdbusmetaobject.cpp2
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_unix.cpp3
6 files changed, 168 insertions, 183 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 9841758c80..c373991b68 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -657,6 +657,98 @@ void QMetaType::destruct(void *data) const
}
}
+/*!
+ Compares the objects at \a lhs and \a rhs for ordering.
+
+ Returns an empty optional if comparison is not supported or the values are unordered.
+ Otherwise, returns -1, 0 or +1 according as \a lhs is less than, equal to or greater
+ than \a rhs.
+
+ Both objects must be of the type described by this metatype. If either \a lhs
+ or \a rhs is \nullptr, the values are unordered. Comparison is only supported
+ if the type's less than operator was visible to the metatype declaration.
+
+ If the type's equality operator was also visible, values will only compare equal if the
+ equality operator says they are. In the absence of an equality operator, when neither
+ value is less than the other, values are considered equal; if equality is also available
+ and two such values are not equal, they are considered unordered, just as NaN (not a
+ number) values of a floating point type lie outside its ordering.
+
+ \note If no less than operator was visible to the metatype declaration, values are
+ unordered even if an equality operator visible to the declaration considers them equal:
+ \s{compare() == 0} only agrees with equals() if the less than operator was visible.
+
+ \since 6.0
+ \sa equals(), isOrdered()
+*/
+std::optional<int> QMetaType::compare(const void *lhs, const void *rhs) const
+{
+ if (!lhs || !rhs)
+ return std::optional<int>{};
+ if (d_ptr && d_ptr->lessThan) {
+ if (d_ptr->equals && d_ptr->equals(d_ptr, lhs, rhs))
+ return 0;
+ if (d_ptr->lessThan(d_ptr, lhs, rhs))
+ return -1;
+ if (d_ptr->lessThan(d_ptr, rhs, lhs))
+ return 1;
+ if (!d_ptr->equals)
+ return 0;
+ }
+ return std::optional<int>{};
+}
+
+/*!
+ Compares the objects at \a lhs and \a rhs for equality.
+
+ Both objects must be of the type described by this metatype. Can only compare the
+ two objects if a less than or equality operator for the type was visible to the
+ metatype declaration. Otherwise, the metatype never considers values equal. When
+ an equality operator was visible to the metatype declaration, it is authoritative;
+ otherwise, if less than is visible, when neither value is less than the other, the
+ two are considered equal. If values are unordered (see compare() for details) they
+ are not equal.
+
+ Returns true if the two objects compare equal, otherwise false.
+
+ \since 6.0
+ \sa isEqualityComparable(), compare()
+*/
+bool QMetaType::equals(const void *lhs, const void *rhs) const
+{
+ if (!lhs || !rhs)
+ return false;
+ if (d_ptr) {
+ if (d_ptr->equals)
+ return d_ptr->equals(d_ptr, lhs, rhs);
+ if (d_ptr->lessThan && !d_ptr->lessThan(d_ptr, lhs, rhs) && !d_ptr->lessThan(d_ptr, rhs, lhs))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns \c true if a less than or equality operator for the type described by
+ this metatype was visible to the metatype declaration, otherwise \c false.
+
+ \sa equals(), isOrdered()
+*/
+bool QMetaType::isEqualityComparable() const
+{
+ return d_ptr && (d_ptr->equals != nullptr || d_ptr->lessThan != nullptr);
+}
+
+/*!
+ Returns \c true if a less than operator for the type described by this metatype
+ was visible to the metatype declaration, otherwise \c false.
+
+ \sa compare(), isEqualityComparable()
+*/
+bool QMetaType::isOrdered() const
+{
+ return d_ptr && d_ptr->lessThan != nullptr;
+}
+
void QtMetaTypePrivate::derefAndDestroy(NS(QtPrivate::QMetaTypeInterface) *d_ptr)
{
if (d_ptr && !d_ptr->ref.deref()) {
@@ -789,13 +881,10 @@ private:
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> >
QMetaTypeConverterRegistry;
-typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractComparatorFunction,int>
-QMetaTypeComparatorRegistry;
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
QMetaTypeDebugStreamRegistry;
Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
-Q_GLOBAL_STATIC(QMetaTypeComparatorRegistry, customTypesComparatorRegistry)
Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
/*!
@@ -829,22 +918,6 @@ Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false.
*/
-/*!
- \fn bool QMetaType::registerComparators()
- \since 5.2
- 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()
@@ -883,30 +956,6 @@ void QMetaType::unregisterConverterFunction(int from, int to)
customTypesConversionRegistry()->remove(from, to);
}
-bool QMetaType::registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type)
-{
- if (!customTypesComparatorRegistry()->insertIfNotContains(type, f)) {
- qWarning("Comparators already registered for type %s", QMetaType::typeName(type));
- return false;
- }
- return true;
-}
-
-/*!
- \fn bool QMetaType::hasRegisteredComparators()
- Returns \c true, if the meta type system has registered comparators for type T.
- \since 5.2
- */
-
-/*!
- Returns \c true, if the meta type system has registered comparators for type id \a typeId.
- \since 5.2
- */
-bool QMetaType::hasRegisteredComparators(int typeId)
-{
- return customTypesComparatorRegistry()->contains(typeId);
-}
-
#ifndef QT_NO_DEBUG_STREAM
bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f,
int type)
@@ -948,44 +997,24 @@ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId
}
/*!
+ bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result)
+ \deprecated Use the non-static compare method instead
+
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, otherwise \c false.
\since 5.2
*/
-bool QMetaType::compare(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 if (f->lessThan)
- *result = f->lessThan(f, lhs, rhs) ? -1 : 1;
- else
- return false;
- return true;
-}
/*!
+ bool QMetaType::equals(const void *lhs, const void *rhs, int typeId, int *result)
+ \deprecated Use the non-static equals method instead
+
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;
-}
/*!
Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns \c true
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 335b958c18..a39c22b780 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -56,6 +56,7 @@
#include <vector>
#include <list>
#include <map>
+#include <optional>
#ifdef Bool
#error qmetatype.h must be included before any header file that defines Bool
@@ -296,62 +297,6 @@ struct BuiltInDebugStreamFunction : public AbstractDebugStreamFunction
};
#endif
-struct AbstractComparatorFunction
-{
- typedef bool (*LessThan)(const AbstractComparatorFunction *, const void *, const void *);
- typedef bool (*Equals)(const AbstractComparatorFunction *, const void *, const void *);
- typedef void (*Destroy)(AbstractComparatorFunction *);
- explicit AbstractComparatorFunction(LessThan lt = nullptr, Equals e = nullptr, Destroy d = nullptr)
- : lessThan(lt), equals(e), destroy(d) {}
- Q_DISABLE_COPY(AbstractComparatorFunction)
- LessThan lessThan;
- Equals equals;
- Destroy destroy;
-};
-
-template<typename T>
-struct BuiltInComparatorFunction : public AbstractComparatorFunction
-{
- BuiltInComparatorFunction()
- : AbstractComparatorFunction(lessThan, equals, destroy) {}
- static bool lessThan(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 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<BuiltInComparatorFunction *>(_this);
- }
-};
-
-template<typename T>
-struct BuiltInEqualsComparatorFunction : public AbstractComparatorFunction
-{
- BuiltInEqualsComparatorFunction()
- : AbstractComparatorFunction(nullptr, 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*);
@@ -569,6 +514,11 @@ public:
void destroy(void *data) const;
void *construct(void *where, const void *copy = nullptr) const;
void destruct(void *data) const;
+ std::optional<int> compare(const void *lhs, const void *rhs) const;
+ bool equals(const void *lhs, const void *rhs) const;
+
+ bool isEqualityComparable() const;
+ bool isOrdered() const;
template<typename T>
static QMetaType fromType();
@@ -577,33 +527,6 @@ public:
friend bool operator!=(const QMetaType &a, const QMetaType &b) { return !(a == b); }
public:
- template<typename T>
- static bool registerComparators()
- {
- static_assert((!QMetaTypeId2<T>::IsBuiltIn),
- "QMetaType::registerComparators: The type must be a custom type.");
-
- const int typeId = qMetaTypeId<T>();
- static const QtPrivate::BuiltInComparatorFunction<T> f;
- return registerComparatorFunction( &f, typeId);
- }
- template<typename T>
- static bool registerEqualsComparator()
- {
- static_assert((!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>());
- }
- static bool hasRegisteredComparators(int typeId);
-
#ifndef QT_NO_DEBUG_STREAM
template<typename T>
@@ -680,8 +603,30 @@ public:
#endif
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);
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_6_0
+ static bool compare(const void *lhs, const void *rhs, int typeId, int *result)
+ {
+ QMetaType t(typeId);
+ auto c = t.compare(lhs, rhs);
+ if (!c) {
+ *result = 0;
+ return false;
+ }
+ *result = *c;
+ return true;
+ }
+ QT_DEPRECATED_VERSION_6_0
+ static bool equals(const void *lhs, const void *rhs, int typeId, int *result)
+ {
+ QMetaType t(typeId);
+ if (!t.isEqualityComparable())
+ return false;
+ *result = t.equals(lhs, rhs) ? 0 : -1;
+ return true;
+ }
+#endif
+
static bool debugStream(QDebug& dbg, const void *rhs, int typeId);
template<typename From, typename To>
@@ -692,7 +637,6 @@ public:
static bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId);
- static bool registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type);
#ifndef QT_NO_DEBUG_STREAM
static bool registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, int type);
#endif
@@ -2297,6 +2241,10 @@ public:
MoveCtrFn moveCtr;
using DtorFn = void (*)(const QMetaTypeInterface *, void *);
DtorFn dtor;
+ using EqualsFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
+ EqualsFn equals;
+ using LessThanFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
+ LessThanFn lessThan;
using LegacyRegisterOp = void (*)();
LegacyRegisterOp legacyRegisterOp;
@@ -2679,6 +2627,32 @@ struct BuiltinMetaType<T, std::enable_if_t<QMetaTypeId2<T>::IsBuiltIn>>
{
};
+template<typename T, bool = QTypeTraits::has_operator_equal_v<T>>
+struct QEqualityOperatorForType
+{
+ static bool equals(const QMetaTypeInterface *, const void *a, const void *b)
+ { return *reinterpret_cast<const T *>(a) == *reinterpret_cast<const T *>(b); }
+};
+
+template<typename T>
+struct QEqualityOperatorForType <T, false>
+{
+ static constexpr QMetaTypeInterface::EqualsFn equals = nullptr;
+};
+
+template<typename T, bool = QTypeTraits::has_operator_less_than_v<T>>
+struct QLessThanOperatorForType
+{
+ static bool lessThan(const QMetaTypeInterface *, const void *a, const void *b)
+ { return *reinterpret_cast<const T *>(a) < *reinterpret_cast<const T *>(b); }
+};
+
+template<typename T>
+struct QLessThanOperatorForType <T, false>
+{
+ static constexpr QMetaTypeInterface::LessThanFn lessThan = nullptr;
+};
+
template<typename S>
class QMetaTypeForType
{
@@ -2765,6 +2739,8 @@ QMetaTypeInterface QMetaTypeForType<T>::metaType = {
/*.copyCtr=*/ getCopyCtr<T>(),
/*.moveCtr=*/ getMoveCtr<T>(),
/*.dtor=*/ getDtor<T>(),
+ /*.equals=*/ QEqualityOperatorForType<T>::equals,
+ /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
/*.legacyRegisterOp=*/ getLegacyRegister<T>()
};
@@ -2792,6 +2768,8 @@ public:
/*.copyCtr=*/ nullptr,
/*.moveCtr=*/ nullptr,
/*.dtor=*/ nullptr,
+ /*.equals=*/ nullptr,
+ /*.lessThan=*/ nullptr,
/*.legacyRegisterOp=*/ nullptr
};
};
diff --git a/src/corelib/kernel/qpropertybinding.cpp b/src/corelib/kernel/qpropertybinding.cpp
index 8602ef957f..e05ef996b6 100644
--- a/src/corelib/kernel/qpropertybinding.cpp
+++ b/src/corelib/kernel/qpropertybinding.cpp
@@ -123,11 +123,10 @@ bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged()
QVariant resultVariant(metaType.id(), nullptr);
evalError = evaluationFunction(metaType, resultVariant.data());
if (evalError.type() == QPropertyBindingError::NoError) {
- int compareResult = 0;
bool updateAllowed = true;
if (hasStaticObserver && staticGuardCallback)
updateAllowed = staticGuardCallback(staticObserver, resultVariant.data());
- if (updateAllowed && (!QMetaType::compare(propertyDataPtr, resultVariant.constData(), metaType.id(), &compareResult) || compareResult != 0)) {
+ if (updateAllowed && !metaType.equals(propertyDataPtr, resultVariant.constData())) {
changed = true;
metaType.destruct(propertyDataPtr);
metaType.construct(propertyDataPtr, resultVariant.constData());
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 61a80eeae8..f4d4dafe6b 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -3738,21 +3738,14 @@ bool QVariant::convert(const int type, void *ptr) const
The result of the function is not affected by the result of QVariant::isNull,
which means that two values can be equal even if one of them is null and
another is not.
-
- \warning To make this function work with a custom type registered with
- qRegisterMetaType(), its comparison operator must be registered using
- QMetaType::registerComparators().
*/
+
/*!
\fn bool operator!=(const QVariant &v1, const QVariant &v2)
\relates QVariant
Returns \c false if \a v1 and \a v2 are equal; otherwise returns \c true.
-
- \warning To make this function work with a custom type registered with
- qRegisterMetaType(), its comparison operator must be registered using
- QMetaType::registerComparators().
*/
/*! \fn bool QVariant::operator==(const QVariant &v) const
@@ -3764,10 +3757,6 @@ bool QVariant::convert(const int type, void *ptr) const
check for equality. QVariant will try to convert() \a v if its
type is not the same as this variant's type. See canConvert() for
a list of possible conversions.
-
- \warning To make this function work with a custom type registered with
- qRegisterMetaType(), its comparison operator must be registered using
- QMetaType::registerComparators().
*/
/*!
@@ -3775,10 +3764,6 @@ bool QVariant::convert(const int type, void *ptr) const
Compares this QVariant with \a v and returns \c true if they are not
equal; otherwise returns \c false.
-
- \warning To make this function work with a custom type registered with
- qRegisterMetaType(), its comparison operator must be registered using
- QMetaType::registerComparators().
*/
static bool qIsNumericType(uint tp)
@@ -3928,12 +3913,9 @@ bool QVariant::cmp(const QVariant &v) const
{
auto cmp_helper = [](const QVariant::Private &d1, const QVariant::Private &d2) {
Q_ASSERT(d1.type() == d2.type());
- if (d1.type().id() >= QMetaType::User) {
- int result;
- if (QMetaType::equals(QT_PREPEND_NAMESPACE(constData(d1)),
- QT_PREPEND_NAMESPACE(constData(d2)), d1.type().id(), &result))
- return result == 0;
- }
+ auto metatype = d1.type();
+ if (metatype.id() >= QMetaType::User)
+ return metatype.equals(QT_PREPEND_NAMESPACE(constData(d1)), QT_PREPEND_NAMESPACE(constData(d2)));
return handlerManager[d1.type().id()]->compare(&d1, &d2);
};
diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp
index dc52dacca5..d308151984 100644
--- a/src/dbus/qdbusmetaobject.cpp
+++ b/src/dbus/qdbusmetaobject.cpp
@@ -139,7 +139,7 @@ static int registerComplexDBusType(const QByteArray &typeName)
[](QtPrivate::QMetaTypeInterface *self) {
delete static_cast<QDBusRawTypeHandler *>(self);
},
- nullptr, nullptr, nullptr, nullptr, nullptr
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
},
name(name)
{}
diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp
index 8142e57c5a..739deaa6e1 100644
--- a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp
+++ b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp
@@ -249,9 +249,6 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent)
{
m_ui.setupUi(this);
- if (!QMetaType::hasRegisteredComparators<QPageSize>())
- QMetaType::registerEqualsComparator<QPageSize>();
-
QVBoxLayout *lay = new QVBoxLayout(m_ui.preview);
m_pagePreview = new QPagePreview(m_ui.preview);
m_pagePreview->setPagePreviewLayout(1, 1);