summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp26
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp13
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp13
-rw-r--r--src/corelib/tools/qhash.cpp37
-rw-r--r--src/corelib/tools/qhash.h8
-rw-r--r--src/corelib/tools/qiterator.h41
-rw-r--r--src/corelib/tools/qmap.h8
-rw-r--r--src/corelib/tools/qmap.qdoc19
-rw-r--r--src/corelib/tools/qmultimap.qdoc19
-rw-r--r--tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp131
10 files changed, 315 insertions, 0 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 ee9f88fc65..844c5f1b7c 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
@@ -360,3 +360,29 @@ template <> struct hash<K>
};
}
//! [33]
+
+//! [34]
+QHash<QString, int> hash;
+hash.insert("January", 1);
+hash.insert("February", 2);
+// ...
+hash.insert("December", 12);
+
+for (auto [key, value] : hash.asKeyValueRange()) {
+ cout << key << ": " << value << Qt::endl;
+ --value; // convert to JS month indexing
+}
+//! [34]
+
+//! [35]
+QMultiHash<QString, int> hash;
+hash.insert("January", 1);
+hash.insert("February", 2);
+// ...
+hash.insert("December", 12);
+
+for (auto [key, value] : hash.asKeyValueRange()) {
+ cout << key << ": " << value << Qt::endl;
+ --value; // convert to JS month indexing
+}
+//! [35]
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp
index 145cd10d84..a0e280e759 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp
@@ -340,3 +340,16 @@ qDeleteAll(map2.keys());
int numPrimes = std::count_if(map.keyBegin(), map.keyEnd(), isPrimeNumber);
qDeleteAll(map2.keyBegin(), map2.keyEnd());
//! [keyiterator2]
+
+//! [28]
+QMap<QString, int> map;
+map.insert("January", 1);
+map.insert("February", 2);
+// ...
+map.insert("December", 12);
+
+for (auto [key, value] : map.asKeyValueRange()) {
+ cout << key << ": " << value << Qt::endl;
+ --value; // convert to JS month indexing
+}
+//! [28]
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp
index 9c2a01834b..bd188c3fb4 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp
@@ -322,3 +322,16 @@ qDeleteAll(multimap2.keys());
int numPrimes = std::count_if(multimap.keyBegin(), multimap.keyEnd(), isPrimeNumber);
qDeleteAll(multimap2.keyBegin(), multimap2.keyEnd());
//! [keyiterator2]
+
+//! [26]
+QMultiMap<QString, int> map;
+map.insert("January", 1);
+map.insert("February", 2);
+// ...
+map.insert("December", 12);
+
+for (auto [key, value] : map.asKeyValueRange()) {
+ cout << key << ": " << value << Qt::endl;
+ --value; // convert to JS month indexing
+}
+//! [26]
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index e3106745da..b5aaaeee5b 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -2270,6 +2270,25 @@ size_t qHash(long double key, size_t seed) noexcept
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this hash as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qhash.cpp 34
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the hash. Specifically, mutating the value
+ will modify the hash itself.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::erase(const_iterator pos)
\since 5.7
@@ -3411,6 +3430,24 @@ size_t qHash(long double key, size_t seed) noexcept
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this hash as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qhash.cpp 35
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the hash. Specifically, mutating the value
+ will modify the hash itself.
+
+ \sa QKeyValueIterator
+*/
/*! \class QMultiHash::iterator
\inmodule QtCore
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 0eb91e7604..73a0225106 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -1228,6 +1228,10 @@ public:
inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator erase(const_iterator it)
{
@@ -1843,6 +1847,10 @@ public:
inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator detach(const_iterator it)
{
diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h
index 8922f34758..559023d493 100644
--- a/src/corelib/tools/qiterator.h
+++ b/src/corelib/tools/qiterator.h
@@ -301,6 +301,47 @@ private:
Iterator i;
};
+namespace QtPrivate {
+
+template <typename Map>
+class QKeyValueRangeStorage
+{
+protected:
+ Map m_map;
+public:
+ explicit QKeyValueRangeStorage(const Map &map) : m_map(map) {}
+ explicit QKeyValueRangeStorage(Map &&map) : m_map(std::move(map)) {}
+};
+
+template <typename Map>
+class QKeyValueRangeStorage<Map &>
+{
+protected:
+ Map &m_map;
+public:
+ explicit QKeyValueRangeStorage(Map &map) : m_map(map) {}
+};
+
+template <typename Map>
+class QKeyValueRange : public QKeyValueRangeStorage<Map>
+{
+public:
+ using QKeyValueRangeStorage<Map>::QKeyValueRangeStorage;
+ auto begin() { return this->m_map.keyValueBegin(); }
+ auto begin() const { return this->m_map.keyValueBegin(); }
+ auto end() { return this->m_map.keyValueEnd(); }
+ auto end() const { return this->m_map.keyValueEnd(); }
+};
+
+template <typename Map>
+QKeyValueRange(Map &) -> QKeyValueRange<Map &>;
+
+template <typename Map, std::enable_if_t<!std::is_reference_v<Map>, bool> = false>
+QKeyValueRange(Map &&) -> QKeyValueRange<std::remove_const_t<Map>>;
+
+} // namespace QtPrivate
+
+
QT_END_NAMESPACE
#endif // QITERATOR_H
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 5daf24189b..672d01791a 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -646,6 +646,10 @@ public:
const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator erase(const_iterator it)
{
@@ -1341,6 +1345,10 @@ public:
const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator erase(const_iterator it)
{
diff --git a/src/corelib/tools/qmap.qdoc b/src/corelib/tools/qmap.qdoc
index 55c2bcb5d9..eeb6b0f939 100644
--- a/src/corelib/tools/qmap.qdoc
+++ b/src/corelib/tools/qmap.qdoc
@@ -663,6 +663,25 @@
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this map as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qmap.cpp 28
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the map. Specifically, mutating the value
+ will modify the map itself.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::erase(const_iterator pos)
Removes the (key, value) pair pointed to by the iterator \a pos
diff --git a/src/corelib/tools/qmultimap.qdoc b/src/corelib/tools/qmultimap.qdoc
index 6bfc1515e6..fb61b540bf 100644
--- a/src/corelib/tools/qmultimap.qdoc
+++ b/src/corelib/tools/qmultimap.qdoc
@@ -693,6 +693,25 @@
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this multi map as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 26
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the multi map. Specifically, mutating the value
+ will modify the map itself.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::erase(const_iterator pos)
Removes the (key, value) pair pointed to by the iterator \a pos
diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp
index 5e2d7eab04..33994dfccc 100644
--- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp
+++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp
@@ -391,6 +391,16 @@ private Q_SLOTS:
void erase_if_QMultiMap() {erase_if_associative_impl<QMultiMap<int, int>>(); }
void erase_if_QHash() { erase_if_associative_impl<QHash<int, int>>(); }
void erase_if_QMultiHash() { erase_if_associative_impl<QMultiHash<int, int>>(); }
+
+private:
+ template <typename Container>
+ void keyValueRange_impl() const;
+
+private Q_SLOTS:
+ void keyValueRange_QMap() { keyValueRange_impl<QMap<int, int>>(); }
+ void keyValueRange_QMultiMap() { keyValueRange_impl<QMultiMap<int, int>>(); }
+ void keyValueRange_QHash() { keyValueRange_impl<QHash<int, int>>(); }
+ void keyValueRange_QMultiHash() { keyValueRange_impl<QMultiHash<int, int>>(); }
};
void tst_ContainerApiSymmetry::init()
@@ -851,5 +861,126 @@ void tst_ContainerApiSymmetry::erase_if_associative_impl() const
QCOMPARE(c.size(), S(0));
}
+template <typename Container>
+void tst_ContainerApiSymmetry::keyValueRange_impl() const
+{
+ constexpr int COUNT = 20;
+
+ using K = typename Container::key_type;
+ using V = typename Container::mapped_type;
+ QVector<K> keys;
+ keys.reserve(COUNT);
+ QVector<V> values;
+ values.reserve(COUNT);
+
+ auto c = makeAssociative<Container>(COUNT);
+ auto returnC = [&](){ return c; };
+
+ const auto verify = [](QVector<K> v, int count, int offset = 0) -> bool {
+ if (v.size() != count)
+ return false;
+ std::sort(v.begin(), v.end());
+ for (int i = 0; i < count; ++i) {
+ // vector is indexed from 0, but makeAssociative starts from 1
+ if (v[i] != i + 1 + offset)
+ return false;
+ }
+ return true;
+ };
+
+ // Check that the range has the right size
+ auto range = c.asKeyValueRange();
+ QCOMPARE(std::distance(range.begin(), range.end()), COUNT);
+
+ auto constRange = std::as_const(c).asKeyValueRange();
+ QCOMPARE(std::distance(constRange.begin(), constRange.end()), COUNT);
+
+ auto rvalueRange = returnC().asKeyValueRange();
+ QCOMPARE(std::distance(rvalueRange.begin(), rvalueRange.end()), COUNT);
+
+ // auto, mutating
+ keys.clear(); values.clear();
+ for (auto [key, value] : c.asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value);
+ QCOMPARE(c.value(key), value);
+ ++value;
+ QCOMPARE(key, value - 1);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT));
+
+ // auto, non-mutating
+ keys.clear(); values.clear();
+ for (auto [key, value] : c.asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 1);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 1));
+
+ // auto &&, mutating
+ keys.clear(); values.clear();
+ for (auto &&[key, value] : c.asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 1);
+ QCOMPARE(c.value(key), value);
+ ++value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 1));
+
+ // auto, non-mutating (const map)
+ keys.clear(); values.clear();
+ for (auto [key, value] : std::as_const(c).asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+
+ // auto &&, non-mutating (const map)
+ keys.clear(); values.clear();
+ for (auto &&[key, value] : std::as_const(c).asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+
+ // auto, non-mutating (rvalue map)
+ keys.clear(); values.clear();
+ for (auto [key, value] : returnC().asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+
+ // auto &&, non-mutating (rvalue map)
+ keys.clear(); values.clear();
+ for (auto &&[key, value] : returnC().asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+}
+
QTEST_APPLESS_MAIN(tst_ContainerApiSymmetry)
#include "tst_containerapisymmetry.moc"