summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp19
-rw-r--r--src/corelib/tools/qhash.cpp148
-rw-r--r--src/corelib/tools/qhash.h28
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp29
4 files changed, 223 insertions, 1 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
index 43d64fc08e..0ac7cb5769 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
@@ -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)
{
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index a8a461e868..87a59c67c8 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -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
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 94cd4c0205..e367cc0068 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -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
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index 6ea33fb37f..6a5c6b5670 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -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