From 52abff8cc1741412c3fa2c9f6d5185cf48f9ef13 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 2 Feb 2024 16:05:36 -0800 Subject: [PATCH] QHash: add the ability to detect whether qHash(t) == qHash(K(t)) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The typical examples are views and their corresponding owning container. Since they are different types, the search is heterogeneous, hence the name. We have to do it differently from the Standard Library. There, because the hasher is a template parameter to std::unordered_{map,set}, it can be a structure with overloads for different types, all of which the implementer guarantees produce the same hash for input that also compares equal. For QHash/QSet, we don't have a template parameter. One alternative solution would be to detect the existence of qHashEquals(T1, T2) or qHashHeterogeneousEquals() or something. Change-Id: I664b9f014ffc48cbb49bfffd17b0318c0775a2b5 Reviewed-by: Mårten Nordheim --- src/corelib/tools/qhashfunctions.h | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index b7182ac6d4..9056d24102 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -13,6 +13,10 @@ #include // for std::hash #include // For std::pair +#ifdef __cpp_concepts +# include +#endif + #if 0 #pragma qt_class(QHashFunctions) #endif @@ -46,6 +50,15 @@ private: size_t data; }; +// Whether, ∀ t of type T && ∀ seed, qHash(Key(t), seed) == qHash(t, seed) +template struct QHashHeterogeneousSearch : std::false_type {}; + +// Specializations +template <> struct QHashHeterogeneousSearch : std::true_type {}; +template <> struct QHashHeterogeneousSearch : std::true_type {}; +template <> struct QHashHeterogeneousSearch : std::true_type {}; +template <> struct QHashHeterogeneousSearch : std::true_type {}; + namespace QHashPrivate { Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept @@ -217,12 +230,35 @@ 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 concept HeterogeneouslySearchableWithHelper = + // if Key and T are not the same (member already exists) + !std::is_same_v + // but are comparable amongst each other + && std::equality_comparable_with + // and supports heteregenous hashing + && QHashHeterogeneousSearch::value; +template concept HeterogeneouslySearchableWith = + HeterogeneouslySearchableWithHelper, q20::remove_cvref_t>; +#else +template constexpr bool HeterogeneouslySearchableWith = false; +#endif +} + template bool qHashEquals(const T &a, const T &b) { return a == b; } +template +std::enable_if_t, bool> +qHashEquals(const T1 &a, const T2 &b) +{ + return a == b; +} + namespace QtPrivate { struct QHashCombine