Introduce QMap key iterators
So we can have interoperability with algorithms. Motivated by inefficient code like qDeleteAll(map.keys()) [ChangeLog][QtCore][QMap] Added key iterators, accessible through keyBegin() and keyEnd(). Change-Id: Ieee2f9ad031e9d1e845a71447746699bbe95b96c Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
parent
75244bf985
commit
07f27fcf6d
@ -311,3 +311,22 @@ while (i != map.end() && i.key() == "plenty") {
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
//! [27]
|
//! [27]
|
||||||
|
|
||||||
|
//! [keyiterator1]
|
||||||
|
for (QMap<int, QString>::const_iterator it = map.cbegin(), end = map.cend(); it != end; ++it) {
|
||||||
|
cout << "The key: " << it.key() << endl
|
||||||
|
cout << "The value: " << it.value() << endl;
|
||||||
|
cout << "Also the value: " << (*it) << endl;
|
||||||
|
}
|
||||||
|
//! [keyiterator1]
|
||||||
|
|
||||||
|
//! [keyiterator2]
|
||||||
|
// Inefficient, keys() is expensive
|
||||||
|
QList<int> keys = map.keys();
|
||||||
|
int numPrimes = std::count_if(map.cbegin(), map.cend(), isPrimeNumber);
|
||||||
|
qDeleteAll(map2.keys());
|
||||||
|
|
||||||
|
// Efficient, no memory allocation needed
|
||||||
|
int numPrimes = std::count_if(map.keyBegin(), map.keyEnd(), isPrimeNumber);
|
||||||
|
qDeleteAll(map2.keyBegin(), map2.keyEnd());
|
||||||
|
//! [keyiterator2]
|
||||||
|
@ -858,6 +858,15 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
\sa begin(), constEnd()
|
\sa begin(), constEnd()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \fn QMap::key_iterator QMap::keyBegin() const
|
||||||
|
\since 5.6
|
||||||
|
|
||||||
|
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
|
||||||
|
in the map.
|
||||||
|
|
||||||
|
\sa keyEnd(), firstKey()
|
||||||
|
*/
|
||||||
|
|
||||||
/*! \fn QMap::iterator QMap::end()
|
/*! \fn QMap::iterator QMap::end()
|
||||||
|
|
||||||
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
|
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
|
||||||
@ -888,6 +897,15 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
\sa constBegin(), end()
|
\sa constBegin(), end()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \fn QMap::key_iterator QMap::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 map.
|
||||||
|
|
||||||
|
\sa keyBegin(), lastKey()
|
||||||
|
*/
|
||||||
|
|
||||||
/*! \fn const Key &QMap::firstKey() const
|
/*! \fn const Key &QMap::firstKey() const
|
||||||
\since 5.2
|
\since 5.2
|
||||||
|
|
||||||
@ -896,7 +914,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
|
|
||||||
This executes in \l{constant time}.
|
This executes in \l{constant time}.
|
||||||
|
|
||||||
\sa lastKey(), first(), isEmpty()
|
\sa lastKey(), first(), keyBegin(), isEmpty()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn const Key &QMap::lastKey() const
|
/*! \fn const Key &QMap::lastKey() const
|
||||||
@ -907,7 +925,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
|
|
||||||
This executes in \l{logarithmic time}.
|
This executes in \l{logarithmic time}.
|
||||||
|
|
||||||
\sa firstKey(), last(), isEmpty()
|
\sa firstKey(), last(), keyEnd(), isEmpty()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn T &QMap::first()
|
/*! \fn T &QMap::first()
|
||||||
@ -1235,7 +1253,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
while iterators are active on that container. For more information,
|
while iterators are active on that container. For more information,
|
||||||
read \l{Implicit sharing iterator problem}.
|
read \l{Implicit sharing iterator problem}.
|
||||||
|
|
||||||
\sa QMap::const_iterator, QMutableMapIterator
|
\sa QMap::const_iterator, QMap::key_iterator, QMutableMapIterator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \typedef QMap::iterator::difference_type
|
/*! \typedef QMap::iterator::difference_type
|
||||||
@ -1458,7 +1476,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
while iterators are active on that container. For more information,
|
while iterators are active on that container. For more information,
|
||||||
read \l{Implicit sharing iterator problem}.
|
read \l{Implicit sharing iterator problem}.
|
||||||
|
|
||||||
\sa QMap::iterator, QMapIterator
|
\sa QMap::iterator, QMap::key_iterator, QMapIterator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \typedef QMap::const_iterator::difference_type
|
/*! \typedef QMap::const_iterator::difference_type
|
||||||
@ -1634,6 +1652,134 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
|||||||
\sa operator+=(), operator-()
|
\sa operator+=(), operator-()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \class QMap::key_iterator
|
||||||
|
\inmodule QtCore
|
||||||
|
\since 5.6
|
||||||
|
\brief The QMap::key_iterator class provides an STL-style const iterator for QMap and QMultiMap keys.
|
||||||
|
|
||||||
|
QMap::key_iterator is essentially the same as QMap::const_iterator
|
||||||
|
with the difference that operator*() and operator->() return a key
|
||||||
|
instead of a value.
|
||||||
|
|
||||||
|
For most uses QMap::iterator and QMap::const_iterator should be used,
|
||||||
|
you can easily access the key by calling QMap::iterator::key():
|
||||||
|
|
||||||
|
\snippet code/src_corelib_tools_qmap.cpp keyiterator1
|
||||||
|
|
||||||
|
However, to have interoperability between QMap's keys and STL-style
|
||||||
|
algorithms we need an iterator that dereferences to a key instead
|
||||||
|
of a value. With QMap::key_iterator we can apply an algorithm to a
|
||||||
|
range of keys without having to call QMap::keys(), which is inefficient
|
||||||
|
as it costs one QMap iteration and memory allocation to create a temporary
|
||||||
|
QList.
|
||||||
|
|
||||||
|
\snippet code/src_corelib_tools_qmap.cpp keyiterator2
|
||||||
|
|
||||||
|
QMap::key_iterator is const, it's not possible to modify the key.
|
||||||
|
|
||||||
|
The default QMap::key_iterator constructor creates an uninitialized
|
||||||
|
iterator. You must initialize it using a QMap function like
|
||||||
|
QMap::keyBegin() or QMap::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 QMap::const_iterator, QMap::iterator
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \typedef QMap::key_iterator::difference_type
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \typedef QMap::key_iterator::iterator_category
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \typedef QMap::key_iterator::pointer
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \typedef QMap::key_iterator::reference
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \typedef QMap::key_iterator::value_type
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \fn const T &QMap::key_iterator::operator*() const
|
||||||
|
|
||||||
|
Returns the current item's key.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \fn const T *QMap::key_iterator::operator->() const
|
||||||
|
|
||||||
|
Returns a pointer to the current item's key.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \fn bool QMap::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 QMap::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 QMap::key_iterator &QMap::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 QMap::keyEnd() leads to undefined results.
|
||||||
|
|
||||||
|
\sa operator--()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \fn QMap::key_iterator QMap::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 QMap::key_iterator &QMap::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 QMap::keyBegin() leads to undefined
|
||||||
|
results.
|
||||||
|
|
||||||
|
\sa operator++()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \fn QMap::key_iterator QMap::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 QMap::key_iterator::base() const
|
||||||
|
Returns the underlying const_iterator this key_iterator is based on.
|
||||||
|
*/
|
||||||
|
|
||||||
/*! \fn QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
|
/*! \fn QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
|
||||||
\relates QMap
|
\relates QMap
|
||||||
|
|
||||||
|
@ -518,6 +518,32 @@ public:
|
|||||||
};
|
};
|
||||||
friend class const_iterator;
|
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
|
// STL style
|
||||||
inline iterator begin() { detach(); return iterator(d->begin()); }
|
inline iterator begin() { detach(); return iterator(d->begin()); }
|
||||||
inline const_iterator begin() const { return const_iterator(d->begin()); }
|
inline const_iterator begin() const { return const_iterator(d->begin()); }
|
||||||
@ -527,6 +553,8 @@ public:
|
|||||||
inline const_iterator end() const { return const_iterator(d->end()); }
|
inline const_iterator end() const { return const_iterator(d->end()); }
|
||||||
inline const_iterator constEnd() const { return const_iterator(d->end()); }
|
inline const_iterator constEnd() const { return const_iterator(d->end()); }
|
||||||
inline const_iterator cend() const { return const_iterator(d->end()); }
|
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()); }
|
||||||
iterator erase(iterator it);
|
iterator erase(iterator it);
|
||||||
|
|
||||||
// more Qt
|
// more Qt
|
||||||
|
@ -65,6 +65,7 @@ private slots:
|
|||||||
void take();
|
void take();
|
||||||
|
|
||||||
void iterators();
|
void iterators();
|
||||||
|
void keyIterator();
|
||||||
void keys_values_uniqueKeys();
|
void keys_values_uniqueKeys();
|
||||||
void qmultimap_specific();
|
void qmultimap_specific();
|
||||||
|
|
||||||
@ -835,6 +836,34 @@ void tst_QMap::iterators()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QMap::keyIterator()
|
||||||
|
{
|
||||||
|
QMap<int, int> map;
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; ++i)
|
||||||
|
map.insert(i, i*100);
|
||||||
|
|
||||||
|
QMap<int, int>::key_iterator key_it = map.keyBegin();
|
||||||
|
QMap<int, int>::const_iterator it = map.cbegin();
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
QCOMPARE(*key_it, it.key());
|
||||||
|
++key_it;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_it = std::find(map.keyBegin(), map.keyEnd(), 50);
|
||||||
|
it = std::find(map.cbegin(), map.cend(), 50 * 100);
|
||||||
|
|
||||||
|
QVERIFY(key_it != map.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(map.keyBegin(), map.keyEnd(), 99), 1);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QMap::keys_values_uniqueKeys()
|
void tst_QMap::keys_values_uniqueKeys()
|
||||||
{
|
{
|
||||||
QMap<QString, int> map;
|
QMap<QString, int> map;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user