diff options
-rw-r--r-- | src/corelib/tools/qhash.cpp | 66 | ||||
-rw-r--r-- | src/corelib/tools/qhash.h | 9 | ||||
-rw-r--r-- | src/corelib/tools/qiterator.h | 151 | ||||
-rw-r--r-- | src/corelib/tools/qmap.cpp | 67 | ||||
-rw-r--r-- | src/corelib/tools/qmap.h | 8 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qhash/tst_qhash.cpp | 55 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qmap/tst_qmap.cpp | 54 |
7 files changed, 410 insertions, 0 deletions
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 09f3fd8e83..353dc834aa 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -1722,6 +1722,60 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW \sa keyBegin() */ +/*! \fn QHash::key_value_iterator QHash::keyValueBegin() + \since 5.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the hash. + + \sa keyValueEnd() +*/ + +/*! \fn QHash::key_value_iterator QHash::keyValueEnd() + \since 5.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the hash. + + \sa keyValueBegin() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::keyValueBegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the hash. + + \sa keyValueEnd() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::constKeyValueBegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the hash. + + \sa keyValueBegin() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::keyValueEnd() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the hash. + + \sa keyValueBegin() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::constKeyValueEnd() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the hash. + + \sa constKeyValueBegin() +*/ + /*! \fn QHash::iterator QHash::erase(const_iterator pos) \since 5.7 @@ -2457,6 +2511,18 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW Returns the underlying const_iterator this key_iterator is based on. */ +/*! \typedef QHash::key_value_iterator + \inmodule QtCore + \since 5.10 + \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QHash and QMultiHash. + + QHash::key_value_iterator is essentially the same as QHash::iterator + with the difference that operator*() returns a key/value pair instead of a + value. + + \sa QKeyValueIterator +*/ + /*! \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 c59f789cb2..bcaaec0ec6 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -447,6 +447,9 @@ public: const_iterator base() const { return i; } }; + typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator; + typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator; + // STL style inline iterator begin() { detach(); return iterator(d->firstNode()); } inline const_iterator begin() const { return const_iterator(d->firstNode()); } @@ -458,6 +461,12 @@ public: 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()); } + inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); } + inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); } + inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); } + inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); } + inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); } + inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); } QPair<iterator, iterator> equal_range(const Key &key); QPair<const_iterator, const_iterator> equal_range(const Key &key) const Q_DECL_NOTHROW; diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h index 3953005242..9550c302bb 100644 --- a/src/corelib/tools/qiterator.h +++ b/src/corelib/tools/qiterator.h @@ -179,6 +179,157 @@ public: \ n = c->end(); return false; } \ }; +template<typename Key, typename T, class Iterator> +class QKeyValueIterator +{ +public: + typedef typename Iterator::iterator_category iterator_category; + typedef typename Iterator::difference_type difference_type; + typedef std::pair<Key, T> value_type; + typedef const value_type *pointer; + typedef const value_type &reference; + + QKeyValueIterator() = default; + Q_DECL_CONSTEXPR explicit QKeyValueIterator(Iterator o) Q_DECL_NOEXCEPT_EXPR(std::is_nothrow_move_constructible<Iterator>::value) + : i(std::move(o)) {} + + std::pair<Key, T> operator*() const { + return std::pair<Key, T>(i.key(), i.value()); + } + + friend Q_DECL_CONSTEXPR bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) Q_DECL_NOEXCEPT { return lhs.i == rhs.i; } + friend Q_DECL_CONSTEXPR bool operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) Q_DECL_NOEXCEPT { return lhs.i != rhs.i; } + + inline QKeyValueIterator &operator++() { ++i; return *this; } + inline QKeyValueIterator operator++(int) { return QKeyValueIterator(i++);} + inline QKeyValueIterator &operator--() { --i; return *this; } + inline QKeyValueIterator operator--(int) { return QKeyValueIterator(i--); } + Iterator base() const { return i; } + +private: + Iterator i; +}; + +/*! \class QKeyValueIterator + \inmodule QtCore + \since 5.10 + + \brief Iterator over the key/value pairs of an associative container. + + The QKeyValueIterator class provides an STL-style iterator for returning + key/value pairs from associative containers like QHash and QMap. It + supports the same API as the STL associative containers, i.e. getting a + key/value pair when iterating through the container. + + This will allow for better interoperability between QMap, QHash and friends + and STL-style algorithms. + + \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}. +*/ + +/*! \typedef QKeyValueIterator::iterator_category + \internal +*/ + +/*! \typedef QKeyValueIterator::difference_type + \internal +*/ + +/*! \typedef QKeyValueIterator::value_type + \internal +*/ + +/*! \typedef QKeyValueIterator::pointer + \internal +*/ + +/*! \typedef QKeyValueIterator::reference + \internal +*/ + +/*! \fn QKeyValueIterator() + + Constructs a default QKeyValueIterator. +*/ + +/*! \fn QKeyValueIterator(Iterator o) + + Constructs a QKeyValueIterator on top of \a o. +*/ + +/*! \fn const T &QKeyValueIterator::operator*() const + + Returns the current entry as a pair. +*/ + +/*! \fn bool QKeyValueIterator::operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) + + Returns \c true if \a rhs points to the same item as \a lhs otherwise returns + \c false. + + \sa operator!=() +*/ + +/*! \fn bool QKeyValueIterator::operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) const + + Returns \c true if \a rhs points to a different item than \a lhs otherwise + returns \c false. + + \sa operator==() +*/ + +/*! + \fn QKeyValueIterator &QKeyValueIterator::operator++() + + The prefix ++ operator (\c{++i}) advances the iterator to the + next item in the container and returns the iterator. + + \note Advancing the iterator past its container's end() constitutes + undefined behavior. + + \sa operator--() +*/ + +/*! \fn QKeyValueIterator QKeyValueIterator::operator++(int) + + \overload + + The postfix ++ operator (\c{i++}) advances the iterator to the + next item in the container and returns the iterator's prior value. + + \note Advancing the iterator past its container's end() constitutes + undefined behavior. +*/ + +/*! \fn QKeyValueIterator &QKeyValueIterator::operator--() + + The prefix -- operator (\c{--i}) backs the iterator up to the previous item + in the container and returns the iterator. + + \note Backing up an iterator to before its container's begin() constitutes + undefined behavior. + + \sa operator++() +*/ + +/*! \fn QKeyValueIterator QKeyValueIterator::operator--(int) + + \overload + + The postfix -- operator (\c{i--}) backs the iterator up to the previous item + in the container and returns the iterator's prior value. + + \note Backing up an iterator to before its container's begin() constitutes + undefined behavior. +*/ + +/*! \fn Iterator QKeyValueIterator::base() const + Returns the underlying iterator this QKeyValueIterator is based on. +*/ + QT_END_NAMESPACE #endif // QITERATOR_H diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 94ed47f898..9738e2ed18 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -908,6 +908,61 @@ void QMapDataBase::freeData(QMapDataBase *d) \sa keyBegin(), lastKey() */ + +/*! \fn QMap::key_value_iterator QMap::keyValueBegin() + \since 5.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the map. + + \sa keyValueEnd() +*/ + +/*! \fn QMap::key_value_iterator QMap::keyValueEnd() + \since 5.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the map. + + \sa keyValueBegin() +*/ + +/*! \fn QMap::const_key_value_iterator QMap::keyValueBegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the map. + + \sa keyValueEnd() +*/ + +/*! \fn QMap::const_key_value_iterator QMap::constKeyValueBegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the map. + + \sa keyValueBegin() +*/ + +/*! \fn QMap::const_key_value_iterator QMap::keyValueEnd() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the map. + + \sa keyValueBegin() +*/ + +/*! \fn QMap::const_key_value_iterator QMap::constKeyValueEnd() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the map. + + \sa constKeyValueBegin() +*/ + /*! \fn const Key &QMap::firstKey() const \since 5.2 @@ -1782,6 +1837,18 @@ void QMapDataBase::freeData(QMapDataBase *d) Returns the underlying const_iterator this key_iterator is based on. */ +/*! \typedef QMap::key_value_iterator + \inmodule QtCore + \since 5.10 + \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QMap and QMultiMap. + + QMap::key_value_iterator is essentially the same as QMap::iterator + with the difference that operator*() returns a key/value pair instead of a + value. + + \sa QKeyValueIterator +*/ + /*! \fn QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map) \relates QMap diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index a3b11eddcf..2c19ae969f 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -548,6 +548,8 @@ public: const_iterator base() const { return i; } }; + typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator; + typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator; // STL style inline iterator begin() { detach(); return iterator(d->begin()); } @@ -560,6 +562,12 @@ public: inline const_iterator cend() const { return const_iterator(d->end()); } inline key_iterator keyBegin() const { return key_iterator(begin()); } inline key_iterator keyEnd() const { return key_iterator(end()); } + inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); } + inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); } + inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); } + inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); } + inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); } + inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_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 0c5f1a7afb..c34bee64b1 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -60,6 +60,7 @@ private slots: void compare2(); void iterators(); // sligthly modified from tst_QMap void keyIterator(); + void keyValueIterator(); void keys_values_uniqueKeys(); // slightly modified from tst_QMap void noNeedlessRehashes(); @@ -1059,6 +1060,60 @@ void tst_QHash::keyIterator() Q_STATIC_ASSERT(std::is_default_constructible<keyIterator>::value); } +void tst_QHash::keyValueIterator() +{ + QHash<int, int> hash; + typedef QHash<int, int>::const_key_value_iterator::value_type entry_type; + + for (int i = 0; i < 100; ++i) + hash.insert(i, i * 100); + + auto key_value_it = hash.constKeyValueBegin(); + auto it = hash.cbegin(); + + + for (int i = 0; i < hash.size(); ++i) { + QVERIFY(key_value_it != hash.constKeyValueEnd()); + QVERIFY(it != hash.cend()); + + entry_type pair(it.key(), it.value()); + QCOMPARE(*key_value_it, pair); + ++key_value_it; + ++it; + } + + QVERIFY(key_value_it == hash.constKeyValueEnd()); + QVERIFY(it == hash.cend()); + + int key = 50; + int value = 50 * 100; + entry_type pair(key, value); + key_value_it = std::find(hash.constKeyValueBegin(), hash.constKeyValueEnd(), pair); + it = std::find(hash.cbegin(), hash.cend(), value); + + QVERIFY(key_value_it != hash.constKeyValueEnd()); + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + key = 99; + value = 99 * 100; + QCOMPARE(std::count(hash.constKeyValueBegin(), hash.constKeyValueEnd(), entry_type(key, value)), 1); +} + void tst_QHash::rehash_isnt_quadratic() { // this test should be incredibly slow if rehash() is quadratic diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index f42ffc0471..b39444e76f 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -61,6 +61,7 @@ private slots: void iterators(); void keyIterator(); + void keyValueIterator(); void keys_values_uniqueKeys(); void qmultimap_specific(); @@ -863,6 +864,59 @@ void tst_QMap::keyIterator() Q_STATIC_ASSERT(std::is_default_constructible<keyIterator>::value); } +void tst_QMap::keyValueIterator() +{ + QMap<int, int> map; + typedef QMap<int, int>::const_key_value_iterator::value_type entry_type; + + for (int i = 0; i < 100; ++i) + map.insert(i, i * 100); + + auto key_value_it = map.constKeyValueBegin(); + auto it = map.cbegin(); + + for (int i = 0; i < map.size(); ++i) { + QVERIFY(key_value_it != map.constKeyValueEnd()); + QVERIFY(it != map.cend()); + + entry_type pair(it.key(), it.value()); + QCOMPARE(*key_value_it, pair); + ++key_value_it; + ++it; + } + + QVERIFY(key_value_it == map.constKeyValueEnd()); + QVERIFY(it == map.cend()); + + int key = 50; + int value = 50 * 100; + entry_type pair(key, value); + key_value_it = std::find(map.constKeyValueBegin(), map.constKeyValueEnd(), pair); + it = std::find(map.cbegin(), map.cend(), value); + + QVERIFY(key_value_it != map.constKeyValueEnd()); + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + key = 99; + value = 99 * 100; + QCOMPARE(std::count(map.constKeyValueBegin(), map.constKeyValueEnd(), entry_type(key, value)), 1); +} + void tst_QMap::keys_values_uniqueKeys() { QMap<QString, int> map; |