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 <edward.welbourne@qt.io>
This commit is contained in:
parent
b10c7b1680
commit
c05ae82efb
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user