Add first/last accessors to QMap

QMap explicitly sorts its entries by key value. For an ordered container
it's (often?) useful to access the first or last entry, for instance to
quickly compute the next key of the mapping. The first entry is easily
accessible by the STL begin() method, but for accessing the last entry
pretty ugly iterator arithmetics must be applied: *(end() - 1). With
their first() and last() accessors the container classes QList and
QVector provide a much nicer method of accessing extrema, so for
consistency this syntactical sugar also should be applied to QMap.

Change-Id: Ibd544acbad8c3ac16f12a1e74362207ea1694375
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
bb10
Mathias Hasselmann 2013-07-04 13:27:15 +02:00 committed by The Qt Project
parent 69e21f1a86
commit 50e2db6a75
3 changed files with 106 additions and 27 deletions

View File

@ -879,6 +879,48 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa constBegin(), end()
*/
/*! \fn const Key &QMap::firstKey() const
Returns a reference to the smallest key in the map.
This function assumes that the map is not empty.
\sa lastKey(), first(), isEmpty()
*/
/*! \fn const Key &QMap::lastKey() const
Returns a reference to the largest key in the map.
This function assumes that the map is not empty.
\sa firstKey(), last(), isEmpty()
*/
/*! \fn T &QMap::first()
Returns a reference to the first value in the map, that is the value mapped
to the smallest key. This function assumes that the map is not empty.
\sa last(), firstKey(), isEmpty()
*/
/*! \fn const T &QMap::first() const
\overload
*/
/*! \fn T &QMap::last()
Returns a reference to the last value in the map, that is the value mapped
to the largest key. This function assumes that the map is not empty.
\sa first(), lastKey(), isEmpty()
*/
/*! \fn const T &QMap::last() const
\overload
*/
/*! \fn QMap::iterator QMap::erase(iterator pos)
Removes the (key, value) pair pointed to by the iterator \a pos

View File

@ -140,32 +140,32 @@ template <class Key, class T>
inline QMapNode<Key, T> *QMapNode<Key, T>::lowerBound(const Key &akey)
{
QMapNode<Key, T> *n = this;
QMapNode<Key, T> *last = 0;
QMapNode<Key, T> *lastNode = 0;
while (n) {
if (!qMapLessThanKey(n->key, akey)) {
last = n;
lastNode = n;
n = n->leftNode();
} else {
n = n->rightNode();
}
}
return last;
return lastNode;
}
template <class Key, class T>
inline QMapNode<Key, T> *QMapNode<Key, T>::upperBound(const Key &akey)
{
QMapNode<Key, T> *n = this;
QMapNode<Key, T> *last = 0;
QMapNode<Key, T> *lastNode = 0;
while (n) {
if (qMapLessThanKey(akey, n->key)) {
last = n;
lastNode = n;
n = n->leftNode();
} else {
n = n->rightNode();
}
}
return last;
return lastNode;
}
@ -206,7 +206,7 @@ struct QMapData : public QMapDataBase
void deleteNode(Node *z);
Node *findNode(const Key &akey) const;
void nodeRange(const Key &akey, Node **first, Node **last);
void nodeRange(const Key &akey, Node **firstNode, Node **lastNode);
Node *createNode(const Key &k, const T &v, Node *parent = 0, bool left = false)
{
@ -296,7 +296,7 @@ QMapNode<Key, T> *QMapData<Key, T>::findNode(const Key &akey) const
template <class Key, class T>
void QMapData<Key, T>::nodeRange(const Key &akey, QMapNode<Key, T> **first, QMapNode<Key, T> **last)
void QMapData<Key, T>::nodeRange(const Key &akey, QMapNode<Key, T> **firstNode, QMapNode<Key, T> **lastNode)
{
Node *n = root();
Node *l = end();
@ -307,16 +307,16 @@ void QMapData<Key, T>::nodeRange(const Key &akey, QMapNode<Key, T> **first, QMap
} else if (qMapLessThanKey(n->key, akey)) {
n = n->rightNode();
} else {
*first = n->leftNode()->lowerBound(akey);
if (!*first)
*first = n;
*last = n->rightNode()->upperBound(akey);
if (!*last)
*last = l;
*firstNode = n->leftNode()->lowerBound(akey);
if (!*firstNode)
*firstNode = n;
*lastNode = n->rightNode()->upperBound(akey);
if (!*lastNode)
*lastNode = l;
return;
}
}
*first = *last = l;
*firstNode = *lastNode = l;
}
@ -395,6 +395,14 @@ public:
QList<T> values(const Key &key) const;
int count(const Key &key) const;
inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return (constEnd() - 1).key(); }
inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
inline T &last() { Q_ASSERT(!isEmpty()); return *(end() - 1); }
inline const T &last() const { Q_ASSERT(!isEmpty()); return *(constEnd() - 1); }
class const_iterator;
class iterator
@ -633,12 +641,12 @@ Q_INLINE_TEMPLATE int QMap<Key, T>::count(const Key &akey) const
Node *lastNode;
d->nodeRange(akey, &firstNode, &lastNode);
const_iterator first(firstNode);
const const_iterator last(lastNode);
const_iterator ci_first(firstNode);
const const_iterator ci_last(lastNode);
int cnt = 0;
while (first != last) {
while (ci_first != ci_last) {
++cnt;
++first;
++ci_first;
}
return cnt;
}
@ -655,12 +663,12 @@ Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insert(const Key
detach();
Node *n = d->root();
Node *y = d->end();
Node *last = 0;
Node *lastNode = 0;
bool left = true;
while (n) {
y = n;
if (!qMapLessThanKey(n->key, akey)) {
last = n;
lastNode = n;
left = true;
n = n->leftNode();
} else {
@ -668,9 +676,9 @@ Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insert(const Key
n = n->rightNode();
}
}
if (last && !qMapLessThanKey(akey, last->key)) {
last->value = avalue;
return iterator(last);
if (lastNode && !qMapLessThanKey(akey, lastNode->key)) {
lastNode->value = avalue;
return iterator(lastNode);
}
Node *z = d->createNode(akey, avalue, y, left);
return iterator(z);
@ -852,9 +860,9 @@ template <class Key, class T>
QPair<typename QMap<Key, T>::iterator, typename QMap<Key, T>::iterator> QMap<Key, T>::equal_range(const Key &akey)
{
detach();
Node *first, *last;
d->nodeRange(akey, &first, &last);
return QPair<iterator, iterator>(iterator(first), iterator(last));
Node *firstNode, *lastNode;
d->nodeRange(akey, &firstNode, &lastNode);
return QPair<iterator, iterator>(iterator(firstNode), iterator(lastNode));
}
#ifdef Q_MAP_DEBUG

View File

@ -59,6 +59,7 @@ private slots:
void count();
void clear();
void beginEnd();
void firstLast();
void key();
void swap();
@ -377,6 +378,34 @@ void tst_QMap::beginEnd()
QVERIFY( map.constBegin() != map2.constBegin() );
}
void tst_QMap::firstLast()
{
// sample string->string map
StringMap map;
map.insert("0", "a");
map.insert("1", "b");
map.insert("5", "e");
QCOMPARE(map.firstKey(), QStringLiteral("0"));
QCOMPARE(map.lastKey(), QStringLiteral("5"));
QCOMPARE(map.first(), QStringLiteral("a"));
QCOMPARE(map.last(), QStringLiteral("e"));
// const map
const StringMap const_map = map;
QCOMPARE(map.firstKey(), const_map.firstKey());
QCOMPARE(map.lastKey(), const_map.lastKey());
QCOMPARE(map.first(), const_map.first());
QCOMPARE(map.last(), const_map.last());
map.take(map.firstKey());
QCOMPARE(map.firstKey(), QStringLiteral("1"));
QCOMPARE(map.lastKey(), QStringLiteral("5"));
map.take(map.lastKey());
QCOMPARE(map.lastKey(), map.lastKey());
}
void tst_QMap::key()
{
{