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;
|
||||
}
|
||||
//! [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()
|
||||
*/
|
||||
|
||||
/*! \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()
|
||||
|
||||
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()
|
||||
*/
|
||||
|
||||
/*! \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
|
||||
\since 5.2
|
||||
|
||||
@ -896,7 +914,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
||||
|
||||
This executes in \l{constant time}.
|
||||
|
||||
\sa lastKey(), first(), isEmpty()
|
||||
\sa lastKey(), first(), keyBegin(), isEmpty()
|
||||
*/
|
||||
|
||||
/*! \fn const Key &QMap::lastKey() const
|
||||
@ -907,7 +925,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
||||
|
||||
This executes in \l{logarithmic time}.
|
||||
|
||||
\sa firstKey(), last(), isEmpty()
|
||||
\sa firstKey(), last(), keyEnd(), isEmpty()
|
||||
*/
|
||||
|
||||
/*! \fn T &QMap::first()
|
||||
@ -1235,7 +1253,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
||||
while iterators are active on that container. For more information,
|
||||
read \l{Implicit sharing iterator problem}.
|
||||
|
||||
\sa QMap::const_iterator, QMutableMapIterator
|
||||
\sa QMap::const_iterator, QMap::key_iterator, QMutableMapIterator
|
||||
*/
|
||||
|
||||
/*! \typedef QMap::iterator::difference_type
|
||||
@ -1458,7 +1476,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
||||
while iterators are active on that container. For more information,
|
||||
read \l{Implicit sharing iterator problem}.
|
||||
|
||||
\sa QMap::iterator, QMapIterator
|
||||
\sa QMap::iterator, QMap::key_iterator, QMapIterator
|
||||
*/
|
||||
|
||||
/*! \typedef QMap::const_iterator::difference_type
|
||||
@ -1634,6 +1652,134 @@ void QMapDataBase::freeData(QMapDataBase *d)
|
||||
\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)
|
||||
\relates QMap
|
||||
|
||||
|
@ -518,6 +518,32 @@ 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->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 constEnd() 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);
|
||||
|
||||
// more Qt
|
||||
|
@ -65,6 +65,7 @@ private slots:
|
||||
void take();
|
||||
|
||||
void iterators();
|
||||
void keyIterator();
|
||||
void keys_values_uniqueKeys();
|
||||
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()
|
||||
{
|
||||
QMap<QString, int> map;
|
||||
|
Loading…
x
Reference in New Issue
Block a user