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)
#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"
bool QUrlQuery::operator==(const QUrlQuery &other) const

View File

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

View File

@ -6,6 +6,7 @@
#define QURL_H
#include <QtCore/qbytearray.h>
#include <QtCore/qcompare.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
@ -230,9 +231,11 @@ public:
void detach();
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;
#endif
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;
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;
friend class QUrlQuery;

View File

@ -6,6 +6,7 @@
#include <QtCore/QDebug>
#include <QTest>
#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QDirIterator>
#include <qcoreapplication.h>
@ -31,6 +32,7 @@ private slots:
void hashInPath();
void unc();
void assignment();
void orderingCompiles();
void comparison();
void comparison2_data();
void comparison2();
@ -289,6 +291,11 @@ void tst_QUrl::assignment()
QCOMPARE(url, copy);
}
void tst_QUrl::orderingCompiles()
{
QTestPrivate::testAllComparisonOperatorsCompile<QUrl>();
}
void tst_QUrl::comparison()
{
QUrl url1("http://qt-project.org/");
@ -437,18 +444,19 @@ void tst_QUrl::comparison2()
QFETCH(QUrl, url2);
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 == url2, ordering == 0);
QCOMPARE(url1 != url2, ordering != 0);
QT_TEST_ALL_COMPARISON_OPS(url1, url2, expectedOrdering);
if (ordering == 0)
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)
QCOMPARE(url1 < url2 || url2 < url1, ordering != 0);
QVERIFY(!(url1 < url2 && url2 < url1));