diff options
author | Thiago Macieira <[email protected]> | 2025-05-21 15:21:11 -0700 |
---|---|---|
committer | Thiago Macieira <[email protected]> | 2025-07-04 14:24:00 -0300 |
commit | 423278c6ee18a86320d253d8f873347c12f882f5 (patch) | |
tree | 45f2b66a0d708adde271556e462acfe85eb12e7d | |
parent | 4b4e77a0869ce00c96acfc209cd827b39ffac7b0 (diff) |
QUrl: use QHashCombine so we use the faster & stronger QString hashing
We were only using the seed for hashing the port number, which is the
weakest of all the uses of the seed, resulting in a weak hash for the
QUrl itself. This commit changes it so QString components of the URL are
themselves also hashed using the seed. As a side benefit, the aeshash()
implementation in qhash.cpp where supported (ARM and x86) is faster than
the siphash() one because it's vectorized.
We're retaining the qHash(QUrl(), seed) == hashing of -1, but it's not
qHash(-1, seed) because QHashCombine adds a constant.
Pick-to: 6.10
Change-Id: If6466d054fd5a4f05205fffdfbc7b655eae5aefb
Reviewed-by: David Faure <[email protected]>
-rw-r--r-- | src/corelib/io/qurl.cpp | 32 | ||||
-rw-r--r-- | tests/auto/corelib/io/qurl/tst_qurl.cpp | 4 |
2 files changed, 26 insertions, 10 deletions
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 565ce04c6ce..a4fbf69da8b 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3660,17 +3660,29 @@ QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode) */ size_t qHash(const QUrl &url, size_t seed) noexcept { + QtPrivate::QHashCombineWithSeed hasher(seed); + + // non-commutative, we must hash the port first if (!url.d) - return qHash(-1, seed); // the hash of an unset port (-1) - - return qHash(url.d->scheme) ^ - qHash(url.d->userName) ^ - qHash(url.d->password) ^ - qHash(url.d->host) ^ - qHash(url.d->port, seed) ^ - qHash(url.d->path) ^ - qHash(url.d->query) ^ - qHash(url.d->fragment); + return hasher(0, -1); + size_t state = hasher(0, url.d->port); + + if (url.d->hasScheme()) + state = hasher(state, url.d->scheme); + if (url.d->hasUserInfo()) { + // see presentSections(), appendUserName(), etc. + state = hasher(state, url.d->userName); + state = hasher(state, url.d->password); + } + if (url.d->hasHost() || url.d->isLocalFile()) // for XDG compatibility + state = hasher(state, url.d->host); + if (url.d->hasPath()) + state = hasher(state, url.d->path); + if (url.d->hasQuery()) + state = hasher(state, url.d->query); + if (url.d->hasFragment()) + state = hasher(state, url.d->fragment); + return state; } static QUrl adjustFtpPath(QUrl url) diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 282c7f2e360..71389abc976 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -513,6 +513,7 @@ void tst_QUrl::comparison2() QCOMPARE(url1.toString(), url2.toString()); QCOMPARE(url1, url2); QCOMPARE(qHash(url1), qHash(url2)); + QCOMPARE(qHash(url1, 1), qHash(url2, 1)); } else if (ordering < 0) { QCOMPARE_LT(url1.toString(), url2.toString()); QCOMPARE_NE(url1, url2); @@ -1387,12 +1388,14 @@ void tst_QUrl::toString_constructed() QUrl parsed(asString); QCOMPARE(url, parsed); QCOMPARE(qHash(url), qHash(parsed)); + QCOMPARE(qHash(url, 1), qHash(parsed, 1)); } // clear it and ensure no memory of the previous state remains url.setUrl(QString()); QCOMPARE(url, QUrl()); QCOMPARE(qHash(url), qHash(QUrl())); + QCOMPARE(qHash(url, 1), qHash(QUrl(), 1)); } void tst_QUrl::toDisplayString_PreferLocalFile_data() @@ -4265,6 +4268,7 @@ void tst_QUrl::setComponents() QUrl recreated(toString); QCOMPARE(copy, recreated); QCOMPARE(qHash(copy), qHash(recreated)); + QCOMPARE(qHash(copy, 1), qHash(recreated, 1)); } else { QVERIFY(copy.toString().isEmpty()); } |