Associative containers: add a way to obtain a key/value range
Our associative containers' iterator's value_type isn't a destructurable type (yielding key/value). This means that something like for (auto [k, v] : map) doesn't even compile -- one can only "directly" iterate on the values. For quite some time we've had QKeyValueIterator to allow key/value iteration, but then one had to resort to a "traditional" for loop: for (auto i = map.keyValueBegin(), e = keyValueEnd(); i!=e; ++i) This can be easily packaged in an adaptor class, which is what this commmit does, thereby offering a C++17-compatible way to obtain key/value iteration over associative containers. Something possibly peculiar is the fact that the range so obtained is a range of pairs of references -- not a range of references to pairs. But that's easily explained by the fact that we have no pairs to build references to; hence, for (auto &[k, v] : map.asKeyValueRange()) doesn't compile (lvalue reference doesn't bind to prvalue pair). Instead, both of these compile: for (auto [k, v] : map.asKeyValueRange()) for (auto &&[k, v] : map.asKeyValueRange()) and in *both* cases one gets references to the keys/values in the map. If the map is non-const, the reference to the value is mutable. Last but not least, implement pinning for rvalue containers. [ChangeLog][QtCore][QMap] Added asKeyValueRange(). [ChangeLog][QtCore][QMultiMap] Added asKeyValueRange(). [ChangeLog][QtCore][QHash] Added asKeyValueRange(). [ChangeLog][QtCore][QMultiHash] Added asKeyValueRange(). Task-number: QTBUG-4615 Change-Id: Ic8506bff38b2f753494b21ab76f52e05c06ffc8b Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
dd5fc20e90
commit
0deff80eab
@ -360,3 +360,29 @@ template <> struct hash<K>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
//! [33]
|
//! [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]
|
||||||
|
@ -340,3 +340,16 @@ qDeleteAll(map2.keys());
|
|||||||
int numPrimes = std::count_if(map.keyBegin(), map.keyEnd(), isPrimeNumber);
|
int numPrimes = std::count_if(map.keyBegin(), map.keyEnd(), isPrimeNumber);
|
||||||
qDeleteAll(map2.keyBegin(), map2.keyEnd());
|
qDeleteAll(map2.keyBegin(), map2.keyEnd());
|
||||||
//! [keyiterator2]
|
//! [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]
|
||||||
|
@ -322,3 +322,16 @@ qDeleteAll(multimap2.keys());
|
|||||||
int numPrimes = std::count_if(multimap.keyBegin(), multimap.keyEnd(), isPrimeNumber);
|
int numPrimes = std::count_if(multimap.keyBegin(), multimap.keyEnd(), isPrimeNumber);
|
||||||
qDeleteAll(multimap2.keyBegin(), multimap2.keyEnd());
|
qDeleteAll(multimap2.keyBegin(), multimap2.keyEnd());
|
||||||
//! [keyiterator2]
|
//! [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]
|
||||||
|
@ -2270,6 +2270,25 @@ size_t qHash(long double key, size_t seed) noexcept
|
|||||||
\sa constKeyValueBegin()
|
\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)
|
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::erase(const_iterator pos)
|
||||||
\since 5.7
|
\since 5.7
|
||||||
|
|
||||||
@ -3411,6 +3430,24 @@ size_t qHash(long double key, size_t seed) noexcept
|
|||||||
\sa constKeyValueBegin()
|
\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
|
/*! \class QMultiHash::iterator
|
||||||
\inmodule QtCore
|
\inmodule QtCore
|
||||||
|
@ -1228,6 +1228,10 @@ public:
|
|||||||
inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
|
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 keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
|
||||||
inline const_key_value_iterator constKeyValueEnd() 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)
|
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 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 keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
|
||||||
inline const_key_value_iterator constKeyValueEnd() 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)
|
iterator detach(const_iterator it)
|
||||||
{
|
{
|
||||||
|
@ -301,6 +301,47 @@ private:
|
|||||||
Iterator i;
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QITERATOR_H
|
#endif // QITERATOR_H
|
||||||
|
@ -646,6 +646,10 @@ public:
|
|||||||
const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
|
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 keyValueEnd() const { return const_key_value_iterator(end()); }
|
||||||
const_key_value_iterator constKeyValueEnd() 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)
|
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 constKeyValueBegin() const { return const_key_value_iterator(begin()); }
|
||||||
const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
|
const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
|
||||||
const_key_value_iterator constKeyValueEnd() 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)
|
iterator erase(const_iterator it)
|
||||||
{
|
{
|
||||||
|
@ -663,6 +663,25 @@
|
|||||||
\sa constKeyValueBegin()
|
\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)
|
/*! \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
|
Removes the (key, value) pair pointed to by the iterator \a pos
|
||||||
|
@ -693,6 +693,25 @@
|
|||||||
\sa constKeyValueBegin()
|
\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)
|
/*! \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
|
Removes the (key, value) pair pointed to by the iterator \a pos
|
||||||
|
@ -391,6 +391,16 @@ private Q_SLOTS:
|
|||||||
void erase_if_QMultiMap() {erase_if_associative_impl<QMultiMap<int, int>>(); }
|
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_QHash() { erase_if_associative_impl<QHash<int, int>>(); }
|
||||||
void erase_if_QMultiHash() { erase_if_associative_impl<QMultiHash<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()
|
void tst_ContainerApiSymmetry::init()
|
||||||
@ -851,5 +861,126 @@ void tst_ContainerApiSymmetry::erase_if_associative_impl() const
|
|||||||
QCOMPARE(c.size(), S(0));
|
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)
|
QTEST_APPLESS_MAIN(tst_ContainerApiSymmetry)
|
||||||
#include "tst_containerapisymmetry.moc"
|
#include "tst_containerapisymmetry.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user