summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qhash.cpp13
-rw-r--r--src/corelib/tools/qhash.h35
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp108
3 files changed, 156 insertions, 0 deletions
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index c1a1b9715f..b49c9d683a 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -1803,6 +1803,19 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
returns \c false.
*/
+/*! \fn QPair<iterator, iterator> QHash::equal_range(const Key &key)
+ \since 5.7
+
+ Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
+ are stored under \a key. If the range is empty then both iterators will be equal to end().
+*/
+
+/*!
+ \fn QPair<const_iterator, const_iterator> QHash::equal_range(const Key &key) const
+ \overload
+ \since 5.7
+*/
+
/*! \typedef QHash::ConstIterator
Qt-style synonym for QHash::const_iterator.
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 819631932b..5e3016d313 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -458,6 +458,8 @@ public:
inline key_iterator keyBegin() const { return key_iterator(begin()); }
inline key_iterator keyEnd() const { return key_iterator(end()); }
+ QPair<iterator, iterator> equal_range(const Key &key);
+ QPair<const_iterator, const_iterator> equal_range(const Key &key) const Q_DECL_NOTHROW;
iterator erase(iterator it) { return erase(const_iterator(it.i)); }
iterator erase(const_iterator it);
@@ -945,6 +947,39 @@ Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
}
template <class Key, class T>
+QPair<typename QHash<Key, T>::iterator, typename QHash<Key, T>::iterator> QHash<Key, T>::equal_range(const Key &akey)
+{
+ detach();
+ auto pair = qAsConst(*this).equal_range(akey);
+ return qMakePair(iterator(pair.first.i), iterator(pair.second.i));
+}
+
+template <class Key, class T>
+QPair<typename QHash<Key, T>::const_iterator, typename QHash<Key, T>::const_iterator> QHash<Key, T>::equal_range(const Key &akey) const Q_DECL_NOTHROW
+{
+ uint h;
+ Node *node = *findNode(akey, &h);
+ const_iterator firstIt = const_iterator(node);
+
+ if (node != e) {
+ // equal keys must hash to the same value and so they all
+ // end up in the same bucket. So we can use node->next,
+ // which only works within a bucket, instead of (out-of-line)
+ // QHashData::nextNode()
+ while (node->next != e && node->next->key == akey)
+ node = node->next;
+
+ // 'node' may be the last node in the bucket. To produce the end iterator, we'd
+ // need to enter the next bucket in this case, so we need to use
+ // QHashData::nextNode() here, which, unlike node->next above, can move between
+ // buckets.
+ node = concrete(QHashData::nextNode(reinterpret_cast<QHashData::Node *>(node)));
+ }
+
+ return qMakePair(firstIt, const_iterator(node));
+}
+
+template <class Key, class T>
class QMultiHash : public QHash<Key, T>
{
public:
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index c62943febc..4336d02b2c 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -32,6 +32,7 @@
#include <qmap.h>
#include <algorithm>
+#include <vector>
class tst_QHash : public QObject
{
@@ -65,6 +66,7 @@ private slots:
void twoArguments_qHash();
void initializerList();
void eraseValidIteratorOnSharedHash();
+ void equal_range();
};
struct IdentityTracker {
@@ -1355,5 +1357,111 @@ void tst_QHash::eraseValidIteratorOnSharedHash()
QCOMPARE(itemsWith10, 3);
}
+void tst_QHash::equal_range()
+{
+ QHash<int, QString> hash;
+
+ auto result = hash.equal_range(0);
+ QCOMPARE(result.first, hash.end());
+ QCOMPARE(result.second, hash.end());
+
+ hash.insert(1, "one");
+
+ result = hash.equal_range(1);
+
+ QCOMPARE(result.first, hash.find(1));
+ QVERIFY(std::distance(result.first, result.second) == 1);
+
+ QHash<int, int> h1;
+ {
+ auto p = h1.equal_range(0);
+ QVERIFY(p.first == p.second);
+ QVERIFY(p.first == h1.end());
+ }
+
+ h1.insert(1, 2);
+ {
+ auto p1 = h1.equal_range(9);
+ QVERIFY(p1.first == p1.second);
+ QVERIFY(p1.first == h1.end());
+ }
+ {
+ auto p2 = h1.equal_range(1);
+ QVERIFY(p2.first != p2.second);
+ QVERIFY(p2.first == h1.begin());
+ QVERIFY(p2.second == h1.end());
+ }
+
+ QMultiHash<int, int> m1 = h1;
+ m1.insert(1, 0);
+ QCOMPARE(m1.size(), 2);
+ {
+ auto p1 = m1.equal_range(9);
+ QVERIFY(p1.first == p1.second);
+ QVERIFY(p1.first == m1.end());
+ }
+ {
+ auto p2 = m1.equal_range(1);
+ QVERIFY(p2.first != p2.second);
+ QVERIFY(p2.first == m1.begin());
+ QVERIFY(p2.second == m1.end());
+ QCOMPARE(std::distance(p2.first, p2.second), 2);
+ }
+
+ m1.insert(0, 0);
+ QCOMPARE(m1.size(), 3);
+ {
+ auto p1 = m1.equal_range(9);
+ QVERIFY(p1.first == p1.second);
+ QVERIFY(p1.first == m1.end());
+ }
+ {
+ const auto p2 = m1.equal_range(1);
+ QVERIFY(p2.first != p2.second);
+ QCOMPARE(p2.first.key(), 1);
+ QCOMPARE(std::distance(p2.first, p2.second), 2);
+ QVERIFY(p2.first == m1.begin() || p2.second == m1.end());
+ }
+
+ const QHash<int, int> ch1 = h1;
+ {
+ auto p1 = ch1.equal_range(9);
+ QVERIFY(p1.first == p1.second);
+ QVERIFY(p1.first == ch1.end());
+ }
+ {
+ auto p2 = ch1.equal_range(1);
+ QVERIFY(p2.first != p2.second);
+ QVERIFY(p2.first == ch1.begin());
+ QVERIFY(p2.second == ch1.end());
+ }
+
+ const QMultiHash<int, int> cm1 = m1;
+ {
+ auto p1 = cm1.equal_range(9);
+ QVERIFY(p1.first == p1.second);
+ QVERIFY(p1.first == cm1.end());
+ }
+ {
+ auto p2 = cm1.equal_range(1);
+ QVERIFY(p2.first != p2.second);
+ QCOMPARE(std::distance(p2.first, p2.second), 2);
+ QVERIFY(p2.first == cm1.cbegin() || p2.second == cm1.cend());
+ }
+
+ QHash<int, int> h2;
+ for (int i = 0; i < 8; ++i)
+ for (int j = 0; j < 8; ++j)
+ h2.insertMulti(i, i*j);
+
+ for (int i = 0; i < 8; ++i) {
+ auto pair = h2.equal_range(i);
+ std::vector<int> vec(pair.first, pair.second);
+ std::sort(vec.begin(), vec.end());
+ for (int j = 0; j < 8; ++j)
+ QCOMPARE(i*j, vec[j]);
+ }
+}
+
QTEST_APPLESS_MAIN(tst_QHash)
#include "tst_qhash.moc"