summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.cpp
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-11-22 18:25:44 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-11-30 17:16:22 +0100
commit405244fe301ac18d20aae245ba2faafaec74e453 (patch)
treea3102274e3bdf98a1e96b83807c7195f5b2e1d9e /src/corelib/kernel/qvariant.cpp
parent81e893fb2d57b7f2d332f4f626e38f51acf43542 (diff)
Fix QVariant/QMetaType::compare APIs
std::optional<int> is the wrong datatype to use for compare. First and foremost, it can't be used in the idiomatic form of auto r = a.compare(b); if (r < 0) ~~~ // a is less than b if (r > 0) ~~~ // a is greater than b which we *already* feature in Qt (QString, QByteArray). Also, std::optional<int> (explicitly) converts to bool, which is a trap, because the result of the comparison can be accidentally tested as a bool: if (a.compare(b)) ~~~ // oops! does NOT mean a<b Not to mention extending this to algorithms: auto lessThan = [](QVariant a, QVariant b) { return a.compare(b); }; // oops! std::ranges::sort(vectorOfVariants, lessThan); which thankfully doesn't compile as is -- std::optional has an *explicit* operator bool, and the Compare concept requires an implicit conversion. However, the error the user is going to face will be "cannot convert to bool because the operator is explicit", which is deceiving because the fix is NOT supposed to be: auto lessThan = [](QVariant a, QVariant b) { return (bool)a.compare(b); }; // big oops! Instead: backport to Qt the required subset of C++20's <compare> API, and use that. This commits just adds the necessary parts for compare() (i.e. partial ordering), the rest of <compare> (classes, functions, conversions) can be added to 6.1. Change-Id: I2b5522da47854da39f79993e1207fad033786f00 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 3e59c97c3453926fc66479d9ceca03901df55f90) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r--src/corelib/kernel/qvariant.cpp30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 8d4bb38dc6..0f92307d8c 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2352,17 +2352,31 @@ bool QVariant::equals(const QVariant &v) const
return metatype.equals(d.storage(), v.d.storage());
}
+static QPartialOrdering convertOptionalToPartialOrdering(const std::optional<int> &opt)
+{
+ if (!opt)
+ return QPartialOrdering::Unordered;
+ else if (*opt < 0)
+ return QPartialOrdering::Less;
+ else if (*opt == 0)
+ return QPartialOrdering::Equivalent;
+ else
+ return QPartialOrdering::Greater;
+}
+
/*!
Compares the objects at \a lhs and \a rhs for ordering.
- Returns an std::nullopt 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.
+ Returns QPartialOrdering::Unordered if comparison is not supported
+ or the values are unordered. Otherwise, returns
+ QPartialOrdering::Less, QPartialOrdering::Equivalent or
+ QPartialOrdering::Greater if \a lhs is less than, equivalent
+ to or greater than \a rhs, respectively.
If the variants contain data with a different metatype, the values are considered
unordered unless they are both of numeric or pointer types, where regular numeric or
pointer comparison rules will be used.
- \note: If a numeric comparison is done and at least one value is NaN, \c std::nullopt
+ \note: If a numeric comparison is done and at least one value is NaN, QPartialOrdering::Unordered
is returned.
If both variants contain data of the same metatype, the method will use the
@@ -2372,18 +2386,18 @@ bool QVariant::equals(const QVariant &v) const
\since 6.0
\sa QMetaType::compare(), QMetaType::isOrdered()
*/
-std::optional<int> QVariant::compare(const QVariant &lhs, const QVariant &rhs)
+QPartialOrdering QVariant::compare(const QVariant &lhs, const QVariant &rhs)
{
QMetaType t = lhs.d.type();
if (t != rhs.d.type()) {
// try numeric comparisons, with C++ type promotion rules (no conversion)
if (qIsNumericType(lhs.d.typeId()) && qIsNumericType(rhs.d.typeId()))
- return numericCompare(&lhs.d, &rhs.d);
+ return convertOptionalToPartialOrdering(numericCompare(&lhs.d, &rhs.d));
#ifndef QT_BOOTSTRAPPED
if (canConvertMetaObject(lhs.metaType(), rhs.metaType()))
- return pointerCompare(&lhs.d, &rhs.d);
+ return convertOptionalToPartialOrdering(pointerCompare(&lhs.d, &rhs.d));
#endif
- return std::nullopt;
+ return QPartialOrdering::Unordered;
}
return t.compare(lhs.constData(), rhs.constData());
}