Introduce QHash key iterators
So we can have interoperability with algorithms. Motivated by inefficient code like qDeleteAll(hash.keys()) [ChangeLog][QtCore][QHash] Added key iterators, accessible through keyBegin() and keyEnd(). Change-Id: I1f9db8a7a4294e1556cbb50b8fe5ebdcf0dc29a2 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
parent
07f27fcf6d
commit
4bced6e7a6
@ -298,6 +298,25 @@ while (i != hash.end() && i.key() == "plenty") {
|
||||
}
|
||||
//! [26]
|
||||
|
||||
//! [27]
|
||||
for (QHash<int, QString>::const_iterator it = hash.cbegin(), end = hash.cend(); it != end; ++it) {
|
||||
cout << "The key: " << it.key() << endl
|
||||
cout << "The value: " << it.value() << endl;
|
||||
cout << "Also the value: " << (*it) << endl;
|
||||
}
|
||||
//! [27]
|
||||
|
||||
//! [28]
|
||||
// Inefficient, keys() is expensive
|
||||
QList<int> keys = hash.keys();
|
||||
int numPrimes = std::count_if(keys.cbegin(), keys.cend(), isPrimeNumber);
|
||||
qDeleteAll(hash2.keys());
|
||||
|
||||
// Efficient, no memory allocation needed
|
||||
int numPrimes = std::count_if(hash.keyBegin(), hash.keyEnd(), isPrimeNumber);
|
||||
qDeleteAll(hash2.keyBegin(), hash2.keyEnd());
|
||||
//! [28]
|
||||
|
||||
//! [qhashbits]
|
||||
inline uint qHash(const std::vector<int> &key, uint seed = 0)
|
||||
{
|
||||
|
@ -1536,6 +1536,15 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
|
||||
\sa begin(), constEnd()
|
||||
*/
|
||||
|
||||
/*! \fn QHash::key_iterator QHash::keyBegin() const
|
||||
\since 5.6
|
||||
|
||||
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
|
||||
in the hash.
|
||||
|
||||
\sa keyEnd()
|
||||
*/
|
||||
|
||||
/*! \fn QHash::iterator QHash::end()
|
||||
|
||||
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
|
||||
@ -1566,6 +1575,15 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
|
||||
\sa cbegin(), end()
|
||||
*/
|
||||
|
||||
/*! \fn QHash::key_iterator QHash::keyEnd() const
|
||||
\since 5.6
|
||||
|
||||
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
|
||||
item after the last key in the hash.
|
||||
|
||||
\sa keyBegin()
|
||||
*/
|
||||
|
||||
/*! \fn QHash::iterator QHash::erase(iterator pos)
|
||||
|
||||
Removes the (key, value) pair associated with the iterator \a pos
|
||||
@ -1729,6 +1747,26 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*! \typedef QHash::key_iterator::difference_type
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*! \typedef QHash::key_iterator::iterator_category
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*! \typedef QHash::key_iterator::pointer
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*! \typedef QHash::key_iterator::reference
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*! \typedef QHash::key_iterator::value_type
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*! \class QHash::iterator
|
||||
\inmodule QtCore
|
||||
\brief The QHash::iterator class provides an STL-style non-const iterator for QHash and QMultiHash.
|
||||
@ -1802,7 +1840,7 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
|
||||
while iterators are active on that container. For more information,
|
||||
read \l{Implicit sharing iterator problem}.
|
||||
|
||||
\sa QHash::const_iterator, QMutableHashIterator
|
||||
\sa QHash::const_iterator, QHash::key_iterator, QMutableHashIterator
|
||||
*/
|
||||
|
||||
/*! \fn QHash::iterator::iterator()
|
||||
@ -2155,6 +2193,114 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
|
||||
\sa operator+=(), operator-()
|
||||
*/
|
||||
|
||||
/*! \class QHash::key_iterator
|
||||
\inmodule QtCore
|
||||
\since 5.6
|
||||
\brief The QHash::key_iterator class provides an STL-style const iterator for QHash and QMultiHash keys.
|
||||
|
||||
QHash::key_iterator is essentially the same as QHash::const_iterator
|
||||
with the difference that operator*() and operator->() return a key
|
||||
instead of a value.
|
||||
|
||||
For most uses QHash::iterator and QHash::const_iterator should be used,
|
||||
you can easily access the key by calling QHash::iterator::key():
|
||||
|
||||
\snippet code/src_corelib_tools_qhash.cpp 27
|
||||
|
||||
However, to have interoperability between QHash's keys and STL-style
|
||||
algorithms we need an iterator that dereferences to a key instead
|
||||
of a value. With QHash::key_iterator we can apply an algorithm to a
|
||||
range of keys without having to call QHash::keys(), which is inefficient
|
||||
as it costs one QHash iteration and memory allocation to create a temporary
|
||||
QList.
|
||||
|
||||
\snippet code/src_corelib_tools_qhash.cpp 28
|
||||
|
||||
QHash::key_iterator is const, it's not possible to modify the key.
|
||||
|
||||
The default QHash::key_iterator constructor creates an uninitialized
|
||||
iterator. You must initialize it using a QHash function like
|
||||
QHash::keyBegin() or QHash::keyEnd().
|
||||
|
||||
\warning Iterators on implicitly shared containers do not work
|
||||
exactly like STL-iterators. You should avoid copying a container
|
||||
while iterators are active on that container. For more information,
|
||||
read \l{Implicit sharing iterator problem}.
|
||||
|
||||
\sa QHash::const_iterator, QHash::iterator
|
||||
*/
|
||||
|
||||
/*! \fn const T &QHash::key_iterator::operator*() const
|
||||
|
||||
Returns the current item's key.
|
||||
*/
|
||||
|
||||
/*! \fn const T *QHash::key_iterator::operator->() const
|
||||
|
||||
Returns a pointer to the current item's key.
|
||||
*/
|
||||
|
||||
/*! \fn bool QHash::key_iterator::operator==(key_iterator other)
|
||||
|
||||
Returns \c true if \a other points to the same item as this
|
||||
iterator; otherwise returns \c false.
|
||||
|
||||
\sa operator!=()
|
||||
*/
|
||||
|
||||
/*! \fn bool QHash::key_iterator::operator!=(key_iterator other)
|
||||
|
||||
Returns \c true if \a other points to a different item than this
|
||||
iterator; otherwise returns \c false.
|
||||
|
||||
\sa operator==()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QHash::key_iterator &QHash::key_iterator::operator++()
|
||||
|
||||
The prefix ++ operator (\c{++i}) advances the iterator to the
|
||||
next item in the hash and returns an iterator to the new current
|
||||
item.
|
||||
|
||||
Calling this function on QHash::keyEnd() leads to undefined results.
|
||||
|
||||
\sa operator--()
|
||||
*/
|
||||
|
||||
/*! \fn QHash::key_iterator QHash::key_iterator::operator++(int)
|
||||
|
||||
\overload
|
||||
|
||||
The postfix ++ operator (\c{i++}) advances the iterator to the
|
||||
next item in the hash and returns an iterator to the previous
|
||||
item.
|
||||
*/
|
||||
|
||||
/*! \fn QHash::key_iterator &QHash::key_iterator::operator--()
|
||||
|
||||
The prefix -- operator (\c{--i}) makes the preceding item
|
||||
current and returns an iterator pointing to the new current item.
|
||||
|
||||
Calling this function on QHash::keyBegin() leads to undefined
|
||||
results.
|
||||
|
||||
\sa operator++()
|
||||
*/
|
||||
|
||||
/*! \fn QHash::key_iterator QHash::key_iterator::operator--(int)
|
||||
|
||||
\overload
|
||||
|
||||
The postfix -- operator (\c{i--}) makes the preceding item
|
||||
current and returns an iterator pointing to the previous
|
||||
item.
|
||||
*/
|
||||
|
||||
/*! \fn const_iterator QHash::key_iterator::base() const
|
||||
Returns the underlying const_iterator this key_iterator is based on.
|
||||
*/
|
||||
|
||||
/*! \fn QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
|
||||
\relates QHash
|
||||
|
||||
|
@ -413,6 +413,31 @@ public:
|
||||
};
|
||||
friend class const_iterator;
|
||||
|
||||
class key_iterator
|
||||
{
|
||||
const_iterator i;
|
||||
|
||||
public:
|
||||
typedef typename const_iterator::iterator_category iterator_category;
|
||||
typedef typename const_iterator::difference_type difference_type;
|
||||
typedef Key value_type;
|
||||
typedef const Key *pointer;
|
||||
typedef const Key &reference;
|
||||
|
||||
explicit key_iterator(const_iterator o) : i(o) { }
|
||||
|
||||
const Key &operator*() const { return i.key(); }
|
||||
const Key *operator->() const { return &i.key(); }
|
||||
bool operator==(key_iterator o) const { return i == o.i; }
|
||||
bool operator!=(key_iterator o) const { return i != o.i; }
|
||||
|
||||
inline key_iterator &operator++() { ++i; return *this; }
|
||||
inline key_iterator operator++(int) { return key_iterator(i++);}
|
||||
inline key_iterator &operator--() { --i; return *this; }
|
||||
inline key_iterator operator--(int) { return key_iterator(i--); }
|
||||
const_iterator base() const { return i; }
|
||||
};
|
||||
|
||||
// STL style
|
||||
inline iterator begin() { detach(); return iterator(d->firstNode()); }
|
||||
inline const_iterator begin() const { return const_iterator(d->firstNode()); }
|
||||
@ -422,6 +447,9 @@ public:
|
||||
inline const_iterator end() const { return const_iterator(e); }
|
||||
inline const_iterator cend() const { return const_iterator(e); }
|
||||
inline const_iterator constEnd() const { return const_iterator(e); }
|
||||
inline key_iterator keyBegin() const { return key_iterator(begin()); }
|
||||
inline key_iterator keyEnd() const { return key_iterator(end()); }
|
||||
|
||||
iterator erase(iterator it);
|
||||
|
||||
// more Qt
|
||||
|
@ -62,6 +62,7 @@ private slots:
|
||||
void compare();
|
||||
void compare2();
|
||||
void iterators(); // sligthly modified from tst_QMap
|
||||
void keyIterator();
|
||||
void keys_values_uniqueKeys(); // slightly modified from tst_QMap
|
||||
void noNeedlessRehashes();
|
||||
|
||||
@ -965,6 +966,34 @@ void tst_QHash::iterators()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QHash::keyIterator()
|
||||
{
|
||||
QHash<int, int> hash;
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
hash.insert(i, i*100);
|
||||
|
||||
QHash<int, int>::key_iterator key_it = hash.keyBegin();
|
||||
QHash<int, int>::const_iterator it = hash.cbegin();
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
QCOMPARE(*key_it, it.key());
|
||||
key_it++;
|
||||
it++;
|
||||
}
|
||||
|
||||
key_it = std::find(hash.keyBegin(), hash.keyEnd(), 50);
|
||||
it = std::find(hash.cbegin(), hash.cend(), 50 * 100);
|
||||
|
||||
QVERIFY(key_it != hash.keyEnd());
|
||||
QCOMPARE(*key_it, it.key());
|
||||
QCOMPARE(*(key_it++), (it++).key());
|
||||
QCOMPARE(*(key_it--), (it--).key());
|
||||
QCOMPARE(*(++key_it), (++it).key());
|
||||
QCOMPARE(*(--key_it), (--it).key());
|
||||
|
||||
QCOMPARE(std::count(hash.keyBegin(), hash.keyEnd(), 99), 1);
|
||||
}
|
||||
|
||||
void tst_QHash::rehash_isnt_quadratic()
|
||||
{
|
||||
// this test should be incredibly slow if rehash() is quadratic
|
||||
|
Loading…
Reference in New Issue
Block a user