QUrl: Use new comparison helper macros

The class had operator==(), operator!=() and operator <() defined as
public member functions, so use QT_CORE_REMOVED_SINCE and
removed_api.cpp to get rid of these methods and replace them with hidden
friends.

Use QT_TEST_ALL_EQUALITY_OPS macro in unit-tests.

Use new \compares command in the documentation to describe the
comparison operators provided by QUrl.

Task-number: QTBUG-120303
Change-Id: Ic4fa2335292cc4b75ad2373832c0b89d768f529c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Rym Bouabid 2024-02-20 16:54:53 +01:00
parent 907e9a8b29
commit 8103d29e94
4 changed files with 102 additions and 56 deletions

View File

@ -962,6 +962,23 @@ bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
} }
#endif // QT_CONFIG(processenvironment) #endif // QT_CONFIG(processenvironment)
#include "qurl.h"
bool QUrl::operator<(const QUrl &url) const
{
return is_lt(compareThreeWay(*this, url));
}
bool QUrl::operator==(const QUrl &url) const
{
return comparesEqual(*this, url);
}
bool QUrl::operator!=(const QUrl &url) const
{
return !comparesEqual(*this, url);
}
#include "qurlquery.h" #include "qurlquery.h"
bool QUrlQuery::operator==(const QUrlQuery &other) const bool QUrlQuery::operator==(const QUrlQuery &other) const

View File

@ -14,6 +14,8 @@
\ingroup network \ingroup network
\ingroup shared \ingroup shared
\compares weak
It can parse and construct URLs in both encoded and unencoded It can parse and construct URLs in both encoded and unencoded
form. QUrl also has support for internationalized domain names form. QUrl also has support for internationalized domain names
(IDNs). (IDNs).
@ -3067,88 +3069,101 @@ QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
/*! /*!
\internal \internal
Returns \c true if this URL is "less than" the given \a url. This \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs)
Returns \c true if URL \a lhs is "less than" URL \a rhs. This
provides a means of ordering URLs. provides a means of ordering URLs.
*/ */
bool QUrl::operator <(const QUrl &url) const
Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
{ {
if (!d || !url.d) { if (!lhs.d || !rhs.d) {
bool thisIsEmpty = !d || d->isEmpty(); bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
bool thatIsEmpty = !url.d || url.d->isEmpty(); bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
// sort an empty URL first // sort an empty URL first
return thisIsEmpty && !thatIsEmpty; if (thisIsEmpty) {
if (!thatIsEmpty)
return Qt::weak_ordering::less;
else
return Qt::weak_ordering::equivalent;
} else {
return Qt::weak_ordering::greater;
}
} }
int cmp; int cmp;
cmp = d->scheme.compare(url.d->scheme); cmp = lhs.d->scheme.compare(rhs.d->scheme);
if (cmp != 0) if (cmp != 0)
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
cmp = d->userName.compare(url.d->userName); cmp = lhs.d->userName.compare(rhs.d->userName);
if (cmp != 0) if (cmp != 0)
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
cmp = d->password.compare(url.d->password); cmp = lhs.d->password.compare(rhs.d->password);
if (cmp != 0) if (cmp != 0)
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
cmp = d->host.compare(url.d->host); cmp = lhs.d->host.compare(rhs.d->host);
if (cmp != 0) if (cmp != 0)
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
if (d->port != url.d->port) if (lhs.d->port != rhs.d->port)
return d->port < url.d->port; return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
cmp = d->path.compare(url.d->path); cmp = lhs.d->path.compare(rhs.d->path);
if (cmp != 0) if (cmp != 0)
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
if (d->hasQuery() != url.d->hasQuery()) if (lhs.d->hasQuery() != rhs.d->hasQuery())
return url.d->hasQuery(); return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
cmp = d->query.compare(url.d->query); cmp = lhs.d->query.compare(rhs.d->query);
if (cmp != 0) if (cmp != 0)
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
if (d->hasFragment() != url.d->hasFragment()) if (lhs.d->hasFragment() != rhs.d->hasFragment())
return url.d->hasFragment(); return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
cmp = d->fragment.compare(url.d->fragment); cmp = lhs.d->fragment.compare(rhs.d->fragment);
return cmp < 0; return Qt::compareThreeWay(cmp, 0);
} }
/*! /*!
Returns \c true if this URL and the given \a url are equal; \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs)
Returns \c true if \a lhs and \a rhs URLs are equivalent;
otherwise returns \c false. otherwise returns \c false.
\sa matches() \sa matches()
*/ */
bool QUrl::operator ==(const QUrl &url) const
bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
{ {
if (!d && !url.d) if (!lhs.d && !rhs.d)
return true; return true;
if (!d) if (!lhs.d)
return url.d->isEmpty(); return rhs.d->isEmpty();
if (!url.d) if (!rhs.d)
return d->isEmpty(); return lhs.d->isEmpty();
// First, compare which sections are present, since it speeds up the // First, compare which sections are present, since it speeds up the
// processing considerably. We just have to ignore the host-is-present flag // processing considerably. We just have to ignore the host-is-present flag
// for local files (the "file" protocol), due to the requirements of the // for local files (the "file" protocol), due to the requirements of the
// XDG file URI specification. // XDG file URI specification.
int mask = QUrlPrivate::FullUrl; int mask = QUrlPrivate::FullUrl;
if (isLocalFile()) if (lhs.isLocalFile())
mask &= ~QUrlPrivate::Host; mask &= ~QUrlPrivate::Host;
return (d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask) && return (lhs.d->sectionIsPresent & mask) == (rhs.d->sectionIsPresent & mask) &&
d->scheme == url.d->scheme && lhs.d->scheme == rhs.d->scheme &&
d->userName == url.d->userName && lhs.d->userName == rhs.d->userName &&
d->password == url.d->password && lhs.d->password == rhs.d->password &&
d->host == url.d->host && lhs.d->host == rhs.d->host &&
d->port == url.d->port && lhs.d->port == rhs.d->port &&
d->path == url.d->path && lhs.d->path == rhs.d->path &&
d->query == url.d->query && lhs.d->query == rhs.d->query &&
d->fragment == url.d->fragment; lhs.d->fragment == rhs.d->fragment;
} }
/*! /*!
@ -3228,15 +3243,13 @@ bool QUrl::matches(const QUrl &url, FormattingOptions options) const
} }
/*! /*!
Returns \c true if this URL and the given \a url are not equal; \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs)
Returns \c true if \a lhs and \a rhs URLs are not equal;
otherwise returns \c false. otherwise returns \c false.
\sa matches() \sa matches()
*/ */
bool QUrl::operator !=(const QUrl &url) const
{
return !(*this == url);
}
/*! /*!
Assigns the specified \a url to this object. Assigns the specified \a url to this object.

View File

@ -6,6 +6,7 @@
#define QURL_H #define QURL_H
#include <QtCore/qbytearray.h> #include <QtCore/qbytearray.h>
#include <QtCore/qcompare.h>
#include <QtCore/qobjectdefs.h> #include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
#include <QtCore/qlist.h> #include <QtCore/qlist.h>
@ -230,9 +231,11 @@ public:
void detach(); void detach();
bool isDetached() const; bool isDetached() const;
#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator <(const QUrl &url) const; bool operator <(const QUrl &url) const;
bool operator ==(const QUrl &url) const; bool operator ==(const QUrl &url) const;
bool operator !=(const QUrl &url) const; bool operator !=(const QUrl &url) const;
#endif
bool matches(const QUrl &url, FormattingOptions options) const; bool matches(const QUrl &url, FormattingOptions options) const;
@ -268,6 +271,11 @@ public:
friend Q_CORE_EXPORT size_t qHash(const QUrl &url, size_t seed) noexcept; friend Q_CORE_EXPORT size_t qHash(const QUrl &url, size_t seed) noexcept;
private: private:
friend Q_CORE_EXPORT bool comparesEqual(const QUrl &lhs, const QUrl &rhs);
friend Q_CORE_EXPORT Qt::weak_ordering
compareThreeWay(const QUrl &lhs, const QUrl &rhs);
Q_DECLARE_WEAKLY_ORDERED(QUrl)
QUrlPrivate *d; QUrlPrivate *d;
friend class QUrlQuery; friend class QUrlQuery;

View File

@ -6,6 +6,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QTest> #include <QTest>
#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QDirIterator> #include <QDirIterator>
#include <qcoreapplication.h> #include <qcoreapplication.h>
@ -31,6 +32,7 @@ private slots:
void hashInPath(); void hashInPath();
void unc(); void unc();
void assignment(); void assignment();
void orderingCompiles();
void comparison(); void comparison();
void comparison2_data(); void comparison2_data();
void comparison2(); void comparison2();
@ -289,6 +291,11 @@ void tst_QUrl::assignment()
QCOMPARE(url, copy); QCOMPARE(url, copy);
} }
void tst_QUrl::orderingCompiles()
{
QTestPrivate::testAllComparisonOperatorsCompile<QUrl>();
}
void tst_QUrl::comparison() void tst_QUrl::comparison()
{ {
QUrl url1("http://qt-project.org/"); QUrl url1("http://qt-project.org/");
@ -437,18 +444,19 @@ void tst_QUrl::comparison2()
QFETCH(QUrl, url2); QFETCH(QUrl, url2);
QFETCH(int, ordering); QFETCH(int, ordering);
const Qt::weak_ordering expectedOrdering = [&ordering] {
if (ordering > 0)
return Qt::weak_ordering::greater;
else if (ordering < 0)
return Qt::weak_ordering::less;
return Qt::weak_ordering::equivalent;
}();
QCOMPARE(url1.toString() == url2.toString(), ordering == 0); QCOMPARE(url1.toString() == url2.toString(), ordering == 0);
QCOMPARE(url1 == url2, ordering == 0); QT_TEST_ALL_COMPARISON_OPS(url1, url2, expectedOrdering);
QCOMPARE(url1 != url2, ordering != 0);
if (ordering == 0) if (ordering == 0)
QCOMPARE(qHash(url1), qHash(url2)); QCOMPARE(qHash(url1), qHash(url2));
QCOMPARE(url1 < url2, ordering < 0);
QCOMPARE(!(url1 < url2), ordering >= 0);
QCOMPARE(url2 < url1, ordering > 0);
QCOMPARE(!(url2 < url1), ordering <= 0);
// redundant checks (the above should catch these) // redundant checks (the above should catch these)
QCOMPARE(url1 < url2 || url2 < url1, ordering != 0); QCOMPARE(url1 < url2 || url2 < url1, ordering != 0);
QVERIFY(!(url1 < url2 && url2 < url1)); QVERIFY(!(url1 < url2 && url2 < url1));