/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMAP_H #define QMAP_H #include #include #include #ifndef QT_NO_STL #include #endif #include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Core) struct Q_CORE_EXPORT QMapData { struct Node { Node *backward; Node *forward[1]; }; enum { LastLevel = 11, Sparseness = 3 }; QMapData *backward; QMapData *forward[QMapData::LastLevel + 1]; QBasicAtomicInt ref; int topLevel; int size; uint randomBits; uint insertInOrder : 1; uint sharable : 1; uint strictAlignment : 1; uint reserved : 29; static QMapData *createData(); // ### Qt5 remove me static QMapData *createData(int alignment); void continueFreeData(int offset); Node *node_create(Node *update[], int offset); // ### Qt5 remove me Node *node_create(Node *update[], int offset, int alignment); void node_delete(Node *update[], int offset, Node *node); #ifdef QT_QMAP_DEBUG uint adjust_ptr(Node *node); void dump(); #endif static QMapData shared_null; }; /* QMap uses qMapLessThanKey() to compare keys. The default implementation uses operator<(). For pointer types, qMapLessThanKey() casts the pointers to integers before it compares them, because operator<() is undefined on pointers that come from different memory blocks. (In practice, this is only a problem when running a program such as BoundsChecker.) */ template inline bool qMapLessThanKey(const Key &key1, const Key &key2) { return key1 < key2; } template inline bool qMapLessThanKey(Ptr *key1, Ptr *key2) { Q_ASSERT(sizeof(quintptr) == sizeof(Ptr *)); return quintptr(key1) < quintptr(key2); } template inline bool qMapLessThanKey(const Ptr *key1, const Ptr *key2) { Q_ASSERT(sizeof(quintptr) == sizeof(const Ptr *)); return quintptr(key1) < quintptr(key2); } template struct QMapNode { Key key; T value; private: // never access these members through this structure. // see below QMapData::Node *backward; QMapData::Node *forward[1]; }; template struct QMapPayloadNode { Key key; T value; private: // QMap::e is a pointer to QMapData::Node, which matches the member // below. However, the memory allocation node in QMapData::node_create // allocates sizeof(QMapPayloNode) and incorrectly calculates the offset // of 'backward' below. If the alignment of QMapPayloadNode is larger // than the alignment of a pointer, the 'backward' member is aligned to // the end of this structure, not to 'value' above, and will occupy the // tail-padding area. // // e.g., on a 32-bit archictecture with Key = int and // sizeof(T) = alignof(T) = 8 // 0 4 8 12 16 20 24 byte // | key | PAD | value |backward| PAD | correct layout // | key | PAD | value | |backward| how it's actually used // |<----- value of QMap::payload() = 20 ----->| QMapData::Node *backward; }; template class QMap { typedef QMapNode Node; typedef QMapPayloadNode PayloadNode; union { QMapData *d; QMapData::Node *e; }; static inline int payload() { return sizeof(PayloadNode) - sizeof(QMapData::Node *); } static inline int alignment() { #ifdef Q_ALIGNOF return int(qMax(sizeof(void*), Q_ALIGNOF(Node))); #else return 0; #endif } static inline Node *concrete(QMapData::Node *node) { return reinterpret_cast(reinterpret_cast(node) - payload()); } public: inline QMap() : d(&QMapData::shared_null) { d->ref.ref(); } inline QMap(const QMap &other) : d(other.d) { d->ref.ref(); if (!d->sharable) detach(); } inline ~QMap() { if (!d) return; if (!d->ref.deref()) freeData(d); } QMap &operator=(const QMap &other); #ifdef Q_COMPILER_RVALUE_REFS inline QMap &operator=(QMap &&other) { qSwap(d, other.d); return *this; } #endif inline void swap(QMap &other) { qSwap(d, other.d); } #ifndef QT_NO_STL explicit QMap(const typename std::map &other); std::map toStdMap() const; #endif bool operator==(const QMap &other) const; inline bool operator!=(const QMap &other) const { return !(*this == other); } inline int size() const { return d->size; } inline bool isEmpty() const { return d->size == 0; } inline void detach() { if (d->ref != 1) detach_helper(); } inline bool isDetached() const { return d->ref == 1; } inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } inline bool isSharedWith(const QMap &other) const { return d == other.d; } inline void setInsertInOrder(bool ordered) { d->insertInOrder = ordered; } void clear(); int remove(const Key &key); T take(const Key &key); bool contains(const Key &key) const; const Key key(const T &value) const; const Key key(const T &value, const Key &defaultKey) const; const T value(const Key &key) const; const T value(const Key &key, const T &defaultValue) const; T &operator[](const Key &key); const T operator[](const Key &key) const; QList uniqueKeys() const; QList keys() const; QList keys(const T &value) const; QList values() const; QList values(const Key &key) const; int count(const Key &key) const; class const_iterator; class iterator { friend class const_iterator; QMapData::Node *i; public: typedef std::bidirectional_iterator_tag iterator_category; typedef qptrdiff difference_type; typedef T value_type; typedef T *pointer; typedef T &reference; // ### Qt 5: get rid of 'operator Node *' inline operator QMapData::Node *() const { return i; } inline iterator() : i(0) { } inline iterator(QMapData::Node *node) : i(node) { } inline const Key &key() const { return concrete(i)->key; } inline T &value() const { return concrete(i)->value; } #ifdef QT3_SUPPORT inline QT3_SUPPORT T &data() const { return concrete(i)->value; } #endif inline T &operator*() const { return concrete(i)->value; } inline T *operator->() const { return &concrete(i)->value; } inline bool operator==(const iterator &o) const { return i == o.i; } inline bool operator!=(const iterator &o) const { return i != o.i; } inline iterator &operator++() { i = i->forward[0]; return *this; } inline iterator operator++(int) { iterator r = *this; i = i->forward[0]; return r; } inline iterator &operator--() { i = i->backward; return *this; } inline iterator operator--(int) { iterator r = *this; i = i->backward; return r; } inline iterator operator+(int j) const { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; } inline iterator operator-(int j) const { return operator+(-j); } inline iterator &operator+=(int j) { return *this = *this + j; } inline iterator &operator-=(int j) { return *this = *this - j; } // ### Qt 5: not sure this is necessary anymore #ifdef QT_STRICT_ITERATORS private: #else public: #endif inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } private: // ### Qt 5: remove inline operator bool() const { return false; } }; friend class iterator; class const_iterator { friend class iterator; QMapData::Node *i; public: typedef std::bidirectional_iterator_tag iterator_category; typedef qptrdiff difference_type; typedef T value_type; typedef const T *pointer; typedef const T &reference; // ### Qt 5: get rid of 'operator Node *' inline operator QMapData::Node *() const { return i; } inline const_iterator() : i(0) { } inline const_iterator(QMapData::Node *node) : i(node) { } #ifdef QT_STRICT_ITERATORS explicit inline const_iterator(const iterator &o) #else inline const_iterator(const iterator &o) #endif { i = o.i; } inline const Key &key() const { return concrete(i)->key; } inline const T &value() const { return concrete(i)->value; } #ifdef QT3_SUPPORT inline QT3_SUPPORT const T &data() const { return concrete(i)->value; } #endif inline const T &operator*() const { return concrete(i)->value; } inline const T *operator->() const { return &concrete(i)->value; } inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline const_iterator &operator++() { i = i->forward[0]; return *this; } inline const_iterator operator++(int) { const_iterator r = *this; i = i->forward[0]; return r; } inline const_iterator &operator--() { i = i->backward; return *this; } inline const_iterator operator--(int) { const_iterator r = *this; i = i->backward; return r; } inline const_iterator operator+(int j) const { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; } inline const_iterator operator-(int j) const { return operator+(-j); } inline const_iterator &operator+=(int j) { return *this = *this + j; } inline const_iterator &operator-=(int j) { return *this = *this - j; } // ### Qt 5: not sure this is necessary anymore #ifdef QT_STRICT_ITERATORS private: inline bool operator==(const iterator &o) { return operator==(const_iterator(o)); } inline bool operator!=(const iterator &o) { return operator!=(const_iterator(o)); } #endif private: // ### Qt 5: remove inline operator bool() const { return false; } }; friend class const_iterator; // STL style inline iterator begin() { detach(); return iterator(e->forward[0]); } inline const_iterator begin() const { return const_iterator(e->forward[0]); } inline const_iterator constBegin() const { return const_iterator(e->forward[0]); } inline iterator end() { detach(); return iterator(e); } inline const_iterator end() const { return const_iterator(e); } inline const_iterator constEnd() const { return const_iterator(e); } iterator erase(iterator it); #ifdef QT3_SUPPORT inline QT3_SUPPORT iterator remove(iterator it) { return erase(it); } inline QT3_SUPPORT void erase(const Key &aKey) { remove(aKey); } #endif // more Qt typedef iterator Iterator; typedef const_iterator ConstIterator; inline int count() const { return d->size; } iterator find(const Key &key); const_iterator find(const Key &key) const; const_iterator constFind(const Key &key) const; iterator lowerBound(const Key &key); const_iterator lowerBound(const Key &key) const; iterator upperBound(const Key &key); const_iterator upperBound(const Key &key) const; iterator insert(const Key &key, const T &value); #ifdef QT3_SUPPORT QT3_SUPPORT iterator insert(const Key &key, const T &value, bool overwrite); #endif iterator insertMulti(const Key &key, const T &value); #ifdef QT3_SUPPORT inline QT3_SUPPORT iterator replace(const Key &aKey, const T &aValue) { return insert(aKey, aValue); } #endif QMap &unite(const QMap &other); // STL compatibility typedef Key key_type; typedef T mapped_type; typedef qptrdiff difference_type; typedef int size_type; inline bool empty() const { return isEmpty(); } #ifdef QT_QMAP_DEBUG inline void dump() const { d->dump(); } #endif private: void detach_helper(); void freeData(QMapData *d); QMapData::Node *findNode(const Key &key) const; QMapData::Node *mutableFindNode(QMapData::Node *update[], const Key &key) const; QMapData::Node *node_create(QMapData *d, QMapData::Node *update[], const Key &key, const T &value); }; template Q_INLINE_TEMPLATE QMap &QMap::operator=(const QMap &other) { if (d != other.d) { QMapData* o = other.d; o->ref.ref(); if (!d->ref.deref()) freeData(d); d = o; if (!d->sharable) detach_helper(); } return *this; } template Q_INLINE_TEMPLATE void QMap::clear() { *this = QMap(); } template Q_INLINE_TEMPLATE typename QMapData::Node * QMap::node_create(QMapData *adt, QMapData::Node *aupdate[], const Key &akey, const T &avalue) { QMapData::Node *abstractNode = adt->node_create(aupdate, payload(), alignment()); QT_TRY { Node *concreteNode = concrete(abstractNode); new (&concreteNode->key) Key(akey); QT_TRY { new (&concreteNode->value) T(avalue); } QT_CATCH(...) { concreteNode->key.~Key(); QT_RETHROW; } } QT_CATCH(...) { adt->node_delete(aupdate, payload(), abstractNode); QT_RETHROW; } // clean up the update array for further insertions /* for (int i = 0; i <= d->topLevel; ++i) { if ( aupdate[i]==reinterpret_cast(adt) || aupdate[i]->forward[i] != abstractNode) break; aupdate[i] = abstractNode; } */ return abstractNode; } template Q_INLINE_TEMPLATE QMapData::Node *QMap::findNode(const Key &akey) const { QMapData::Node *cur = e; QMapData::Node *next = e; for (int i = d->topLevel; i >= 0; i--) { while ((next = cur->forward[i]) != e && qMapLessThanKey(concrete(next)->key, akey)) cur = next; } if (next != e && !qMapLessThanKey(akey, concrete(next)->key)) { return next; } else { return e; } } template Q_INLINE_TEMPLATE const T QMap::value(const Key &akey) const { QMapData::Node *node; if (d->size == 0 || (node = findNode(akey)) == e) { return T(); } else { return concrete(node)->value; } } template Q_INLINE_TEMPLATE const T QMap::value(const Key &akey, const T &adefaultValue) const { QMapData::Node *node; if (d->size == 0 || (node = findNode(akey)) == e) { return adefaultValue; } else { return concrete(node)->value; } } template Q_INLINE_TEMPLATE const T QMap::operator[](const Key &akey) const { return value(akey); } template Q_INLINE_TEMPLATE T &QMap::operator[](const Key &akey) { detach(); QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *node = mutableFindNode(update, akey); if (node == e) node = node_create(d, update, akey, T()); return concrete(node)->value; } template Q_INLINE_TEMPLATE int QMap::count(const Key &akey) const { int cnt = 0; QMapData::Node *node = findNode(akey); if (node != e) { do { ++cnt; node = node->forward[0]; } while (node != e && !qMapLessThanKey(akey, concrete(node)->key)); } return cnt; } template Q_INLINE_TEMPLATE bool QMap::contains(const Key &akey) const { return findNode(akey) != e; } template Q_INLINE_TEMPLATE typename QMap::iterator QMap::insert(const Key &akey, const T &avalue) { detach(); QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *node = mutableFindNode(update, akey); if (node == e) { node = node_create(d, update, akey, avalue); } else { concrete(node)->value = avalue; } return iterator(node); } #ifdef QT3_SUPPORT template Q_INLINE_TEMPLATE typename QMap::iterator QMap::insert(const Key &akey, const T &avalue, bool aoverwrite) { detach(); QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *node = mutableFindNode(update, akey); if (node == e) { node = node_create(d, update, akey, avalue); } else { if (aoverwrite) concrete(node)->value = avalue; } return iterator(node); } #endif template Q_INLINE_TEMPLATE typename QMap::iterator QMap::insertMulti(const Key &akey, const T &avalue) { detach(); QMapData::Node *update[QMapData::LastLevel + 1]; mutableFindNode(update, akey); return iterator(node_create(d, update, akey, avalue)); } template Q_INLINE_TEMPLATE typename QMap::const_iterator QMap::find(const Key &akey) const { return const_iterator(findNode(akey)); } template Q_INLINE_TEMPLATE typename QMap::const_iterator QMap::constFind(const Key &akey) const { return const_iterator(findNode(akey)); } template Q_INLINE_TEMPLATE typename QMap::iterator QMap::find(const Key &akey) { detach(); return iterator(findNode(akey)); } template Q_INLINE_TEMPLATE QMap &QMap::unite(const QMap &other) { QMap copy(other); const_iterator it = copy.constEnd(); const const_iterator b = copy.constBegin(); while (it != b) { --it; insertMulti(it.key(), it.value()); } return *this; } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4189) #endif template Q_OUTOFLINE_TEMPLATE void QMap::freeData(QMapData *x) { if (QTypeInfo::isComplex || QTypeInfo::isComplex) { QMapData *cur = x; QMapData *next = cur->forward[0]; while (next != x) { cur = next; next = cur->forward[0]; Node *concreteNode = concrete(reinterpret_cast(cur)); concreteNode->key.~Key(); concreteNode->value.~T(); } } x->continueFreeData(payload()); } #if defined(_MSC_VER) #pragma warning(pop) #endif template Q_OUTOFLINE_TEMPLATE int QMap::remove(const Key &akey) { detach(); QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *cur = e; QMapData::Node *next = e; int oldSize = d->size; for (int i = d->topLevel; i >= 0; i--) { while ((next = cur->forward[i]) != e && qMapLessThanKey(concrete(next)->key, akey)) cur = next; update[i] = cur; } if (next != e && !qMapLessThanKey(akey, concrete(next)->key)) { bool deleteNext = true; do { cur = next; next = cur->forward[0]; deleteNext = (next != e && !qMapLessThanKey(concrete(cur)->key, concrete(next)->key)); concrete(cur)->key.~Key(); concrete(cur)->value.~T(); d->node_delete(update, payload(), cur); } while (deleteNext); } return oldSize - d->size; } template Q_OUTOFLINE_TEMPLATE T QMap::take(const Key &akey) { detach(); QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *cur = e; QMapData::Node *next = e; for (int i = d->topLevel; i >= 0; i--) { while ((next = cur->forward[i]) != e && qMapLessThanKey(concrete(next)->key, akey)) cur = next; update[i] = cur; } if (next != e && !qMapLessThanKey(akey, concrete(next)->key)) { T t = concrete(next)->value; concrete(next)->key.~Key(); concrete(next)->value.~T(); d->node_delete(update, payload(), next); return t; } return T(); } template Q_OUTOFLINE_TEMPLATE typename QMap::iterator QMap::erase(iterator it) { QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *cur = e; QMapData::Node *next = e; if (it == iterator(e)) return it; for (int i = d->topLevel; i >= 0; i--) { while ((next = cur->forward[i]) != e && qMapLessThanKey(concrete(next)->key, it.key())) cur = next; update[i] = cur; } while (next != e) { cur = next; next = cur->forward[0]; if (cur == it) { concrete(cur)->key.~Key(); concrete(cur)->value.~T(); d->node_delete(update, payload(), cur); return iterator(next); } for (int i = 0; i <= d->topLevel; ++i) { if (update[i]->forward[i] != cur) break; update[i] = cur; } } return end(); } template Q_OUTOFLINE_TEMPLATE void QMap::detach_helper() { union { QMapData *d; QMapData::Node *e; } x; x.d = QMapData::createData(alignment()); if (d->size) { x.d->insertInOrder = true; QMapData::Node *update[QMapData::LastLevel + 1]; QMapData::Node *cur = e->forward[0]; update[0] = x.e; while (cur != e) { QT_TRY { Node *concreteNode = concrete(cur); node_create(x.d, update, concreteNode->key, concreteNode->value); } QT_CATCH(...) { freeData(x.d); QT_RETHROW; } cur = cur->forward[0]; } x.d->insertInOrder = false; } if (!d->ref.deref()) freeData(d); d = x.d; } template Q_OUTOFLINE_TEMPLATE QMapData::Node *QMap::mutableFindNode(QMapData::Node *aupdate[], const Key &akey) const { QMapData::Node *cur = e; QMapData::Node *next = e; for (int i = d->topLevel; i >= 0; i--) { while ((next = cur->forward[i]) != e && qMapLessThanKey(concrete(next)->key, akey)) cur = next; aupdate[i] = cur; } if (next != e && !qMapLessThanKey(akey, concrete(next)->key)) { return next; } else { return e; } } template Q_OUTOFLINE_TEMPLATE QList QMap::uniqueKeys() const { QList res; res.reserve(size()); // May be too much, but assume short lifetime const_iterator i = begin(); if (i != end()) { for (;;) { const Key &aKey = i.key(); res.append(aKey); do { if (++i == end()) goto break_out_of_outer_loop; } while (!(aKey < i.key())); // loop while (key == i.key()) } } break_out_of_outer_loop: return res; } template Q_OUTOFLINE_TEMPLATE QList QMap::keys() const { QList res; res.reserve(size()); const_iterator i = begin(); while (i != end()) { res.append(i.key()); ++i; } return res; } template Q_OUTOFLINE_TEMPLATE QList QMap::keys(const T &avalue) const { QList res; const_iterator i = begin(); while (i != end()) { if (i.value() == avalue) res.append(i.key()); ++i; } return res; } template Q_OUTOFLINE_TEMPLATE const Key QMap::key(const T &avalue) const { return key(avalue, Key()); } template Q_OUTOFLINE_TEMPLATE const Key QMap::key(const T &avalue, const Key &defaultKey) const { const_iterator i = begin(); while (i != end()) { if (i.value() == avalue) return i.key(); ++i; } return defaultKey; } template Q_OUTOFLINE_TEMPLATE QList QMap::values() const { QList res; res.reserve(size()); const_iterator i = begin(); while (i != end()) { res.append(i.value()); ++i; } return res; } template Q_OUTOFLINE_TEMPLATE QList QMap::values(const Key &akey) const { QList res; QMapData::Node *node = findNode(akey); if (node != e) { do { res.append(concrete(node)->value); node = node->forward[0]; } while (node != e && !qMapLessThanKey(akey, concrete(node)->key)); } return res; } template Q_INLINE_TEMPLATE typename QMap::const_iterator QMap::lowerBound(const Key &akey) const { QMapData::Node *update[QMapData::LastLevel + 1]; mutableFindNode(update, akey); return const_iterator(update[0]->forward[0]); } template Q_INLINE_TEMPLATE typename QMap::iterator QMap::lowerBound(const Key &akey) { detach(); return static_cast(const_cast(this)->lowerBound(akey)); } template Q_INLINE_TEMPLATE typename QMap::const_iterator QMap::upperBound(const Key &akey) const { QMapData::Node *update[QMapData::LastLevel + 1]; mutableFindNode(update, akey); QMapData::Node *node = update[0]->forward[0]; while (node != e && !qMapLessThanKey(akey, concrete(node)->key)) node = node->forward[0]; return const_iterator(node); } template Q_INLINE_TEMPLATE typename QMap::iterator QMap::upperBound(const Key &akey) { detach(); return static_cast(const_cast(this)->upperBound(akey)); } template Q_OUTOFLINE_TEMPLATE bool QMap::operator==(const QMap &other) const { if (size() != other.size()) return false; if (d == other.d) return true; const_iterator it1 = begin(); const_iterator it2 = other.begin(); while (it1 != end()) { if (!(it1.value() == it2.value()) || qMapLessThanKey(it1.key(), it2.key()) || qMapLessThanKey(it2.key(), it1.key())) return false; ++it2; ++it1; } return true; } #ifndef QT_NO_STL template Q_OUTOFLINE_TEMPLATE QMap::QMap(const std::map &other) { d = QMapData::createData(alignment()); d->insertInOrder = true; typename std::map::const_iterator it = other.end(); while (it != other.begin()) { --it; insert((*it).first, (*it).second); } d->insertInOrder = false; } template Q_OUTOFLINE_TEMPLATE std::map QMap::toStdMap() const { std::map map; const_iterator it = end(); while (it != begin()) { --it; map.insert(std::pair(it.key(), it.value())); } return map; } #endif // QT_NO_STL template class QMultiMap : public QMap { public: QMultiMap() {} QMultiMap(const QMap &other) : QMap(other) {} inline void swap(QMultiMap &other) { QMap::swap(other); } inline typename QMap::iterator replace(const Key &key, const T &value) { return QMap::insert(key, value); } inline typename QMap::iterator insert(const Key &key, const T &value) { return QMap::insertMulti(key, value); } inline QMultiMap &operator+=(const QMultiMap &other) { this->unite(other); return *this; } inline QMultiMap operator+(const QMultiMap &other) const { QMultiMap result = *this; result += other; return result; } #if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT) // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class using QMap::contains; using QMap::remove; using QMap::count; using QMap::find; using QMap::constFind; #else inline bool contains(const Key &key) const { return QMap::contains(key); } inline int remove(const Key &key) { return QMap::remove(key); } inline int count(const Key &key) const { return QMap::count(key); } inline int count() const { return QMap::count(); } inline typename QMap::iterator find(const Key &key) { return QMap::find(key); } inline typename QMap::const_iterator find(const Key &key) const { return QMap::find(key); } inline typename QMap::const_iterator constFind(const Key &key) const { return QMap::constFind(key); } #endif bool contains(const Key &key, const T &value) const; int remove(const Key &key, const T &value); int count(const Key &key, const T &value) const; typename QMap::iterator find(const Key &key, const T &value) { typename QMap::iterator i(find(key)); typename QMap::iterator end(this->end()); while (i != end && !qMapLessThanKey(key, i.key())) { if (i.value() == value) return i; ++i; } return end; } typename QMap::const_iterator find(const Key &key, const T &value) const { typename QMap::const_iterator i(constFind(key)); typename QMap::const_iterator end(QMap::constEnd()); while (i != end && !qMapLessThanKey(key, i.key())) { if (i.value() == value) return i; ++i; } return end; } typename QMap::const_iterator constFind(const Key &key, const T &value) const { return find(key, value); } private: T &operator[](const Key &key); const T operator[](const Key &key) const; }; template Q_INLINE_TEMPLATE bool QMultiMap::contains(const Key &key, const T &value) const { return constFind(key, value) != QMap::constEnd(); } template Q_INLINE_TEMPLATE int QMultiMap::remove(const Key &key, const T &value) { int n = 0; typename QMap::iterator i(find(key)); typename QMap::iterator end(QMap::end()); while (i != end && !qMapLessThanKey(key, i.key())) { if (i.value() == value) { i = this->erase(i); ++n; } else { ++i; } } return n; } template Q_INLINE_TEMPLATE int QMultiMap::count(const Key &key, const T &value) const { int n = 0; typename QMap::const_iterator i(constFind(key)); typename QMap::const_iterator end(QMap::constEnd()); while (i != end && !qMapLessThanKey(key, i.key())) { if (i.value() == value) ++n; ++i; } return n; } Q_DECLARE_ASSOCIATIVE_ITERATOR(Map) Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map) QT_END_NAMESPACE QT_END_HEADER #endif // QMAP_H