Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qhashfunctions.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
3// Copyright (C) 2024 Intel Corporation.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#ifndef QHASHFUNCTIONS_H
7#define QHASHFUNCTIONS_H
8
9#include <QtCore/qstring.h>
10#include <QtCore/qstringfwd.h>
11
12#include <numeric> // for std::accumulate
13#include <functional> // for std::hash
14#include <utility> // For std::pair
15
16#ifdef __cpp_concepts
17# include <concepts>
18#endif
19
20#if 0
21#pragma qt_class(QHashFunctions)
22#endif
23
24#if defined(Q_CC_MSVC)
25#pragma warning( push )
26#pragma warning( disable : 4311 ) // disable pointer truncation warning
27#pragma warning( disable : 4127 ) // conditional expression is constant
28#endif
29
31
32class QBitArray;
33
34#if QT_DEPRECATED_SINCE(6,6)
35QT_DEPRECATED_VERSION_X_6_6("Use QHashSeed instead")
36Q_CORE_EXPORT int qGlobalQHashSeed();
38Q_CORE_EXPORT void qSetGlobalQHashSeed(int newSeed);
39#endif
40
42{
43 constexpr QHashSeed(size_t d = 0) : data(d) {}
44 constexpr operator size_t() const noexcept { return data; }
45
46 static Q_CORE_EXPORT QHashSeed globalSeed() noexcept;
47 static Q_CORE_EXPORT void setDeterministicGlobalSeed();
48 static Q_CORE_EXPORT void resetRandomGlobalSeed();
50 size_t data;
51};
52
53// Whether, ∀ t of type T && ∀ seed, qHash(Key(t), seed) == qHash(t, seed)
54template <typename Key, typename T> struct QHashHeterogeneousSearch : std::false_type {};
55
56// Specializations
57template <> struct QHashHeterogeneousSearch<QString, QStringView> : std::true_type {};
58template <> struct QHashHeterogeneousSearch<QStringView, QString> : std::true_type {};
59template <> struct QHashHeterogeneousSearch<QByteArray, QByteArrayView> : std::true_type {};
60template <> struct QHashHeterogeneousSearch<QByteArrayView, QByteArray> : std::true_type {};
61#ifndef Q_PROCESSOR_ARM
62template <> struct QHashHeterogeneousSearch<QString, QLatin1StringView> : std::true_type {};
63template <> struct QHashHeterogeneousSearch<QStringView, QLatin1StringView> : std::true_type {};
64template <> struct QHashHeterogeneousSearch<QLatin1StringView, QString> : std::true_type {};
65template <> struct QHashHeterogeneousSearch<QLatin1StringView, QStringView> : std::true_type {};
66#endif
67
68namespace QHashPrivate {
69
70Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
71{
72 key ^= seed;
73 if constexpr (sizeof(size_t) == 4) {
74 key ^= key >> 16;
75 key *= UINT32_C(0x45d9f3b);
76 key ^= key >> 16;
77 key *= UINT32_C(0x45d9f3b);
78 key ^= key >> 16;
79 return key;
80 } else {
81 quint64 key64 = key;
82 key64 ^= key64 >> 32;
83 key64 *= UINT64_C(0xd6e8feb86659fd93);
84 key64 ^= key64 >> 32;
85 key64 *= UINT64_C(0xd6e8feb86659fd93);
86 key64 ^= key64 >> 32;
87 return size_t(key64);
88 }
89}
90
91template <typename T1, typename T2> static constexpr bool noexceptPairHash();
92}
93
94Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHashBits(const void *p, size_t size, size_t seed = 0) noexcept;
95
96// implementation below qHashMulti
97template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
98 noexcept(QHashPrivate::noexceptPairHash<T1, T2>());
99
100// C++ builtin types
101Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char key, size_t seed = 0) noexcept
102{ return QHashPrivate::hash(size_t(key), seed); }
103Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(uchar key, size_t seed = 0) noexcept
104{ return QHashPrivate::hash(size_t(key), seed); }
105Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(signed char key, size_t seed = 0) noexcept
106{ return QHashPrivate::hash(size_t(key), seed); }
107Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(ushort key, size_t seed = 0) noexcept
108{ return QHashPrivate::hash(size_t(key), seed); }
109Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(short key, size_t seed = 0) noexcept
110{ return QHashPrivate::hash(size_t(key), seed); }
111Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(uint key, size_t seed = 0) noexcept
112{ return QHashPrivate::hash(size_t(key), seed); }
113Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(int key, size_t seed = 0) noexcept
114{ return QHashPrivate::hash(size_t(key), seed); }
115Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(ulong key, size_t seed = 0) noexcept
116{ return QHashPrivate::hash(size_t(key), seed); }
117Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(long key, size_t seed = 0) noexcept
118{ return QHashPrivate::hash(size_t(key), seed); }
119Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(quint64 key, size_t seed = 0) noexcept
120{
121 if constexpr (sizeof(quint64) > sizeof(size_t))
122 key ^= (key >> 32);
123 return QHashPrivate::hash(size_t(key), seed);
124}
125Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept
126{
127 if constexpr (sizeof(qint64) > sizeof(size_t)) {
128 // Avoid QTBUG-116080: we XOR the top half with its own sign bit:
129 // - if the qint64 is in range of qint32, then signmask ^ high == 0
130 // (for Qt 7 only)
131 // - if the qint64 is in range of quint32, then signmask == 0 and we
132 // do the same as the quint64 overload above
133 quint32 high = quint32(quint64(key) >> 32);
134 quint32 low = quint32(quint64(key));
135 quint32 signmask = qint32(high) >> 31; // all zeroes or all ones
136 signmask = QT_VERSION_MAJOR > 6 ? signmask : 0;
137 low ^= signmask ^ high;
138 return qHash(low, seed);
139 }
140 return qHash(quint64(key), seed);
141}
142#if QT_SUPPORTS_INT128
143constexpr size_t qHash(quint128 key, size_t seed = 0) noexcept
144{
145 return qHash(quint64(key + (key >> 64)), seed);
146}
147constexpr size_t qHash(qint128 key, size_t seed = 0) noexcept
148{
149 // Avoid QTBUG-116080: same as above, but with double the sizes and without
150 // the need for compatibility
151 quint64 high = quint64(quint128(key) >> 64);
152 quint64 low = quint64(quint128(key));
153 quint64 signmask = qint64(high) >> 63; // all zeroes or all ones
154 low += signmask ^ high;
155 return qHash(low, seed);
156}
157#endif // QT_SUPPORTS_INT128
158Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
159{
160 // ensure -0 gets mapped to 0
161 key += 0.0f;
162 uint k;
163 memcpy(&k, &key, sizeof(float));
164 return QHashPrivate::hash(k, seed);
165}
166Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(double key, size_t seed = 0) noexcept;
167Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(long double key, size_t seed = 0) noexcept;
168Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(wchar_t key, size_t seed = 0) noexcept
169{ return QHashPrivate::hash(size_t(key), seed); }
170Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char16_t key, size_t seed = 0) noexcept
171{ return QHashPrivate::hash(size_t(key), seed); }
172Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char32_t key, size_t seed = 0) noexcept
173{ return QHashPrivate::hash(size_t(key), seed); }
174#ifdef __cpp_char8_t
175Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char8_t key, size_t seed = 0) noexcept
176{ return QHashPrivate::hash(size_t(key), seed); }
177#endif
178template <class T> inline size_t qHash(const T *key, size_t seed = 0) noexcept
179{
180 return qHash(reinterpret_cast<quintptr>(key), seed);
181}
182Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed = 0) noexcept
183{
184 return seed;
185}
186template <class Enum, std::enable_if_t<std::is_enum_v<Enum>, bool> = true>
187Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(Enum e, size_t seed = 0) noexcept
189
190// (some) Qt types
191Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(const QChar key, size_t seed = 0) noexcept { return qHash(key.unicode(), seed); }
192
193#if QT_CORE_REMOVED_SINCE(6, 4)
194Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0) noexcept;
195Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArrayView &key, size_t seed = 0) noexcept;
196#else
197Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QByteArrayView key, size_t seed = 0) noexcept;
198inline Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0
201#endif
202
203Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept;
204inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept
205{ return qHash(QStringView{key}, seed); }
206#ifndef QT_BOOTSTRAPPED
207Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &key, size_t seed = 0) noexcept;
208#endif
209Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1StringView key, size_t seed = 0) noexcept;
210Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QKeyCombination key, size_t seed = 0) noexcept
211{ return qHash(key.toCombined(), seed); }
212Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) noexcept;
213
214template <typename Enum>
215Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QFlags<Enum> flags, size_t seed = 0) noexcept
216{ return qHash(flags.toInt(), seed); }
217
218// ### Qt 7: remove this "catch-all" overload logic, and require users
219// to provide the two-argument version of qHash.
220#if (QT_VERSION < QT_VERSION_CHECK(7, 0, 0))
221// Beware of moving this code from here. It needs to see all the
222// declarations of qHash overloads for C++ fundamental types *before*
223// its own declaration.
224namespace QHashPrivate {
225template <typename T, typename = void>
226constexpr inline bool HasQHashSingleArgOverload = false;
227
228template <typename T>
229constexpr inline bool HasQHashSingleArgOverload<T, std::enable_if_t<
230 std::is_convertible_v<decltype(qHash(std::declval<const T &>())), size_t>
231>> = true;
232}
233
234template <typename T, std::enable_if_t<QHashPrivate::HasQHashSingleArgOverload<T> && !std::is_enum_v<T>, bool> = true>
235size_t qHash(const T &t, size_t seed) noexcept(noexcept(qHash(t)))
236{ return qHash(t) ^ seed; }
237#endif // < Qt 7
238
239namespace QHashPrivate {
240#ifdef __cpp_concepts
241template <typename Key, typename T> concept HeterogeneouslySearchableWithHelper =
242 // if Key and T are not the same (member already exists)
243 !std::is_same_v<Key, T>
244 // but are comparable amongst each other
245 && std::equality_comparable_with<Key, T>
246 // and supports heteregenous hashing
248template <typename Key, typename T> concept HeterogeneouslySearchableWith =
249 HeterogeneouslySearchableWithHelper<q20::remove_cvref_t<Key>, q20::remove_cvref_t<T>>;
250#else
251template <typename Key, typename T> constexpr bool HeterogeneouslySearchableWith = false;
252#endif
253}
254
255template<typename T>
256bool qHashEquals(const T &a, const T &b)
257{
258 return a == b;
259}
260
261template <typename T1, typename T2>
262std::enable_if_t<QHashPrivate::HeterogeneouslySearchableWith<T1, T2>, bool>
263qHashEquals(const T1 &a, const T2 &b)
264{
265 return a == b;
266}
267
268namespace QtPrivate {
269
271{
272 typedef size_t result_type;
273 template <typename T>
274 constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
275 // combiner taken from N3876 / boost::hash_combine
276 { return seed ^ (qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2)) ; }
277};
278
280{
281 // QHashCombine is a good hash combiner, but is not commutative,
282 // ie. it depends on the order of the input elements. That is
283 // usually what we want: {0,1,3} should hash differently than
284 // {1,3,0}. Except when it isn't (e.g. for QSet and
285 // QHash). Therefore, provide a commutative combiner, too.
286 typedef size_t result_type;
287 template <typename T>
288 constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
289 { return seed + qHash(t); } // don't use xor!
290};
291
292template <typename... T>
293using QHashMultiReturnType = decltype(
294 std::declval< std::enable_if_t<(sizeof...(T) > 0)> >(),
295 (qHash(std::declval<const T &>()), ...),
296 size_t{}
297);
298
299// workaround for a MSVC ICE,
300// https://developercommunity.visualstudio.com/content/problem/996540/internal-compiler-error-on-msvc-1924-when-doing-sf.html
301template <typename T>
302inline constexpr bool QNothrowHashableHelper_v = noexcept(qHash(std::declval<const T &>()));
303
304template <typename T, typename Enable = void>
305struct QNothrowHashable : std::false_type {};
306
307template <typename T>
308struct QNothrowHashable<T, std::enable_if_t<QNothrowHashableHelper_v<T>>> : std::true_type {};
309
310template <typename T>
312
313} // namespace QtPrivate
314
315template <typename... T>
316constexpr
317#ifdef Q_QDOC
318size_t
319#else
321#endif
322qHashMulti(size_t seed, const T &... args)
323 noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
324{
326 return ((seed = hash(seed, args)), ...), seed;
327}
328
329template <typename... T>
330constexpr
331#ifdef Q_QDOC
332size_t
333#else
335#endif
336qHashMultiCommutative(size_t seed, const T &... args)
337 noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
338{
340 return ((seed = hash(seed, args)), ...), seed;
341}
342
343template <typename InputIterator>
344inline size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
345 noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
346{
347 return std::accumulate(first, last, seed, QtPrivate::QHashCombine());
348}
349
350template <typename InputIterator>
351inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
352 noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
353{
354 return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative());
355}
356
357namespace QHashPrivate {
358template <typename T1, typename T2> static constexpr bool noexceptPairHash()
359{
360 size_t seed = 0;
361 return noexcept(qHash(std::declval<T1>(), seed)) && noexcept(qHash(std::declval<T2>(), seed));
362}
363} // QHashPrivate
364
365template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed)
366 noexcept(QHashPrivate::noexceptPairHash<T1, T2>())
367{
368 return qHashMulti(seed, key.first, key.second);
369}
370
371#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, Arguments) \
372 QT_BEGIN_INCLUDE_NAMESPACE \
373 namespace std { \
374 template <> \
375 struct hash< QT_PREPEND_NAMESPACE(Class) > { \
376 using argument_type = QT_PREPEND_NAMESPACE(Class); \
377 using result_type = size_t; \
378 size_t operator()(Arguments s) const \
379 noexcept(QT_PREPEND_NAMESPACE( \
380 QtPrivate::QNothrowHashable_v)<argument_type>) \
381 { \
382 /* this seeds qHash with the result of */ \
383 /* std::hash applied to an int, to reap */ \
384 /* any protection against predictable hash */ \
385 /* values the std implementation may provide */ \
386 using QT_PREPEND_NAMESPACE(qHash); \
387 return qHash(s, qHash(std::hash<int>{}(0))); \
388 } \
389 }; \
390 } \
391 QT_END_INCLUDE_NAMESPACE \
392 /*end*/
393
394#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(Class) \
395 QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, const argument_type &)
396#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(Class) \
397 QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, argument_type)
398
404#ifndef QT_BOOTSTRAPPED
406#endif
407
409
410#if defined(Q_CC_MSVC)
411#pragma warning( pop )
412#endif
413
414#endif // QHASHFUNCTIONS_H
\inmodule QtCore
Definition qbitarray.h:13
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QHash< int, QWidget * > hash
[35multi]
Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
constexpr bool HeterogeneouslySearchableWith
static constexpr bool noexceptPairHash()
Combined button and popup list for selecting options.
\macro QT_NO_KEYWORDS >
decltype( std::declval< std::enable_if_t<(sizeof...(T) > 0)> >(),(qHash(std::declval< const T & >()),...), size_t{}) QHashMultiReturnType
constexpr bool QNothrowHashableHelper_v
constexpr bool QNothrowHashable_v
std::remove_cv_t< std::remove_reference_t< T > > remove_cvref_t
QByteArrayView qToByteArrayViewIgnoringNull(const QByteArrayLike &b) noexcept
#define Q_DECL_PURE_FUNCTION
#define Q_DECL_CONST_FUNCTION
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(Class)
bool qHashEquals(const T &a, const T &b)
size_t qHash(const std::pair< T1, T2 > &key, size_t seed=0) noexcept(QHashPrivate::noexceptPairHash< T1, T2 >())
#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(Class)
size_t qHashRange(InputIterator first, InputIterator last, size_t seed=0) noexcept(noexcept(qHash(*first)))
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHashBits(const void *p, size_t size, size_t seed=0) noexcept
Definition qhash.cpp:1089
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMultiCommutative(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained=0) noexcept
Definition qhash.cpp:1325
size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed=0) noexcept(noexcept(qHash(*first)))
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
GLboolean GLboolean GLboolean b
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLbitfield flags
GLint first
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define QT_DEPRECATED_VERSION_X_6_6(text)
QT_BEGIN_NAMESPACE constexpr std::underlying_type_t< Enum > qToUnderlying(Enum e) noexcept
#define QT6_DECL_NEW_OVERLOAD_TAIL
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
size_t quintptr
Definition qtypes.h:167
int qint32
Definition qtypes.h:49
unsigned long ulong
Definition qtypes.h:35
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned short ushort
Definition qtypes.h:33
QJSValueList args
\inmodule QtCore
static Q_CORE_EXPORT void setDeterministicGlobalSeed()
\threadsafe
Definition qhash.cpp:1230
static Q_CORE_EXPORT void resetRandomGlobalSeed()
\threadsafe
Definition qhash.cpp:1250
constexpr QHashSeed(size_t d=0)
Constructs a new QHashSeed object using data as the seed.
static Q_CORE_EXPORT QHashSeed globalSeed() noexcept
\threadsafe
Definition qhash.cpp:1216
constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))