summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qhash.cpp20
-rw-r--r--src/corelib/tools/qhash.h21
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp64
3 files changed, 105 insertions, 0 deletions
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 593a87e65d..abec9ebb79 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -2644,4 +2644,24 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
\sa QHash::constFind()
*/
+/*!
+ \fn uint qHash(const QHash<Key, T> &key, uint seed = 0)
+ \since 5.8
+ \relates QHash
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+
+ Type \c T must be supported by qHash().
+*/
+
+/*!
+ \fn uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
+ \since 5.8
+ \relates QMultiHash
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+
+ Type \c T must be supported by qHash().
+*/
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 7abbeabeae..6a2d7bdd11 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -1095,6 +1095,27 @@ Q_INLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &key, const T &value)
Q_DECLARE_ASSOCIATIVE_ITERATOR(Hash)
Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Hash)
+template <class Key, class T>
+uint qHash(const QHash<Key, T> &key, uint seed = 0)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
+{
+ QtPrivate::QHashCombineCommutative hash;
+ for (auto it = key.begin(), end = key.end(); it != end; ++it) {
+ const Key &k = it.key();
+ const T &v = it.value();
+ seed = hash(seed, std::pair<const Key&, const T&>(k, v));
+ }
+ return seed;
+}
+
+template <class Key, class T>
+inline uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
+{
+ const QHash<Key, T> &key2 = key;
+ return qHash(key2, seed);
+}
+
QT_END_NAMESPACE
#if defined(Q_CC_MSVC)
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index cfd2bdc6f7..0b864e71d4 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -49,6 +49,7 @@ private slots:
void find(); // copied from tst_QMap
void constFind(); // copied from tst_QMap
void contains(); // copied from tst_QMap
+ void qhash();
void take(); // copied from tst_QMap
void operator_eq(); // copied from tst_QMap
void rehash_isnt_quadratic();
@@ -695,6 +696,69 @@ void tst_QHash::contains()
QVERIFY(!map1.contains(43));
}
+namespace {
+class QGlobalQHashSeedResetter
+{
+ int oldSeed;
+public:
+ // not entirely correct (may lost changes made by another thread between the query
+ // of the old and the setting of the new seed), but qSetGlobalQHashSeed doesn't
+ // return the old value, so this is the best we can do:
+ explicit QGlobalQHashSeedResetter(int newSeed)
+ : oldSeed(qGlobalQHashSeed())
+ {
+ qSetGlobalQHashSeed(newSeed);
+ }
+ ~QGlobalQHashSeedResetter()
+ {
+ qSetGlobalQHashSeed(oldSeed);
+ }
+};
+
+template <typename Key, typename T>
+QHash<T, Key> inverted(const QHash<Key, T> &in)
+{
+ QHash<T, Key> result;
+ for (auto it = in.begin(), end = in.end(); it != end; ++it)
+ result[it.value()] = it.key();
+ return result;
+}
+
+template <typename AssociativeContainer>
+void make_test_data(AssociativeContainer &c)
+{
+ c["one"] = "1";
+ c["two"] = "2";
+}
+
+}
+
+void tst_QHash::qhash()
+{
+ const QGlobalQHashSeedResetter seed1(0);
+
+ QHash<QString, QString> hash1;
+ make_test_data(hash1);
+ const QHash<QString, QString> hsah1 = inverted(hash1);
+
+ const QGlobalQHashSeedResetter seed2(1);
+
+ QHash<QString, QString> hash2;
+ make_test_data(hash2);
+ const QHash<QString, QString> hsah2 = inverted(hash2);
+
+ QCOMPARE(hash1, hash2);
+ QCOMPARE(hsah1, hsah2);
+ QCOMPARE(qHash(hash1), qHash(hash2));
+ QCOMPARE(qHash(hsah1), qHash(hsah2));
+
+ // by construction this is almost impossible to cause false collisions:
+ QVERIFY(hash1 != hsah1);
+ QVERIFY(hash2 != hsah2);
+ QVERIFY(qHash(hash1) != qHash(hsah1));
+ QVERIFY(qHash(hash2) != qHash(hsah2));
+}
+
//copied from tst_QMap
void tst_QHash::take()
{