diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index 4c2eba3e536..4f8e4066ee9 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -114,10 +114,15 @@ constexpr inline bool HasQHashSingleArgOverload())), size_t> >> = true; +template 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 inline size_t qHash(const std::pair &key, size_t seed = 0) + noexcept(QHashPrivate::noexceptPairHash()); + // 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 inline size_t qHash(const std::pair &key, size_t seed = 0) - noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed))) +namespace QHashPrivate { +template static constexpr bool noexceptPairHash() +{ + size_t seed = 0; + return noexcept(qHash(std::declval(), seed)) && noexcept(qHash(std::declval(), seed)); +} +} // QHashPrivate + +template inline size_t qHash(const std::pair &key, size_t seed) + noexcept(QHashPrivate::noexceptPairHash()) { return qHashMulti(seed, key.first, key.second); } diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp index d313fbb0b0d..a440d43454a 100644 --- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp +++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp @@ -46,6 +46,8 @@ public: }; uint seed; + template 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 +void tst_QHashFunctions::stdPair_template(const T1 &t1, const T2 &t2) +{ + std::pair dpair{}; + std::pair 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