summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <[email protected]>2025-03-13 08:30:06 -0700
committerThiago Macieira <[email protected]>2025-05-09 16:54:13 -0700
commitc05ae82efb33507959ae2082483fb9425ccca8a0 (patch)
treede0398da78fee891aaf5f9bbf2ce1299c3e5aeba
parentb10c7b1680d57174f2b4d5a08387378550434ae9 (diff)
qHashMulti: switch to passing the seed to the qHash() function in 7.0
Amends 707129fd5a7c6390fbdf4270119226df2a427fcd. This is much better for our string types because qHashBits() has a faster implementation when seed!=0. The algorithm is the same, except that QHashCombine now separates the seed from the combined hash, not merging the two unrelated concepts together. We can't fix it in Qt 6.x because it changes the hashing algorithm of existing types that used qHashMulti(), which will have been inlined throughout user code. The deprecated constructor is there only until the rest of Qt is fixed. Since this is a private class, that won't stay for long. Task-number: QTBUG-134683 Fixes: QTBUG-134690 Change-Id: I2167e154f083089d12a1fffd61c1ab8670731156 Reviewed-by: Edward Welbourne <[email protected]>
-rw-r--r--src/corelib/serialization/qjsonobject.cpp2
-rw-r--r--src/corelib/tools/qhash.h4
-rw-r--r--src/corelib/tools/qhashfunctions.h49
-rw-r--r--src/corelib/tools/qmap.h2
-rw-r--r--src/gui/painting/qtransform.cpp2
-rw-r--r--src/gui/rhi/qrhi.cpp2
-rw-r--r--src/gui/rhi/qrhi.h14
-rw-r--r--src/gui/rhi/qrhid3d12_p.h2
-rw-r--r--src/gui/rhi/qshader.cpp2
-rw-r--r--src/gui/text/qfontdatabase_p.h2
-rw-r--r--src/gui/vulkan/qvulkaninstance.h4
11 files changed, 52 insertions, 33 deletions
diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp
index 99f5507aa12..3e0857dc954 100644
--- a/src/corelib/serialization/qjsonobject.cpp
+++ b/src/corelib/serialization/qjsonobject.cpp
@@ -1445,7 +1445,7 @@ void QJsonObject::removeAt(qsizetype index)
size_t qHash(const QJsonObject &object, size_t seed)
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
for (auto it = object.begin(), end = object.end(); it != end; ++it) {
const QString key = it.key();
const QJsonValue value = it.value();
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 24c014e2153..87713b93a77 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -2710,9 +2710,9 @@ template <class Key, class T>
size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
+ const QtPrivate::QHashCombine combine(seed);
size_t hash = 0;
for (auto it = key.begin(), end = key.end(); it != end; ++it) {
- QtPrivate::QHashCombine combine;
size_t h = combine(seed, it.key());
// use + to keep the result independent of the ordering of the keys
hash += combine(h, it.value());
@@ -2724,9 +2724,9 @@ template <class Key, class T>
inline size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
+ const QtPrivate::QHashCombine combine(seed);
size_t hash = 0;
for (auto it = key.begin(), end = key.end(); it != end; ++it) {
- QtPrivate::QHashCombine combine;
size_t h = combine(seed, it.key());
// use + to keep the result independent of the ordering of the keys
hash += combine(h, it.value());
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index c687cdaeb72..cbe217db11e 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -298,18 +298,40 @@ bool qHashEquals(const T1 &a, const T2 &b)
}
namespace QtPrivate {
-
-struct QHashCombine
+template <typename Mixer> struct QHashCombiner : private Mixer
{
- typedef size_t result_type;
+ using result_type = typename Mixer::result_type ;
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
+ // Qt 6.x didn't use to pass the seed; bootstrap has no seed
+ static constexpr size_t seed = 0;
+ constexpr QHashCombiner(result_type) noexcept {}
+ Q_DECL_DEPRECATED_X("pass the seed argument") constexpr QHashCombiner() noexcept {}
+#else
+ size_t seed;
+ constexpr QHashCombiner(result_type s) : seed(s) noexcept {}
+#endif
+
template <typename T>
- constexpr result_type operator()(size_t seed, const T &t) const
+ constexpr result_type operator()(result_type result, const T &t) const
noexcept(noexcept(qHash(t, seed)))
- // combiner taken from N3876 / boost::hash_combine
- { return seed ^ (qHash(t, size_t(0)) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); }
+ {
+ return Mixer::operator()(result, qHash(t, seed));
+ }
};
-struct QHashCombineCommutative
+struct QHashCombineMixer
+{
+ typedef size_t result_type;
+ constexpr result_type operator()(result_type result, result_type hash) const noexcept
+ {
+ // combiner taken from N3876 / boost::hash_combine
+ return result ^ (hash + 0x9e3779b9 + (result << 6) + (result >> 2));
+ }
+};
+using QHashCombine = QHashCombiner<QHashCombineMixer>;
+
+struct QHashCombineCommutativeMixer : std::plus<size_t>
{
// QHashCombine is a good hash combiner, but is not commutative,
// ie. it depends on the order of the input elements. That is
@@ -317,11 +339,8 @@ struct QHashCombineCommutative
// {1,3,0}. Except when it isn't (e.g. for QSet and
// QHash). Therefore, provide a commutative combiner, too.
typedef size_t result_type;
- template <typename T>
- constexpr result_type operator()(size_t seed, const T &t) const
- noexcept(noexcept(qHash(t, seed)))
- { return seed + qHash(t, size_t(0)); } // don't use xor!
};
+using QHashCombineCommutative = QHashCombiner<QHashCombineCommutativeMixer>;
template <typename... T>
using QHashMultiReturnType = decltype(
@@ -356,7 +375,7 @@ QtPrivate::QHashMultiReturnType<T...>
qHashMulti(size_t seed, const T &... args)
noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
return ((seed = hash(seed, args)), ...), seed;
}
@@ -370,7 +389,7 @@ QtPrivate::QHashMultiReturnType<T...>
qHashMultiCommutative(size_t seed, const T &... args)
noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
{
- QtPrivate::QHashCombineCommutative hash;
+ QtPrivate::QHashCombineCommutative hash(seed);
return ((seed = hash(seed, args)), ...), seed;
}
@@ -378,14 +397,14 @@ template <typename InputIterator>
inline size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
{
- return std::accumulate(first, last, seed, QtPrivate::QHashCombine());
+ return std::accumulate(first, last, seed, QtPrivate::QHashCombine(seed));
}
template <typename InputIterator>
inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
{
- return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative());
+ return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative(seed));
}
namespace QHashPrivate {
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 01e614aa28b..ac2f04b8cd8 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -810,7 +810,7 @@ private:
return seed;
// don't use qHashRange to avoid its compile-time overhead:
return std::accumulate(key.d->m.begin(), key.d->m.end(), seed,
- QtPrivate::QHashCombine{});
+ QtPrivate::QHashCombine{seed});
}
#endif // !Q_QDOC
};
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 1ea63f40965..66f1cf2a985 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -784,7 +784,7 @@ bool QTransform::operator==(const QTransform &o) const
*/
size_t qHash(const QTransform &key, size_t seed) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, key.m11());
seed = hash(seed, key.m12());
seed = hash(seed, key.m21());
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index 42e7753e4cb..0628d07ce73 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -6543,7 +6543,7 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept
{
const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(b);
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, d->binding);
seed = hash(seed, d->stage);
seed = hash(seed, d->type);
diff --git a/src/gui/rhi/qrhi.h b/src/gui/rhi/qrhi.h
index 5776554916a..66651dcf979 100644
--- a/src/gui/rhi/qrhi.h
+++ b/src/gui/rhi/qrhi.h
@@ -69,7 +69,7 @@ private:
friend size_t qHash(const QRhiDepthStencilClearValue &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_d);
seed = hash(seed, v.m_s);
return seed;
@@ -118,7 +118,7 @@ private:
friend size_t qHash(const QRhiViewport &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_rect[0]);
seed = hash(seed, v.m_rect[1]);
seed = hash(seed, v.m_rect[2]);
@@ -161,7 +161,7 @@ private:
friend size_t qHash(const QRhiScissor &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_rect[0]);
seed = hash(seed, v.m_rect[1]);
seed = hash(seed, v.m_rect[2]);
@@ -215,7 +215,7 @@ private:
friend size_t qHash(const QRhiVertexInputBinding &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_stride);
seed = hash(seed, v.m_classification);
seed = hash(seed, v.m_instanceStepRate);
@@ -303,7 +303,7 @@ private:
friend size_t qHash(const QRhiVertexInputAttribute &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_binding);
seed = hash(seed, v.m_location);
seed = hash(seed, v.m_format);
@@ -363,7 +363,7 @@ private:
friend size_t qHash(const QRhiVertexInputLayout &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_bindings);
seed = hash(seed, v.m_attributes);
return seed;
@@ -420,7 +420,7 @@ private:
friend size_t qHash(const QRhiShaderStage &v, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, v.m_type);
seed = hash(seed, v.m_shader);
seed = hash(seed, v.m_shaderVariant);
diff --git a/src/gui/rhi/qrhid3d12_p.h b/src/gui/rhi/qrhid3d12_p.h
index 2381bb40d42..caa428c6cbc 100644
--- a/src/gui/rhi/qrhid3d12_p.h
+++ b/src/gui/rhi/qrhid3d12_p.h
@@ -507,7 +507,7 @@ struct Q_D3D12_SAMPLER_DESC
friend size_t qHash(const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, key.desc.Filter);
seed = hash(seed, key.desc.AddressU);
seed = hash(seed, key.desc.AddressV);
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index e1fe23c2a2f..5e967c62e40 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -812,7 +812,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) noexcept
size_t qHash(const QShader &s, size_t seed) noexcept
{
if (s.d) {
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, s.stage());
if (!s.d->shaders.isEmpty()) {
seed = hash(seed, s.d->shaders.firstKey());
diff --git a/src/gui/text/qfontdatabase_p.h b/src/gui/text/qfontdatabase_p.h
index 58feb9457b9..cbfa02b2b7c 100644
--- a/src/gui/text/qfontdatabase_p.h
+++ b/src/gui/text/qfontdatabase_p.h
@@ -51,7 +51,7 @@ inline bool operator!=(const QtFontFallbacksCacheKey &lhs, const QtFontFallbacks
inline size_t qHash(const QtFontFallbacksCacheKey &key, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, key.family);
seed = hash(seed, int(key.style));
seed = hash(seed, int(key.styleHint));
diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h
index 819751025be..2728fc2e1b0 100644
--- a/src/gui/vulkan/qvulkaninstance.h
+++ b/src/gui/vulkan/qvulkaninstance.h
@@ -81,7 +81,7 @@ inline bool operator!=(const QVulkanLayer &lhs, const QVulkanLayer &rhs) noexcep
inline size_t qHash(const QVulkanLayer &key, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, key.name);
seed = hash(seed, key.version);
seed = hash(seed, key.specVersion);
@@ -104,7 +104,7 @@ inline bool operator!=(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
inline size_t qHash(const QVulkanExtension &key, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash;
+ QtPrivate::QHashCombine hash(seed);
seed = hash(seed, key.name);
seed = hash(seed, key.version);
return seed;