diff options
-rw-r--r-- | src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp | 19 | ||||
-rw-r--r-- | src/corelib/tools/qhash.cpp | 148 | ||||
-rw-r--r-- | src/corelib/tools/qhash.h | 28 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qhash/tst_qhash.cpp | 29 |
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 |