diff options
Diffstat (limited to 'src/corelib/tools/qhashfunctions.h')
-rw-r--r-- | src/corelib/tools/qhashfunctions.h | 226 |
1 files changed, 160 insertions, 66 deletions
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index 018c317834..90a269deaa 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -1,51 +1,21 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +// Copyright (C) 2024 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QHASHFUNCTIONS_H #define QHASHFUNCTIONS_H #include <QtCore/qstring.h> -#include <QtCore/qpair.h> +#include <QtCore/qstringfwd.h> #include <numeric> // for std::accumulate #include <functional> // for std::hash +#include <utility> // For std::pair + +#ifdef __cpp_concepts +# include <concepts> +#endif #if 0 #pragma qt_class(QHashFunctions) @@ -60,13 +30,40 @@ QT_BEGIN_NAMESPACE class QBitArray; -class QByteArray; -class QString; -class QLatin1String; -// ### Qt 7: these should use size_t, not int. +#if QT_DEPRECATED_SINCE(6,6) +QT_DEPRECATED_VERSION_X_6_6("Use QHashSeed instead") Q_CORE_EXPORT int qGlobalQHashSeed(); +QT_DEPRECATED_VERSION_X_6_6("Use QHashSeed instead") Q_CORE_EXPORT void qSetGlobalQHashSeed(int newSeed); +#endif + +struct QHashSeed +{ + constexpr QHashSeed(size_t d = 0) : data(d) {} + constexpr operator size_t() const noexcept { return data; } + + static Q_CORE_EXPORT QHashSeed globalSeed() noexcept; + static Q_CORE_EXPORT void setDeterministicGlobalSeed(); + static Q_CORE_EXPORT void resetRandomGlobalSeed(); +private: + size_t data; +}; + +// Whether, ∀ t of type T && ∀ seed, qHash(Key(t), seed) == qHash(t, seed) +template <typename Key, typename T> struct QHashHeterogeneousSearch : std::false_type {}; + +// Specializations +template <> struct QHashHeterogeneousSearch<QString, QStringView> : std::true_type {}; +template <> struct QHashHeterogeneousSearch<QStringView, QString> : std::true_type {}; +template <> struct QHashHeterogeneousSearch<QByteArray, QByteArrayView> : std::true_type {}; +template <> struct QHashHeterogeneousSearch<QByteArrayView, QByteArray> : std::true_type {}; +#ifndef Q_PROCESSOR_ARM +template <> struct QHashHeterogeneousSearch<QString, QLatin1StringView> : std::true_type {}; +template <> struct QHashHeterogeneousSearch<QStringView, QLatin1StringView> : std::true_type {}; +template <> struct QHashHeterogeneousSearch<QLatin1StringView, QString> : std::true_type {}; +template <> struct QHashHeterogeneousSearch<QLatin1StringView, QStringView> : std::true_type {}; +#endif namespace QHashPrivate { @@ -91,18 +88,15 @@ Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept } } -template <typename T, typename = void> -constexpr inline bool HasQHashSingleArgOverload = false; - -template <typename T> -constexpr inline bool HasQHashSingleArgOverload<T, std::enable_if_t< - std::is_convertible_v<decltype(qHash(std::declval<const T &>())), size_t> ->> = true; - +template <typename T1, typename T2> static constexpr bool noexceptPairHash(); } Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHashBits(const void *p, size_t size, size_t seed = 0) noexcept; +// implementation below qHashMulti +template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0) + noexcept(QHashPrivate::noexceptPairHash<T1, T2>()); + // C++ builtin types Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char key, size_t seed = 0) noexcept { return QHashPrivate::hash(size_t(key), seed); } @@ -128,7 +122,39 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(quint64 key, size_t seed = 0 key ^= (key >> 32); return QHashPrivate::hash(size_t(key), seed); } -Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept { return qHash(quint64(key), seed); } +Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept +{ + if constexpr (sizeof(qint64) > sizeof(size_t)) { + // Avoid QTBUG-116080: we XOR the top half with its own sign bit: + // - if the qint64 is in range of qint32, then signmask ^ high == 0 + // (for Qt 7 only) + // - if the qint64 is in range of quint32, then signmask == 0 and we + // do the same as the quint64 overload above + quint32 high = quint32(quint64(key) >> 32); + quint32 low = quint32(quint64(key)); + quint32 signmask = qint32(high) >> 31; // all zeroes or all ones + signmask = QT_VERSION_MAJOR > 6 ? signmask : 0; + low ^= signmask ^ high; + return qHash(low, seed); + } + return qHash(quint64(key), seed); +} +#if QT_SUPPORTS_INT128 +constexpr size_t qHash(quint128 key, size_t seed = 0) noexcept +{ + return qHash(quint64(key + (key >> 64)), seed); +} +constexpr size_t qHash(qint128 key, size_t seed = 0) noexcept +{ + // Avoid QTBUG-116080: same as above, but with double the sizes and without + // the need for compatibility + quint64 high = quint64(quint128(key) >> 64); + quint64 low = quint64(quint128(key)); + quint64 signmask = qint64(high) >> 63; // all zeroes or all ones + low += signmask ^ high; + return qHash(low, seed); +} +#endif // QT_SUPPORTS_INT128 Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept { // ensure -0 gets mapped to 0 @@ -138,9 +164,7 @@ Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept return QHashPrivate::hash(k, seed); } Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(double key, size_t seed = 0) noexcept; -#if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC) Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(long double key, size_t seed = 0) noexcept; -#endif Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(wchar_t key, size_t seed = 0) noexcept { return QHashPrivate::hash(size_t(key), seed); } Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char16_t key, size_t seed = 0) noexcept @@ -159,25 +183,74 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed { return seed; } +template <class Enum, std::enable_if_t<std::is_enum_v<Enum>, bool> = true> +Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(Enum e, size_t seed = 0) noexcept +{ return QHashPrivate::hash(qToUnderlying(e), seed); } // (some) Qt types Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(const QChar key, size_t seed = 0) noexcept { return qHash(key.unicode(), seed); } + +#if QT_CORE_REMOVED_SINCE(6, 4) Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0) noexcept; Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArrayView &key, size_t seed = 0) noexcept; +#else +Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QByteArrayView key, size_t seed = 0) noexcept; +inline Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0 + QT6_DECL_NEW_OVERLOAD_TAIL) noexcept +{ return qHash(qToByteArrayViewIgnoringNull(key), seed); } +#endif + Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept; -#if QT_STRINGVIEW_LEVEL < 2 inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept { return qHash(QStringView{key}, seed); } -#endif +#ifndef QT_BOOTSTRAPPED Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &key, size_t seed = 0) noexcept; -Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1String key, size_t seed = 0) noexcept; +#endif +Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1StringView key, size_t seed = 0) noexcept; Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QKeyCombination key, size_t seed = 0) noexcept { return qHash(key.toCombined(), seed); } Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) noexcept; -template <typename T, std::enable_if_t<QHashPrivate::HasQHashSingleArgOverload<T>, bool> = true> +template <typename Enum> +Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QFlags<Enum> flags, size_t seed = 0) noexcept +{ return qHash(flags.toInt(), seed); } + +// ### Qt 7: remove this "catch-all" overload logic, and require users +// to provide the two-argument version of qHash. +#if (QT_VERSION < QT_VERSION_CHECK(7, 0, 0)) +// Beware of moving this code from here. It needs to see all the +// declarations of qHash overloads for C++ fundamental types *before* +// its own declaration. +namespace QHashPrivate { +template <typename T, typename = void> +constexpr inline bool HasQHashSingleArgOverload = false; + +template <typename T> +constexpr inline bool HasQHashSingleArgOverload<T, std::enable_if_t< + std::is_convertible_v<decltype(qHash(std::declval<const T &>())), size_t> +>> = true; +} + +template <typename T, std::enable_if_t<QHashPrivate::HasQHashSingleArgOverload<T> && !std::is_enum_v<T>, bool> = true> size_t qHash(const T &t, size_t seed) noexcept(noexcept(qHash(t))) { return qHash(t) ^ seed; } +#endif // < Qt 7 + +namespace QHashPrivate { +#ifdef __cpp_concepts +template <typename Key, typename T> concept HeterogeneouslySearchableWithHelper = + // if Key and T are not the same (member already exists) + !std::is_same_v<Key, T> + // but are comparable amongst each other + && std::equality_comparable_with<Key, T> + // and supports heteregenous hashing + && QHashHeterogeneousSearch<Key, T>::value; +template <typename Key, typename T> concept HeterogeneouslySearchableWith = + HeterogeneouslySearchableWithHelper<q20::remove_cvref_t<Key>, q20::remove_cvref_t<T>>; +#else +template <typename Key, typename T> constexpr bool HeterogeneouslySearchableWith = false; +#endif +} template<typename T> bool qHashEquals(const T &a, const T &b) @@ -185,6 +258,13 @@ bool qHashEquals(const T &a, const T &b) return a == b; } +template <typename T1, typename T2> +std::enable_if_t<QHashPrivate::HeterogeneouslySearchableWith<T1, T2>, bool> +qHashEquals(const T1 &a, const T2 &b) +{ + return a == b; +} + namespace QtPrivate { struct QHashCombine @@ -227,6 +307,9 @@ struct QNothrowHashable : std::false_type {}; template <typename T> struct QNothrowHashable<T, std::enable_if_t<QNothrowHashableHelper_v<T>>> : std::true_type {}; +template <typename T> +constexpr inline bool QNothrowHashable_v = QNothrowHashable<T>::value; + } // namespace QtPrivate template <typename... T> @@ -271,8 +354,16 @@ inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, siz return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative()); } -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))) +namespace QHashPrivate { +template <typename T1, typename T2> static constexpr bool noexceptPairHash() +{ + size_t seed = 0; + return noexcept(qHash(std::declval<T1>(), seed)) && noexcept(qHash(std::declval<T2>(), seed)); +} +} // QHashPrivate + +template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed) + noexcept(QHashPrivate::noexceptPairHash<T1, T2>()) { return qHashMulti(seed, key.first, key.second); } @@ -285,15 +376,15 @@ template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> using argument_type = QT_PREPEND_NAMESPACE(Class); \ using result_type = size_t; \ size_t operator()(Arguments s) const \ - noexcept(noexcept(QT_PREPEND_NAMESPACE(qHash)(s))) \ + noexcept(QT_PREPEND_NAMESPACE( \ + QtPrivate::QNothrowHashable_v)<argument_type>) \ { \ /* this seeds qHash with the result of */ \ /* std::hash applied to an int, to reap */ \ /* any protection against predictable hash */ \ /* values the std implementation may provide */ \ - return QT_PREPEND_NAMESPACE(qHash)(s, \ - QT_PREPEND_NAMESPACE(qHash)( \ - std::hash<int>{}(0))); \ + using QT_PREPEND_NAMESPACE(qHash); \ + return qHash(s, qHash(std::hash<int>{}(0))); \ } \ }; \ } \ @@ -307,9 +398,12 @@ template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QString) QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QStringView) -QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QLatin1String) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QLatin1StringView) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QByteArrayView) QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QByteArray) +#ifndef QT_BOOTSTRAPPED QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QBitArray) +#endif QT_END_NAMESPACE |