Introduce QHash::equal_range()
Similar to QMap::equal_range(). Will allow to easily fix inefficient code such as: foreach (auto value, hash.values(key)) { ... } [ChangeLog][QtCore][QHash] Added QHash::equal_range() Change-Id: I6e19e25de632e897ad83d3141d9d07f0313f7200 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
parent
26dca142a7
commit
6139fbeb5f
@ -1803,6 +1803,19 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
|
|||||||
returns \c false.
|
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
|
/*! \typedef QHash::ConstIterator
|
||||||
|
|
||||||
Qt-style synonym for QHash::const_iterator.
|
Qt-style synonym for QHash::const_iterator.
|
||||||
|
@ -458,6 +458,8 @@ public:
|
|||||||
inline key_iterator keyBegin() const { return key_iterator(begin()); }
|
inline key_iterator keyBegin() const { return key_iterator(begin()); }
|
||||||
inline key_iterator keyEnd() const { return key_iterator(end()); }
|
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(iterator it) { return erase(const_iterator(it.i)); }
|
||||||
iterator erase(const_iterator it);
|
iterator erase(const_iterator it);
|
||||||
|
|
||||||
@ -944,6 +946,39 @@ Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>
|
template <class Key, class T>
|
||||||
class QMultiHash : public QHash<Key, T>
|
class QMultiHash : public QHash<Key, T>
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <qmap.h>
|
#include <qmap.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class tst_QHash : public QObject
|
class tst_QHash : public QObject
|
||||||
{
|
{
|
||||||
@ -65,6 +66,7 @@ private slots:
|
|||||||
void twoArguments_qHash();
|
void twoArguments_qHash();
|
||||||
void initializerList();
|
void initializerList();
|
||||||
void eraseValidIteratorOnSharedHash();
|
void eraseValidIteratorOnSharedHash();
|
||||||
|
void equal_range();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IdentityTracker {
|
struct IdentityTracker {
|
||||||
@ -1355,5 +1357,111 @@ void tst_QHash::eraseValidIteratorOnSharedHash()
|
|||||||
QCOMPARE(itemsWith10, 3);
|
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)
|
QTEST_APPLESS_MAIN(tst_QHash)
|
||||||
#include "tst_qhash.moc"
|
#include "tst_qhash.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user