1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtCore module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
45 #include <QtCore/qchar.h>
46 #include <QtCore/qiterator.h>
47 #include <QtCore/qlist.h>
48 #include <QtCore/qpair.h>
49 #include <QtCore/qrefcount.h>
61 inline uint qHash(char key) { return uint(key); }
62 inline uint qHash(uchar key) { return uint(key); }
63 inline uint qHash(signed char key) { return uint(key); }
64 inline uint qHash(ushort key) { return uint(key); }
65 inline uint qHash(short key) { return uint(key); }
66 inline uint qHash(uint key) { return key; }
67 inline uint qHash(int key) { return uint(key); }
68 inline uint qHash(ulong key)
70 if (sizeof(ulong) > sizeof(uint)) {
71 return uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U));
73 return uint(key & (~0U));
76 inline uint qHash(long key) { return qHash(ulong(key)); }
77 inline uint qHash(quint64 key)
79 if (sizeof(quint64) > sizeof(uint)) {
80 return uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U));
82 return uint(key & (~0U));
85 inline uint qHash(qint64 key) { return qHash(quint64(key)); }
86 inline uint qHash(QChar key) { return qHash(key.unicode()); }
87 Q_CORE_EXPORT uint qHash(const QByteArray &key, uint seed = 0);
88 Q_CORE_EXPORT uint qHash(const QString &key, uint seed = 0);
89 Q_CORE_EXPORT uint qHash(const QStringRef &key, uint seed = 0);
90 Q_CORE_EXPORT uint qHash(const QBitArray &key, uint seed = 0);
91 Q_CORE_EXPORT uint qHash(const QLatin1String &key, uint seed = 0);
92 Q_CORE_EXPORT uint qt_hash(const QString &key);
94 #if defined(Q_CC_MSVC)
95 #pragma warning( push )
96 #pragma warning( disable : 4311 ) // disable pointer truncation warning
98 template <class T> inline uint qHash(const T *key)
100 return qHash(reinterpret_cast<quintptr>(key));
102 #if defined(Q_CC_MSVC)
103 #pragma warning( pop )
106 template <typename T1, typename T2> inline uint qHash(const QPair<T1, T2> &key)
108 uint h1 = qHash(key.first);
109 uint h2 = qHash(key.second);
110 return ((h1 << 16) | (h1 >> 16)) ^ h2;
113 template<typename T> inline uint qHash(const T &t, uint seed) { return (qHash(t) ^ seed); }
115 struct Q_CORE_EXPORT QHashData
124 QtPrivate::RefCount ref;
132 uint strictAlignment : 1;
135 void *allocateNode(int nodeAlign);
136 void freeNode(void *node);
137 QHashData *detach_helper(void (*node_duplicate)(Node *, void *), void (*node_delete)(Node *),
138 int nodeSize, int nodeAlign);
141 void rehash(int hint);
142 void free_helper(void (*node_delete)(Node *));
144 #ifdef QT_QHASH_DEBUG
148 static Node *nextNode(Node *node);
149 static Node *previousNode(Node *node);
151 static const QHashData shared_null;
154 inline bool QHashData::willGrow()
156 if (size >= numBuckets) {
164 inline void QHashData::hasShrunk()
166 if (size <= (numBuckets >> 3) && numBits > userNumBits) {
168 rehash(qMax(int(numBits) - 2, int(userNumBits)));
169 } QT_CATCH(const std::bad_alloc &) {
170 // ignore bad allocs - shrinking shouldn't throw. rehash is exception safe.
175 inline QHashData::Node *QHashData::firstNode()
177 Node *e = reinterpret_cast<Node *>(this);
178 Node **bucket = buckets;
188 struct QHashDummyValue
192 inline bool operator==(const QHashDummyValue & /* v1 */, const QHashDummyValue & /* v2 */)
197 Q_DECLARE_TYPEINFO(QHashDummyValue, Q_MOVABLE_TYPE | Q_DUMMY_TYPE);
199 template <class Key, class T>
200 struct QHashDummyNode
202 QHashDummyNode *next;
206 inline QHashDummyNode(const Key &key0) : key(key0) {}
209 template <class Key, class T>
217 inline QHashNode(const Key &key0, const T &value0) : key(key0), value(value0) {}
218 inline bool same_key(uint h0, const Key &key0) { return h0 == h && key0 == key; }
222 #define Q_HASH_DECLARE_INT_NODES(key_type) \
224 struct QHashDummyNode<key_type, T> { \
225 QHashDummyNode *next; \
226 union { uint h; key_type key; }; \
228 inline QHashDummyNode(key_type /* key0 */) {} \
232 struct QHashNode<key_type, T> { \
234 union { uint h; key_type key; }; \
237 inline QHashNode(key_type /* key0 */) {} \
238 inline QHashNode(key_type /* key0 */, const T &value0) : value(value0) {} \
239 inline bool same_key(uint h0, key_type) { return h0 == h; } \
242 #if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
243 Q_HASH_DECLARE_INT_NODES(short);
244 Q_HASH_DECLARE_INT_NODES(ushort);
246 Q_HASH_DECLARE_INT_NODES(int);
247 Q_HASH_DECLARE_INT_NODES(uint);
248 #undef Q_HASH_DECLARE_INT_NODES
250 template <class Key, class T>
253 typedef QHashDummyNode<Key, T> DummyNode;
254 typedef QHashNode<Key, T> Node;
258 QHashNode<Key, T> *e;
261 static inline Node *concrete(QHashData::Node *node) {
262 return reinterpret_cast<Node *>(node);
265 static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); }
266 static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); }
269 inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
270 inline QHash(const QHash<Key, T> &other) : d(other.d) { d->ref.ref(); if (!d->sharable) detach(); }
271 inline ~QHash() { if (!d->ref.deref()) freeData(d); }
273 QHash<Key, T> &operator=(const QHash<Key, T> &other);
274 #ifdef Q_COMPILER_RVALUE_REFS
275 inline QHash<Key, T> &operator=(QHash<Key, T> &&other)
276 { qSwap(d, other.d); return *this; }
278 inline void swap(QHash<Key, T> &other) { qSwap(d, other.d); }
280 bool operator==(const QHash<Key, T> &other) const;
281 inline bool operator!=(const QHash<Key, T> &other) const { return !(*this == other); }
283 inline int size() const { return d->size; }
285 inline bool isEmpty() const { return d->size == 0; }
287 inline int capacity() const { return d->numBuckets; }
288 void reserve(int size);
289 inline void squeeze() { reserve(1); }
291 inline void detach() { if (d->ref.isShared()) detach_helper(); }
292 inline bool isDetached() const { return !d->ref.isShared(); }
293 inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QHashData::shared_null) d->sharable = sharable; }
294 inline bool isSharedWith(const QHash<Key, T> &other) const { return d == other.d; }
298 int remove(const Key &key);
299 T take(const Key &key);
301 bool contains(const Key &key) const;
302 const Key key(const T &value) const;
303 const Key key(const T &value, const Key &defaultKey) const;
304 const T value(const Key &key) const;
305 const T value(const Key &key, const T &defaultValue) const;
306 T &operator[](const Key &key);
307 const T operator[](const Key &key) const;
309 QList<Key> uniqueKeys() const;
310 QList<Key> keys() const;
311 QList<Key> keys(const T &value) const;
312 QList<T> values() const;
313 QList<T> values(const Key &key) const;
314 int count(const Key &key) const;
316 class const_iterator;
320 friend class const_iterator;
321 friend class QHash<Key, T>;
325 typedef std::bidirectional_iterator_tag iterator_category;
326 typedef qptrdiff difference_type;
327 typedef T value_type;
329 typedef T &reference;
331 inline iterator() : i(0) { }
332 explicit inline iterator(void *node) : i(reinterpret_cast<QHashData::Node *>(node)) { }
334 inline const Key &key() const { return concrete(i)->key; }
335 inline T &value() const { return concrete(i)->value; }
336 inline T &operator*() const { return concrete(i)->value; }
337 inline T *operator->() const { return &concrete(i)->value; }
338 inline bool operator==(const iterator &o) const { return i == o.i; }
339 inline bool operator!=(const iterator &o) const { return i != o.i; }
341 inline iterator &operator++() {
342 i = QHashData::nextNode(i);
345 inline iterator operator++(int) {
347 i = QHashData::nextNode(i);
350 inline iterator &operator--() {
351 i = QHashData::previousNode(i);
354 inline iterator operator--(int) {
356 i = QHashData::previousNode(i);
359 inline iterator operator+(int j) const
360 { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
361 inline iterator operator-(int j) const { return operator+(-j); }
362 inline iterator &operator+=(int j) { return *this = *this + j; }
363 inline iterator &operator-=(int j) { return *this = *this - j; }
365 // ### Qt 5: not sure this is necessary anymore
366 #ifdef QT_STRICT_ITERATORS
371 inline bool operator==(const const_iterator &o) const
373 inline bool operator!=(const const_iterator &o) const
376 friend class iterator;
380 friend class iterator;
384 typedef std::bidirectional_iterator_tag iterator_category;
385 typedef qptrdiff difference_type;
386 typedef T value_type;
387 typedef const T *pointer;
388 typedef const T &reference;
390 inline const_iterator() : i(0) { }
391 explicit inline const_iterator(void *node)
392 : i(reinterpret_cast<QHashData::Node *>(node)) { }
393 #ifdef QT_STRICT_ITERATORS
394 explicit inline const_iterator(const iterator &o)
396 inline const_iterator(const iterator &o)
400 inline const Key &key() const { return concrete(i)->key; }
401 inline const T &value() const { return concrete(i)->value; }
402 inline const T &operator*() const { return concrete(i)->value; }
403 inline const T *operator->() const { return &concrete(i)->value; }
404 inline bool operator==(const const_iterator &o) const { return i == o.i; }
405 inline bool operator!=(const const_iterator &o) const { return i != o.i; }
407 inline const_iterator &operator++() {
408 i = QHashData::nextNode(i);
411 inline const_iterator operator++(int) {
412 const_iterator r = *this;
413 i = QHashData::nextNode(i);
416 inline const_iterator &operator--() {
417 i = QHashData::previousNode(i);
420 inline const_iterator operator--(int) {
421 const_iterator r = *this;
422 i = QHashData::previousNode(i);
425 inline const_iterator operator+(int j) const
426 { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
427 inline const_iterator operator-(int j) const { return operator+(-j); }
428 inline const_iterator &operator+=(int j) { return *this = *this + j; }
429 inline const_iterator &operator-=(int j) { return *this = *this - j; }
431 // ### Qt 5: not sure this is necessary anymore
432 #ifdef QT_STRICT_ITERATORS
434 inline bool operator==(const iterator &o) const { return operator==(const_iterator(o)); }
435 inline bool operator!=(const iterator &o) const { return operator!=(const_iterator(o)); }
438 friend class const_iterator;
441 inline iterator begin() { detach(); return iterator(d->firstNode()); }
442 inline const_iterator begin() const { return const_iterator(d->firstNode()); }
443 inline const_iterator cbegin() const { return const_iterator(d->firstNode()); }
444 inline const_iterator constBegin() const { return const_iterator(d->firstNode()); }
445 inline iterator end() { detach(); return iterator(e); }
446 inline const_iterator end() const { return const_iterator(e); }
447 inline const_iterator cend() const { return const_iterator(e); }
448 inline const_iterator constEnd() const { return const_iterator(e); }
449 iterator erase(iterator it);
452 typedef iterator Iterator;
453 typedef const_iterator ConstIterator;
454 inline int count() const { return d->size; }
455 iterator find(const Key &key);
456 const_iterator find(const Key &key) const;
457 const_iterator constFind(const Key &key) const;
458 iterator insert(const Key &key, const T &value);
459 iterator insertMulti(const Key &key, const T &value);
460 QHash<Key, T> &unite(const QHash<Key, T> &other);
463 typedef T mapped_type;
464 typedef Key key_type;
465 typedef qptrdiff difference_type;
466 typedef int size_type;
468 inline bool empty() const { return isEmpty(); }
470 #ifdef QT_QHASH_DEBUG
471 inline void dump() const { d->dump(); }
472 inline void checkSanity() const { d->checkSanity(); }
476 void detach_helper();
477 void freeData(QHashData *d);
478 Node **findNode(const Key &key, uint *hp = 0) const;
479 Node *createNode(uint h, const Key &key, const T &value, Node **nextNode);
480 void deleteNode(Node *node);
481 static void deleteNode2(QHashData::Node *node);
483 static void duplicateNode(QHashData::Node *originalNode, void *newNode);
487 template <class Key, class T>
488 Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(Node *node)
490 deleteNode2(reinterpret_cast<QHashData::Node*>(node));
494 template <class Key, class T>
495 Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode2(QHashData::Node *node)
498 concrete(node)->~QHashNode<Key, T>();
500 concrete(node)->~Node();
504 template <class Key, class T>
505 Q_INLINE_TEMPLATE void QHash<Key, T>::duplicateNode(QHashData::Node *node, void *newNode)
507 Node *concreteNode = concrete(node);
508 if (QTypeInfo<T>::isDummy) {
509 (void) new (newNode) DummyNode(concreteNode->key);
511 (void) new (newNode) Node(concreteNode->key, concreteNode->value);
515 template <class Key, class T>
516 Q_INLINE_TEMPLATE typename QHash<Key, T>::Node *
517 QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode)
521 if (QTypeInfo<T>::isDummy) {
522 node = reinterpret_cast<Node *>(new (d->allocateNode(alignOfDummyNode())) DummyNode(akey));
524 node = new (d->allocateNode(alignOfNode())) Node(akey, avalue);
528 node->next = *anextNode;
534 template <class Key, class T>
535 Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash<Key, T> &other)
537 QHash<Key, T> copy(other);
538 const_iterator it = copy.constEnd();
539 while (it != copy.constBegin()) {
541 insertMulti(it.key(), it.value());
546 template <class Key, class T>
547 Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x)
549 x->free_helper(deleteNode2);
552 template <class Key, class T>
553 Q_INLINE_TEMPLATE void QHash<Key, T>::clear()
555 *this = QHash<Key,T>();
558 template <class Key, class T>
559 Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
561 QHashData *x = d->detach_helper(duplicateNode, deleteNode2,
562 QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node),
563 QTypeInfo<T>::isDummy ? alignOfDummyNode() : alignOfNode());
569 template <class Key, class T>
570 Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::operator=(const QHash<Key, T> &other)
573 QHashData *o = other.d;
584 template <class Key, class T>
585 Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey) const
588 if (d->size == 0 || (node = *findNode(akey)) == e) {
595 template <class Key, class T>
596 Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey, const T &adefaultValue) const
599 if (d->size == 0 || (node = *findNode(akey)) == e) {
600 return adefaultValue;
606 template <class Key, class T>
607 Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::uniqueKeys() const
610 res.reserve(size()); // May be too much, but assume short lifetime
611 const_iterator i = begin();
614 const Key &aKey = i.key();
618 goto break_out_of_outer_loop;
619 } while (aKey == i.key());
622 break_out_of_outer_loop:
626 template <class Key, class T>
627 Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys() const
631 const_iterator i = begin();
639 template <class Key, class T>
640 Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys(const T &avalue) const
643 const_iterator i = begin();
645 if (i.value() == avalue)
652 template <class Key, class T>
653 Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue) const
655 return key(avalue, Key());
658 template <class Key, class T>
659 Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue, const Key &defaultValue) const
661 const_iterator i = begin();
663 if (i.value() == avalue)
671 template <class Key, class T>
672 Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values() const
676 const_iterator i = begin();
678 res.append(i.value());
684 template <class Key, class T>
685 Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values(const Key &akey) const
688 Node *node = *findNode(akey);
691 res.append(node->value);
692 } while ((node = node->next) != e && node->key == akey);
697 template <class Key, class T>
698 Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::count(const Key &akey) const
701 Node *node = *findNode(akey);
705 } while ((node = node->next) != e && node->key == akey);
710 template <class Key, class T>
711 Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const
716 template <class Key, class T>
717 Q_INLINE_TEMPLATE T &QHash<Key, T>::operator[](const Key &akey)
722 Node **node = findNode(akey, &h);
725 node = findNode(akey, &h);
726 return createNode(h, akey, T(), node)->value;
728 return (*node)->value;
731 template <class Key, class T>
732 Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insert(const Key &akey,
738 Node **node = findNode(akey, &h);
741 node = findNode(akey, &h);
742 return iterator(createNode(h, akey, avalue, node));
745 if (!QTypeInfo<T>::isDummy)
746 (*node)->value = avalue;
747 return iterator(*node);
750 template <class Key, class T>
751 Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &akey,
758 Node **nextNode = findNode(akey, &h);
759 return iterator(createNode(h, akey, avalue, nextNode));
762 template <class Key, class T>
763 Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::remove(const Key &akey)
765 if (isEmpty()) // prevents detaching shared null
769 int oldSize = d->size;
770 Node **node = findNode(akey);
772 bool deleteNext = true;
774 Node *next = (*node)->next;
775 deleteNext = (next != e && next->key == (*node)->key);
779 } while (deleteNext);
782 return oldSize - d->size;
785 template <class Key, class T>
786 Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey)
788 if (isEmpty()) // prevents detaching shared null
792 Node **node = findNode(akey);
794 T t = (*node)->value;
795 Node *next = (*node)->next;
805 template <class Key, class T>
806 Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::erase(iterator it)
808 if (it == iterator(e))
814 Node *node = concrete(it.i);
815 Node **node_ptr = reinterpret_cast<Node **>(&d->buckets[node->h % d->numBuckets]);
816 while (*node_ptr != node)
817 node_ptr = &(*node_ptr)->next;
818 *node_ptr = node->next;
824 template <class Key, class T>
825 Q_INLINE_TEMPLATE void QHash<Key, T>::reserve(int asize)
828 d->rehash(-qMax(asize, 1));
831 template <class Key, class T>
832 Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &akey) const
834 return const_iterator(*findNode(akey));
837 template <class Key, class T>
838 Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::constFind(const Key &akey) const
840 return const_iterator(*findNode(akey));
843 template <class Key, class T>
844 Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::find(const Key &akey)
847 return iterator(*findNode(akey));
850 template <class Key, class T>
851 Q_INLINE_TEMPLATE bool QHash<Key, T>::contains(const Key &akey) const
853 return *findNode(akey) != e;
856 template <class Key, class T>
857 Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(const Key &akey,
863 if (d->numBuckets || ahp) {
869 node = reinterpret_cast<Node **>(&d->buckets[h % d->numBuckets]);
870 Q_ASSERT(*node == e || (*node)->next);
871 while (*node != e && !(*node)->same_key(h, akey))
872 node = &(*node)->next;
874 node = const_cast<Node **>(reinterpret_cast<const Node * const *>(&e));
879 template <class Key, class T>
880 Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash<Key, T> &other) const
882 if (size() != other.size())
887 const_iterator it = begin();
889 while (it != end()) {
890 const Key &akey = it.key();
892 const_iterator it2 = other.find(akey);
894 if (it2 == other.end() || !(it2.key() == akey))
896 if (!QTypeInfo<T>::isDummy && !(it.value() == it2.value()))
900 } while (it != end() && it.key() == akey);
905 template <class Key, class T>
906 class QMultiHash : public QHash<Key, T>
910 QMultiHash(const QHash<Key, T> &other) : QHash<Key, T>(other) {}
911 inline void swap(QMultiHash<Key, T> &other) { QHash<Key, T>::swap(other); } // prevent QMultiHash<->QHash swaps
913 inline typename QHash<Key, T>::iterator replace(const Key &key, const T &value)
914 { return QHash<Key, T>::insert(key, value); }
916 inline typename QHash<Key, T>::iterator insert(const Key &key, const T &value)
917 { return QHash<Key, T>::insertMulti(key, value); }
919 inline QMultiHash &operator+=(const QMultiHash &other)
920 { this->unite(other); return *this; }
921 inline QMultiHash operator+(const QMultiHash &other) const
922 { QMultiHash result = *this; result += other; return result; }
924 #if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT)
925 // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class
926 using QHash<Key, T>::contains;
927 using QHash<Key, T>::remove;
928 using QHash<Key, T>::count;
929 using QHash<Key, T>::find;
930 using QHash<Key, T>::constFind;
932 inline bool contains(const Key &key) const
933 { return QHash<Key, T>::contains(key); }
934 inline int remove(const Key &key)
935 { return QHash<Key, T>::remove(key); }
936 inline int count(const Key &key) const
937 { return QHash<Key, T>::count(key); }
938 inline int count() const
939 { return QHash<Key, T>::count(); }
940 inline typename QHash<Key, T>::iterator find(const Key &key)
941 { return QHash<Key, T>::find(key); }
942 inline typename QHash<Key, T>::const_iterator find(const Key &key) const
943 { return QHash<Key, T>::find(key); }
944 inline typename QHash<Key, T>::const_iterator constFind(const Key &key) const
945 { return QHash<Key, T>::constFind(key); }
948 bool contains(const Key &key, const T &value) const;
950 int remove(const Key &key, const T &value);
952 int count(const Key &key, const T &value) const;
954 typename QHash<Key, T>::iterator find(const Key &key, const T &value) {
955 typename QHash<Key, T>::iterator i(find(key));
956 typename QHash<Key, T>::iterator end(this->end());
957 while (i != end && i.key() == key) {
958 if (i.value() == value)
964 typename QHash<Key, T>::const_iterator find(const Key &key, const T &value) const {
965 typename QHash<Key, T>::const_iterator i(constFind(key));
966 typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
967 while (i != end && i.key() == key) {
968 if (i.value() == value)
974 typename QHash<Key, T>::const_iterator constFind(const Key &key, const T &value) const
975 { return find(key, value); }
977 T &operator[](const Key &key);
978 const T operator[](const Key &key) const;
981 template <class Key, class T>
982 Q_INLINE_TEMPLATE bool QMultiHash<Key, T>::contains(const Key &key, const T &value) const
984 return constFind(key, value) != QHash<Key, T>::constEnd();
987 template <class Key, class T>
988 Q_INLINE_TEMPLATE int QMultiHash<Key, T>::remove(const Key &key, const T &value)
991 typename QHash<Key, T>::iterator i(find(key));
992 typename QHash<Key, T>::iterator end(QHash<Key, T>::end());
993 while (i != end && i.key() == key) {
994 if (i.value() == value) {
1004 template <class Key, class T>
1005 Q_INLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &key, const T &value) const
1008 typename QHash<Key, T>::const_iterator i(constFind(key));
1009 typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
1010 while (i != end && i.key() == key) {
1011 if (i.value() == value)
1018 Q_DECLARE_ASSOCIATIVE_ITERATOR(Hash)
1019 Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Hash)