Long live qHashMulti(Commutative)
Add a helper function so that we have a shortcut. Instead of writing: QHashCombine hash; seed = hash(seed, fieldA); seed = hash(seed, fieldB); // etc. return seed; one can now simply write: return qHashMulti(seed, fieldA, fieldB, fieldC); Port a few usages inside qtbase as a demonstration. [ChangeLog][QtCore][QHash] Added the qHashMulti and qHashMultiCommutative functions as convenience helpers to calculate a hash from multiple variables (typically, data members of a class). Change-Id: I881a9ad41168df20ceecc6588a94abe7ddc6a532 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
parent
2844631aa9
commit
707129fd5a
@ -151,7 +151,7 @@ inline bool operator==(const Employee &e1, const Employee &e2)
|
||||
|
||||
inline size_t qHash(const Employee &key, size_t seed)
|
||||
{
|
||||
return qHash(key.name(), seed) ^ key.dateOfBirth().day();
|
||||
return qHashMulti(seed, key.name(), key.dateOfBirth());
|
||||
}
|
||||
|
||||
#endif // EMPLOYEE_H
|
||||
|
@ -5030,10 +5030,7 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
|
||||
*/
|
||||
size_t qHash(const QByteArray::FromBase64Result &key, size_t seed) noexcept
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, key.decoded);
|
||||
seed = hash(seed, static_cast<int>(key.decodingStatus));
|
||||
return seed;
|
||||
return qHashMulti(seed, key.decoded, static_cast<int>(key.decodingStatus));
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -1091,10 +1091,7 @@ bool QLocale::operator!=(const QLocale &other) const
|
||||
*/
|
||||
size_t qHash(const QLocale &key, size_t seed) noexcept
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, key.d->m_data);
|
||||
seed = hash(seed, key.d->m_numberOptions);
|
||||
return seed;
|
||||
return qHashMulti(seed, key.d->m_data, key.d->m_numberOptions);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1030,11 +1030,7 @@ static bool operator==(const QRegExpEngineKey &key1, const QRegExpEngineKey &key
|
||||
|
||||
static size_t qHash(const QRegExpEngineKey &key, size_t seed = 0) noexcept
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, key.pattern);
|
||||
seed = hash(seed, key.patternSyntax);
|
||||
seed = hash(seed, key.cs);
|
||||
return seed;
|
||||
return qHashMulti(seed, key.pattern, key.patternSyntax, key.cs);
|
||||
}
|
||||
|
||||
class QRegExpEngine;
|
||||
|
@ -1712,10 +1712,7 @@ bool QRegularExpression::operator==(const QRegularExpression &re) const
|
||||
*/
|
||||
size_t qHash(const QRegularExpression &key, size_t seed) noexcept
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, key.d->pattern);
|
||||
seed = hash(seed, key.d->patternOptions);
|
||||
return seed;
|
||||
return qHashMulti(seed, key.d->pattern, key.d->patternOptions);
|
||||
}
|
||||
|
||||
#if QT_STRINGVIEW_LEVEL < 2
|
||||
|
@ -596,6 +596,48 @@ uint qt_hash(QStringView key, uint chained) noexcept
|
||||
constraints, we cannot change the QPair algorithm to match the std::pair one before Qt 6.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename... T> size_t qHashMulti(size_t seed, const T &...args)
|
||||
\relates QHash
|
||||
\since 6.0
|
||||
|
||||
Returns the hash value for the \a{args}, using \a seed to seed
|
||||
the calculation, by successively applying qHash() to each
|
||||
element and combining the hash values into a single one.
|
||||
|
||||
Note that the order of the arguments is significant. If order does
|
||||
not matter, use qHashMultiCommutative() instead. If you are hashing raw
|
||||
memory, use qHashBits(); if you are hashing a range, use qHashRange().
|
||||
|
||||
This function is provided as a convenience to implement qHash() for
|
||||
your own custom types. For example, here's how you could implement
|
||||
a qHash() overload for a class \c{Employee}:
|
||||
|
||||
\snippet code/src_corelib_tools_qhash.cpp 13
|
||||
|
||||
\sa qHashMultiCommutative, qHashRange
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename... T> size_t qHashMultiCommutative(size_t seed, const T &...args)
|
||||
\relates QHash
|
||||
\since 6.0
|
||||
|
||||
Returns the hash value for the \a{args}, using \a seed to seed
|
||||
the calculation, by successively applying qHash() to each
|
||||
element and combining the hash values into a single one.
|
||||
|
||||
The order of the arguments is insignificant. If order does
|
||||
matter, use qHashMulti() instead, as it may produce better quality
|
||||
hashing. If you are hashing raw memory, use qHashBits(); if you are
|
||||
hashing a range, use qHashRange().
|
||||
|
||||
This function is provided as a convenience to implement qHash() for
|
||||
your own custom types.
|
||||
|
||||
\sa qHashMulti, qHashRange
|
||||
*/
|
||||
|
||||
/*! \fn template <typename InputIterator> size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
|
||||
\relates QHash
|
||||
\since 5.5
|
||||
@ -1059,15 +1101,16 @@ size_t qHash(long double key, size_t seed) noexcept
|
||||
the documentation of each class.
|
||||
|
||||
If you want to use other types as the key, make sure that you provide
|
||||
operator==() and a qHash() implementation.
|
||||
operator==() and a qHash() implementation. The convenience qHashMulti()
|
||||
function can be used to implement qHash() for a custom type, where
|
||||
one usually wants to produce a hash value from multiple fields:
|
||||
|
||||
Example:
|
||||
\snippet code/src_corelib_tools_qhash.cpp 13
|
||||
|
||||
In the example above, we've relied on Qt's global qHash(const
|
||||
QString &, uint) to give us a hash value for the employee's name, and
|
||||
XOR'ed this with the day they were born to help produce unique
|
||||
hashes for people with the same name.
|
||||
In the example above, we've relied on Qt's own implementation of
|
||||
qHash() for QString and QDate to give us a hash value for the
|
||||
employee's name and date of birth respectively.
|
||||
|
||||
Note that the implementation of the qHash() overloads offered by Qt
|
||||
may change at any time. You \b{must not} rely on the fact that qHash()
|
||||
|
@ -190,8 +190,54 @@ struct QHashCombineCommutative {
|
||||
{ return seed + qHash(t); } // don't use xor!
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
using QHashMultiReturnType = decltype(
|
||||
std::declval< std::enable_if_t<(sizeof...(T) > 0)> >(),
|
||||
(qHash(std::declval<const T &>()), ...),
|
||||
size_t{}
|
||||
);
|
||||
|
||||
// workaround for a MSVC ICE,
|
||||
// https://developercommunity.visualstudio.com/content/problem/996540/internal-compiler-error-on-msvc-1924-when-doing-sf.html
|
||||
template <typename T>
|
||||
inline constexpr bool QNothrowHashableHelper_v = noexcept(qHash(std::declval<const T &>()));
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct QNothrowHashable : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct QNothrowHashable<T, std::enable_if_t<QNothrowHashableHelper_v<T>>> : std::true_type {};
|
||||
|
||||
} // namespace QtPrivate
|
||||
|
||||
template <typename... T>
|
||||
constexpr
|
||||
#ifdef Q_QDOC
|
||||
size_t
|
||||
#else
|
||||
QtPrivate::QHashMultiReturnType<T...>
|
||||
#endif
|
||||
qHashMulti(size_t seed, const T &... args)
|
||||
noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
return ((seed = hash(seed, args)), ...), seed;
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
constexpr
|
||||
#ifdef Q_QDOC
|
||||
size_t
|
||||
#else
|
||||
QtPrivate::QHashMultiReturnType<T...>
|
||||
#endif
|
||||
qHashMultiCommutative(size_t seed, const T &... args)
|
||||
noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
|
||||
{
|
||||
QtPrivate::QHashCombineCommutative hash;
|
||||
return ((seed = hash(seed, args)), ...), seed;
|
||||
}
|
||||
|
||||
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
|
||||
@ -218,10 +264,7 @@ template <typename T1, typename T2> inline size_t qHash(const QPair<T1, T2> &key
|
||||
template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
|
||||
noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, key.first);
|
||||
seed = hash(seed, key.second);
|
||||
return seed;
|
||||
return qHashMulti(seed, key.first, key.second);
|
||||
}
|
||||
|
||||
#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, Arguments) \
|
||||
|
@ -138,20 +138,19 @@ struct QFontDef
|
||||
|
||||
inline size_t qHash(const QFontDef &fd, size_t seed = 0) noexcept
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, qRound64(fd.pixelSize*10000)); // use only 4 fractional digits
|
||||
seed = hash(seed, fd.weight);
|
||||
seed = hash(seed, fd.style);
|
||||
seed = hash(seed, fd.stretch);
|
||||
seed = hash(seed, fd.styleHint);
|
||||
seed = hash(seed, fd.styleStrategy);
|
||||
seed = hash(seed, fd.ignorePitch);
|
||||
seed = hash(seed, fd.fixedPitch);
|
||||
seed = hash(seed, fd.family);
|
||||
seed = hash(seed, fd.families);
|
||||
seed = hash(seed, fd.styleName);
|
||||
seed = hash(seed, fd.hintingPreference);
|
||||
return seed;
|
||||
return qHashMulti(seed,
|
||||
qRound64(fd.pixelSize*10000), // use only 4 fractional digits
|
||||
fd.weight,
|
||||
fd.style,
|
||||
fd.stretch,
|
||||
fd.styleHint,
|
||||
fd.styleStrategy,
|
||||
fd.ignorePitch,
|
||||
fd.fixedPitch,
|
||||
fd.family,
|
||||
fd.families,
|
||||
fd.styleName,
|
||||
fd.hintingPreference);
|
||||
}
|
||||
|
||||
class QFontEngineData
|
||||
|
@ -410,12 +410,7 @@ inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId
|
||||
inline size_t qHash(const QFontEngine::FaceId &f, size_t seed = 0)
|
||||
noexcept(noexcept(qHash(f.filename)))
|
||||
{
|
||||
QtPrivate::QHashCombine hash;
|
||||
seed = hash(seed, f.filename);
|
||||
seed = hash(seed, f.uuid);
|
||||
seed = hash(seed, f.index);
|
||||
seed = hash(seed, f.encoding);
|
||||
return seed;
|
||||
return qHashMulti(seed, f.filename, f.uuid, f.index, f.encoding);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user