QHash: fix qHash(std::pair)
There were two problems here: first, qHash(std::pair) must be declared before qHashMulti that might call back to qHash(std::pair) (i.e., a pair with one element that is also a pair). But moving the declaration above causes the second problem: the noexcept expression can't refer to qHash functions that aren't declared yet. So we forward-declare a constexpr function for that result, but implement it far below. Fixes: QTBUG-92910 Change-Id: Ia8e48103a54446509e3bfffd16767ed2e29b026c Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
a5ff71578d
commit
64bfc927b0
@ -114,10 +114,15 @@ 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); }
|
||||
@ -290,8 +295,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);
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
};
|
||||
uint seed;
|
||||
|
||||
template <typename T1, typename T2> void stdPair_template(const T1 &t1, const T2 &t2);
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
void init();
|
||||
@ -63,6 +65,18 @@ private Q_SLOTS:
|
||||
|
||||
void stdHash();
|
||||
|
||||
void stdPair_int_int() { stdPair_template(1, 2); }
|
||||
void stdPair_ulong_llong() { stdPair_template(1UL, -2LL); }
|
||||
void stdPair_ullong_long() { stdPair_template(1ULL, -2L); }
|
||||
void stdPair_string_int() { stdPair_template(QString("Hello"), 2); }
|
||||
void stdPair_int_string() { stdPair_template(1, QString("Hello")); }
|
||||
void stdPair_bytearray_string() { stdPair_template(QByteArray("Hello"), QString("World")); }
|
||||
void stdPair_string_bytearray() { stdPair_template(QString("Hello"), QByteArray("World")); }
|
||||
void stdPair_int_pairIntInt() { stdPair_template(1, std::make_pair(2, 3)); }
|
||||
void stdPair_2x_pairIntInt() { stdPair_template(std::make_pair(1, 2), std::make_pair(2, 3)); }
|
||||
void stdPair_string_pairIntInt() { stdPair_template(QString("Hello"), std::make_pair(42, -47)); } // QTBUG-92910
|
||||
void stdPair_int_pairIntPairIntInt() { stdPair_template(1, std::make_pair(2, std::make_pair(3, 4))); }
|
||||
|
||||
void setGlobalQHashSeed();
|
||||
};
|
||||
|
||||
@ -310,6 +324,32 @@ void tst_QHashFunctions::stdHash()
|
||||
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void tst_QHashFunctions::stdPair_template(const T1 &t1, const T2 &t2)
|
||||
{
|
||||
std::pair<T1, T2> dpair{};
|
||||
std::pair<T1, T2> vpair{t1, t2};
|
||||
|
||||
size_t seed = QHashSeed::globalSeed();
|
||||
|
||||
// confirm proper working of the pair and of the underlying types
|
||||
QVERIFY(t1 == t1);
|
||||
QVERIFY(t2 == t2);
|
||||
QCOMPARE(qHash(t1), qHash(t1));
|
||||
QCOMPARE(qHash(t2), qHash(t2));
|
||||
QCOMPARE(qHash(t1, seed), qHash(t1, seed));
|
||||
QCOMPARE(qHash(t2, seed), qHash(t2, seed));
|
||||
|
||||
QVERIFY(dpair == dpair);
|
||||
QVERIFY(vpair == vpair);
|
||||
|
||||
// therefore their hashes should be equal
|
||||
QCOMPARE(qHash(dpair), qHash(dpair));
|
||||
QCOMPARE(qHash(dpair, seed), qHash(dpair, seed));
|
||||
QCOMPARE(qHash(vpair), qHash(vpair));
|
||||
QCOMPARE(qHash(vpair, seed), qHash(vpair, seed));
|
||||
}
|
||||
|
||||
void tst_QHashFunctions::setGlobalQHashSeed()
|
||||
{
|
||||
// Setter works as advertised
|
||||
|
Loading…
Reference in New Issue
Block a user