source: trunk/src/corelib/tools/qhash.h@ 448

Last change on this file since 448 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 28.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QHASH_H
43#define QHASH_H
44
45#include <QtCore/qatomic.h>
46#include <QtCore/qchar.h>
47#include <QtCore/qiterator.h>
48#include <QtCore/qlist.h>
49#include <QtCore/qpair.h>
50
51QT_BEGIN_HEADER
52
53QT_BEGIN_NAMESPACE
54
55#undef QT_QHASH_DEBUG
56QT_MODULE(Core)
57
58class QBitArray;
59class QByteArray;
60class QString;
61class QStringRef;
62
63inline uint qHash(char key) { return uint(key); }
64inline uint qHash(uchar key) { return uint(key); }
65inline uint qHash(signed char key) { return uint(key); }
66inline uint qHash(ushort key) { return uint(key); }
67inline uint qHash(short key) { return uint(key); }
68inline uint qHash(uint key) { return key; }
69inline uint qHash(int key) { return uint(key); }
70inline uint qHash(ulong key)
71{
72 if (sizeof(ulong) > sizeof(uint)) {
73 return uint((key >> (8 * sizeof(uint) - 1)) ^ key);
74 } else {
75 return uint(key);
76 }
77}
78inline uint qHash(long key) { return qHash(ulong(key)); }
79inline uint qHash(quint64 key)
80{
81 if (sizeof(quint64) > sizeof(uint)) {
82 return uint((key >> (8 * sizeof(uint) - 1)) ^ key);
83 } else {
84 return uint(key);
85 }
86}
87inline uint qHash(qint64 key) { return qHash(quint64(key)); }
88inline uint qHash(QChar key) { return qHash(key.unicode()); }
89Q_CORE_EXPORT uint qHash(const QByteArray &key);
90Q_CORE_EXPORT uint qHash(const QString &key);
91Q_CORE_EXPORT uint qHash(const QStringRef &key);
92Q_CORE_EXPORT uint qHash(const QBitArray &key);
93
94#if defined(Q_CC_MSVC)
95#pragma warning( push )
96#pragma warning( disable : 4311 ) // disable pointer truncation warning
97#endif
98template <class T> inline uint qHash(const T *key)
99{
100 if (sizeof(const T *) > sizeof(uint))
101 return qHash(reinterpret_cast<quint64>(key));
102 else
103 return uint(reinterpret_cast<ulong>(key));
104}
105#if defined(Q_CC_MSVC)
106#pragma warning( pop )
107#endif
108
109template <typename T1, typename T2> inline uint qHash(const QPair<T1, T2> &key)
110{
111 uint h1 = qHash(key.first);
112 uint h2 = qHash(key.second);
113 return ((h1 << 16) | (h1 >> 16)) ^ h2;
114}
115
116struct Q_CORE_EXPORT QHashData
117{
118 struct Node {
119 Node *next;
120 uint h;
121 };
122
123 Node *fakeNext;
124 Node **buckets;
125 QBasicAtomicInt ref;
126 int size;
127 int nodeSize;
128 short userNumBits;
129 short numBits;
130 int numBuckets;
131 uint sharable : 1;
132
133 void *allocateNode();
134 void freeNode(void *node);
135 QHashData *detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize);
136 void mightGrow();
137 bool willGrow();
138 void hasShrunk();
139 void rehash(int hint);
140 void destroyAndFree();
141 Node *firstNode();
142#ifdef QT_QHASH_DEBUG
143 void dump();
144 void checkSanity();
145#endif
146 static Node *nextNode(Node *node);
147 static Node *previousNode(Node *node);
148
149 static QHashData shared_null;
150};
151
152inline void QHashData::mightGrow() // ### Qt 5: eliminate
153{
154 if (size >= numBuckets)
155 rehash(numBits + 1);
156}
157
158inline bool QHashData::willGrow()
159{
160 if (size >= numBuckets) {
161 rehash(numBits + 1);
162 return true;
163 } else {
164 return false;
165 }
166}
167
168inline void QHashData::hasShrunk()
169{
170 if (size <= (numBuckets >> 3) && numBits > userNumBits)
171 rehash(qMax(int(numBits) - 2, int(userNumBits)));
172}
173
174inline QHashData::Node *QHashData::firstNode()
175{
176 Node *e = reinterpret_cast<Node *>(this);
177 Node **bucket = buckets;
178 int n = numBuckets;
179 while (n--) {
180 if (*bucket != e)
181 return *bucket;
182 ++bucket;
183 }
184 return e;
185}
186
187struct QHashDummyValue
188{
189};
190
191inline bool operator==(const QHashDummyValue & /* v1 */, const QHashDummyValue & /* v2 */)
192{
193 return true;
194}
195
196Q_DECLARE_TYPEINFO(QHashDummyValue, Q_MOVABLE_TYPE | Q_DUMMY_TYPE);
197
198template <class Key, class T>
199struct QHashDummyNode
200{
201 QHashDummyNode *next;
202 uint h;
203 Key key;
204
205 inline QHashDummyNode(const Key &key0) : key(key0) {}
206};
207
208template <class Key, class T>
209struct QHashNode
210{
211 QHashNode *next;
212 uint h;
213 Key key;
214 T value;
215
216 inline QHashNode(const Key &key0) : key(key0) {} // ### remove in 5.0
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; }
219};
220
221#ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
222#define Q_HASH_DECLARE_INT_NODES(key_type) \
223 template <class T> \
224 struct QHashDummyNode<key_type, T> { \
225 QHashDummyNode *next; \
226 union { uint h; key_type key; }; \
227\
228 inline QHashDummyNode(key_type /* key0 */) {} \
229 }; \
230\
231 template <class T> \
232 struct QHashNode<key_type, T> { \
233 QHashNode *next; \
234 union { uint h; key_type key; }; \
235 T value; \
236\
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; } \
240 }
241
242#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
243Q_HASH_DECLARE_INT_NODES(short);
244Q_HASH_DECLARE_INT_NODES(ushort);
245#endif
246Q_HASH_DECLARE_INT_NODES(int);
247Q_HASH_DECLARE_INT_NODES(uint);
248#undef Q_HASH_DECLARE_INT_NODES
249#endif // QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
250
251template <class Key, class T>
252class QHash
253{
254 typedef QHashDummyNode<Key, T> DummyNode;
255 typedef QHashNode<Key, T> Node;
256
257 union {
258 QHashData *d;
259 QHashNode<Key, T> *e;
260 };
261
262 static inline Node *concrete(QHashData::Node *node) {
263 return reinterpret_cast<Node *>(node);
264 }
265
266public:
267 inline QHash() : d(&QHashData::shared_null) { d->ref.ref(); }
268 inline QHash(const QHash<Key, T> &other) : d(other.d) { d->ref.ref(); if (!d->sharable) detach(); }
269 inline ~QHash() { if (!d->ref.deref()) freeData(d); }
270
271 QHash<Key, T> &operator=(const QHash<Key, T> &other);
272
273 bool operator==(const QHash<Key, T> &other) const;
274 inline bool operator!=(const QHash<Key, T> &other) const { return !(*this == other); }
275
276 inline int size() const { return d->size; }
277
278 inline bool isEmpty() const { return d->size == 0; }
279
280 inline int capacity() const { return d->numBuckets; }
281 void reserve(int size);
282 inline void squeeze() { reserve(1); }
283
284 inline void detach() { if (d->ref != 1) detach_helper(); }
285 inline bool isDetached() const { return d->ref == 1; }
286 inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
287
288 void clear();
289
290 int remove(const Key &key);
291 T take(const Key &key);
292
293 bool contains(const Key &key) const;
294 const Key key(const T &value) const;
295 const Key key(const T &value, const Key &defaultKey) const;
296 const T value(const Key &key) const;
297 const T value(const Key &key, const T &defaultValue) const;
298 T &operator[](const Key &key);
299 const T operator[](const Key &key) const;
300
301 QList<Key> uniqueKeys() const;
302 QList<Key> keys() const;
303 QList<Key> keys(const T &value) const;
304 QList<T> values() const;
305 QList<T> values(const Key &key) const;
306 int count(const Key &key) const;
307
308 class const_iterator;
309
310 class iterator
311 {
312 friend class const_iterator;
313 QHashData::Node *i;
314
315 public:
316 typedef std::bidirectional_iterator_tag iterator_category;
317 typedef ptrdiff_t difference_type;
318 typedef T value_type;
319 typedef T *pointer;
320 typedef T &reference;
321
322 // ### Qt 5: get rid of 'operator Node *'
323 inline operator Node *() const { return concrete(i); }
324 inline iterator() : i(0) { }
325 explicit inline iterator(void *node) : i(reinterpret_cast<QHashData::Node *>(node)) { }
326
327 inline const Key &key() const { return concrete(i)->key; }
328 inline T &value() const { return concrete(i)->value; }
329 inline T &operator*() const { return concrete(i)->value; }
330 inline T *operator->() const { return &concrete(i)->value; }
331 inline bool operator==(const iterator &o) const { return i == o.i; }
332 inline bool operator!=(const iterator &o) const { return i != o.i; }
333
334 inline iterator &operator++() {
335 i = QHashData::nextNode(i);
336 return *this;
337 }
338 inline iterator operator++(int) {
339 iterator r = *this;
340 i = QHashData::nextNode(i);
341 return r;
342 }
343 inline iterator &operator--() {
344 i = QHashData::previousNode(i);
345 return *this;
346 }
347 inline iterator operator--(int) {
348 iterator r = *this;
349 i = QHashData::previousNode(i);
350 return r;
351 }
352 inline iterator operator+(int j) const
353 { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
354 inline iterator operator-(int j) const { return operator+(-j); }
355 inline iterator &operator+=(int j) { return *this = *this + j; }
356 inline iterator &operator-=(int j) { return *this = *this - j; }
357
358 // ### Qt 5: not sure this is necessary anymore
359#ifdef QT_STRICT_ITERATORS
360 private:
361#else
362 public:
363#endif
364 inline bool operator==(const const_iterator &o) const
365 { return i == o.i; }
366 inline bool operator!=(const const_iterator &o) const
367 { return i != o.i; }
368
369 private:
370 // ### Qt 5: remove
371 inline operator bool() const { return false; }
372 };
373 friend class iterator;
374
375 class const_iterator
376 {
377 friend class iterator;
378 QHashData::Node *i;
379
380 public:
381 typedef std::bidirectional_iterator_tag iterator_category;
382 typedef ptrdiff_t difference_type;
383 typedef T value_type;
384 typedef const T *pointer;
385 typedef const T &reference;
386
387 // ### Qt 5: get rid of 'operator Node *'
388 inline operator Node *() const { return concrete(i); }
389 inline const_iterator() : i(0) { }
390 explicit inline const_iterator(void *node)
391 : i(reinterpret_cast<QHashData::Node *>(node)) { }
392#ifdef QT_STRICT_ITERATORS
393 explicit inline const_iterator(const iterator &o)
394#else
395 inline const_iterator(const iterator &o)
396#endif
397 { i = o.i; }
398
399 inline const Key &key() const { return concrete(i)->key; }
400 inline const T &value() const { return concrete(i)->value; }
401 inline const T &operator*() const { return concrete(i)->value; }
402 inline const T *operator->() const { return &concrete(i)->value; }
403 inline bool operator==(const const_iterator &o) const { return i == o.i; }
404 inline bool operator!=(const const_iterator &o) const { return i != o.i; }
405
406 inline const_iterator &operator++() {
407 i = QHashData::nextNode(i);
408 return *this;
409 }
410 inline const_iterator operator++(int) {
411 const_iterator r = *this;
412 i = QHashData::nextNode(i);
413 return r;
414 }
415 inline const_iterator &operator--() {
416 i = QHashData::previousNode(i);
417 return *this;
418 }
419 inline const_iterator operator--(int) {
420 const_iterator r = *this;
421 i = QHashData::previousNode(i);
422 return r;
423 }
424 inline const_iterator operator+(int j) const
425 { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
426 inline const_iterator operator-(int j) const { return operator+(-j); }
427 inline const_iterator &operator+=(int j) { return *this = *this + j; }
428 inline const_iterator &operator-=(int j) { return *this = *this - j; }
429
430 // ### Qt 5: not sure this is necessary anymore
431#ifdef QT_STRICT_ITERATORS
432 private:
433 inline bool operator==(const iterator &o) const { return operator==(const_iterator(o)); }
434 inline bool operator!=(const iterator &o) const { return operator!=(const_iterator(o)); }
435#endif
436
437 private:
438 // ### Qt 5: remove
439 inline operator bool() const { return false; }
440 };
441 friend class const_iterator;
442
443 // STL style
444 inline iterator begin() { detach(); return iterator(d->firstNode()); }
445 inline const_iterator begin() const { return const_iterator(d->firstNode()); }
446 inline const_iterator constBegin() const { return const_iterator(d->firstNode()); }
447 inline iterator end() { detach(); return iterator(e); }
448 inline const_iterator end() const { return const_iterator(e); }
449 inline const_iterator constEnd() const { return const_iterator(e); }
450 iterator erase(iterator it);
451
452 // more Qt
453 typedef iterator Iterator;
454 typedef const_iterator ConstIterator;
455 inline int count() const { return d->size; }
456 iterator find(const Key &key);
457 const_iterator find(const Key &key) const;
458 const_iterator constFind(const Key &key) const;
459 iterator insert(const Key &key, const T &value);
460 iterator insertMulti(const Key &key, const T &value);
461 QHash<Key, T> &unite(const QHash<Key, T> &other);
462
463 // STL compatibility
464 typedef T mapped_type;
465 typedef Key key_type;
466 typedef ptrdiff_t difference_type;
467 typedef int size_type;
468
469 inline bool empty() const { return isEmpty(); }
470
471#ifdef QT_QHASH_DEBUG
472 inline void dump() const { d->dump(); }
473 inline void checkSanity() const { d->checkSanity(); }
474#endif
475
476private:
477 void detach_helper();
478 void freeData(QHashData *d);
479 Node **findNode(const Key &key, uint *hp = 0) const;
480 Node *createNode(uint h, const Key &key, const T &value, Node **nextNode);
481 void deleteNode(Node *node);
482
483 static void duplicateNode(QHashData::Node *originalNode, void *newNode);
484};
485
486template <class Key, class T>
487Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(Node *node)
488{
489#ifdef Q_CC_BOR
490 node->~QHashNode<Key, T>();
491#elif defined(QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION)
492 node->~QHashNode();
493#else
494 node->~Node();
495#endif
496 d->freeNode(node);
497}
498
499template <class Key, class T>
500Q_INLINE_TEMPLATE void QHash<Key, T>::duplicateNode(QHashData::Node *node, void *newNode)
501{
502 Node *concreteNode = concrete(node);
503 if (QTypeInfo<T>::isDummy) {
504 (void) new (newNode) DummyNode(concreteNode->key);
505 } else {
506 (void) new (newNode) Node(concreteNode->key, concreteNode->value);
507 }
508}
509
510template <class Key, class T>
511Q_INLINE_TEMPLATE typename QHash<Key, T>::Node *
512QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode)
513{
514 Node *node;
515
516 if (QTypeInfo<T>::isDummy) {
517 node = reinterpret_cast<Node *>(new (d->allocateNode()) DummyNode(akey));
518 } else {
519 node = new (d->allocateNode()) Node(akey, avalue);
520 }
521
522 node->h = ah;
523 node->next = *anextNode;
524 *anextNode = node;
525 ++d->size;
526 return node;
527}
528
529template <class Key, class T>
530Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash<Key, T> &other)
531{
532 QHash<Key, T> copy(other);
533 const_iterator it = copy.constEnd();
534 while (it != copy.constBegin()) {
535 --it;
536 insertMulti(it.key(), it.value());
537 }
538 return *this;
539}
540
541template <class Key, class T>
542Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x)
543{
544 Node *e_for_x = reinterpret_cast<Node *>(x);
545 Node **bucket = reinterpret_cast<Node **>(x->buckets);
546 int n = x->numBuckets;
547 while (n--) {
548 Node *cur = *bucket++;
549 while (cur != e_for_x) {
550 Node *next = cur->next;
551 deleteNode(cur);
552 cur = next;
553 }
554 }
555 x->destroyAndFree();
556}
557
558template <class Key, class T>
559Q_INLINE_TEMPLATE void QHash<Key, T>::clear()
560{
561 *this = QHash<Key,T>();
562}
563
564template <class Key, class T>
565Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
566{
567 QHashData *x = d->detach_helper(duplicateNode,
568 QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node));
569 if (!d->ref.deref())
570 freeData(d);
571 d = x;
572}
573
574template <class Key, class T>
575Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::operator=(const QHash<Key, T> &other)
576{
577 if (d != other.d) {
578 other.d->ref.ref();
579 if (!d->ref.deref())
580 freeData(d);
581 d = other.d;
582 if (!d->sharable)
583 detach_helper();
584 }
585 return *this;
586}
587
588template <class Key, class T>
589Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey) const
590{
591 Node *node;
592 if (d->size == 0 || (node = *findNode(akey)) == e) {
593 return T();
594 } else {
595 return node->value;
596 }
597}
598
599template <class Key, class T>
600Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey, const T &adefaultValue) const
601{
602 Node *node;
603 if (d->size == 0 || (node = *findNode(akey)) == e) {
604 return adefaultValue;
605 } else {
606 return node->value;
607 }
608}
609
610template <class Key, class T>
611Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::uniqueKeys() const
612{
613 QList<Key> res;
614 const_iterator i = begin();
615 if (i != end()) {
616 for (;;) {
617 const Key &aKey = i.key();
618 res.append(aKey);
619 do {
620 if (++i == end())
621 goto break_out_of_outer_loop;
622 } while (aKey == i.key());
623 }
624 }
625break_out_of_outer_loop:
626 return res;
627}
628
629template <class Key, class T>
630Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys() const
631{
632 QList<Key> res;
633 const_iterator i = begin();
634 while (i != end()) {
635 res.append(i.key());
636 ++i;
637 }
638 return res;
639}
640
641template <class Key, class T>
642Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys(const T &avalue) const
643{
644 QList<Key> res;
645 const_iterator i = begin();
646 while (i != end()) {
647 if (i.value() == avalue)
648 res.append(i.key());
649 ++i;
650 }
651 return res;
652}
653
654template <class Key, class T>
655Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue) const
656{
657 return key(avalue, Key());
658}
659
660template <class Key, class T>
661Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue, const Key &defaultValue) const
662{
663 const_iterator i = begin();
664 while (i != end()) {
665 if (i.value() == avalue)
666 return i.key();
667 ++i;
668 }
669
670 return defaultValue;
671}
672
673template <class Key, class T>
674Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values() const
675{
676 QList<T> res;
677 const_iterator i = begin();
678 while (i != end()) {
679 res.append(i.value());
680 ++i;
681 }
682 return res;
683}
684
685template <class Key, class T>
686Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values(const Key &akey) const
687{
688 QList<T> res;
689 Node *node = *findNode(akey);
690 if (node != e) {
691 do {
692 res.append(node->value);
693 } while ((node = node->next) != e && node->key == akey);
694 }
695 return res;
696}
697
698template <class Key, class T>
699Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::count(const Key &akey) const
700{
701 int cnt = 0;
702 Node *node = *findNode(akey);
703 if (node != e) {
704 do {
705 ++cnt;
706 } while ((node = node->next) != e && node->key == akey);
707 }
708 return cnt;
709}
710
711template <class Key, class T>
712Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const
713{
714 return value(akey);
715}
716
717template <class Key, class T>
718Q_INLINE_TEMPLATE T &QHash<Key, T>::operator[](const Key &akey)
719{
720 detach();
721
722 uint h;
723 Node **node = findNode(akey, &h);
724 if (*node == e) {
725 if (d->willGrow())
726 node = findNode(akey, &h);
727 return createNode(h, akey, T(), node)->value;
728 }
729 return (*node)->value;
730}
731
732template <class Key, class T>
733Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insert(const Key &akey,
734 const T &avalue)
735{
736 detach();
737
738 uint h;
739 Node **node = findNode(akey, &h);
740 if (*node == e) {
741 if (d->willGrow())
742 node = findNode(akey, &h);
743 return iterator(createNode(h, akey, avalue, node));
744 }
745
746 if (!QTypeInfo<T>::isDummy)
747 (*node)->value = avalue;
748 return iterator(*node);
749}
750
751template <class Key, class T>
752Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &akey,
753 const T &avalue)
754{
755 detach();
756 d->willGrow();
757
758 uint h;
759 Node **nextNode = findNode(akey, &h);
760 return iterator(createNode(h, akey, avalue, nextNode));
761}
762
763template <class Key, class T>
764Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::remove(const Key &akey)
765{
766 detach();
767
768 int oldSize = d->size;
769 Node **node = findNode(akey);
770 if (*node != e) {
771 bool deleteNext = true;
772 do {
773 Node *next = (*node)->next;
774 deleteNext = (next != e && next->key == (*node)->key);
775 deleteNode(*node);
776 *node = next;
777 --d->size;
778 } while (deleteNext);
779 d->hasShrunk();
780 }
781 return oldSize - d->size;
782}
783
784template <class Key, class T>
785Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey)
786{
787 detach();
788
789 Node **node = findNode(akey);
790 if (*node != e) {
791 T t = (*node)->value;
792 Node *next = (*node)->next;
793 deleteNode(*node);
794 *node = next;
795 --d->size;
796 d->hasShrunk();
797 return t;
798 }
799 return T();
800}
801
802template <class Key, class T>
803Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::erase(iterator it)
804{
805 if (it == iterator(e))
806 return it;
807
808 iterator ret = it;
809 ++ret;
810
811 Node *node = it;
812 Node **node_ptr = reinterpret_cast<Node **>(&d->buckets[node->h % d->numBuckets]);
813 while (*node_ptr != node)
814 node_ptr = &(*node_ptr)->next;
815 *node_ptr = node->next;
816 deleteNode(node);
817 --d->size;
818 return ret;
819}
820
821template <class Key, class T>
822Q_INLINE_TEMPLATE void QHash<Key, T>::reserve(int asize)
823{
824 detach();
825 d->rehash(-qMax(asize, 1));
826}
827
828template <class Key, class T>
829Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &akey) const
830{
831 return const_iterator(*findNode(akey));
832}
833
834template <class Key, class T>
835Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::constFind(const Key &akey) const
836{
837 return const_iterator(*findNode(akey));
838}
839
840template <class Key, class T>
841Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::find(const Key &akey)
842{
843 detach();
844 return iterator(*findNode(akey));
845}
846
847template <class Key, class T>
848Q_INLINE_TEMPLATE bool QHash<Key, T>::contains(const Key &akey) const
849{
850 return *findNode(akey) != e;
851}
852
853template <class Key, class T>
854Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(const Key &akey,
855 uint *ahp) const
856{
857 Node **node;
858 uint h = qHash(akey);
859
860 if (d->numBuckets) {
861 node = reinterpret_cast<Node **>(&d->buckets[h % d->numBuckets]);
862 Q_ASSERT(*node == e || (*node)->next);
863 while (*node != e && !(*node)->same_key(h, akey))
864 node = &(*node)->next;
865 } else {
866 node = const_cast<Node **>(reinterpret_cast<const Node * const *>(&e));
867 }
868 if (ahp)
869 *ahp = h;
870 return node;
871}
872
873template <class Key, class T>
874Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash<Key, T> &other) const
875{
876 if (size() != other.size())
877 return false;
878 if (d == other.d)
879 return true;
880
881 const_iterator it = begin();
882
883 while (it != end()) {
884 const Key &akey = it.key();
885
886 const_iterator it2 = other.find(akey);
887 do {
888 if (it2 == other.end() || !(it2.key() == akey))
889 return false;
890 if (!QTypeInfo<T>::isDummy && !(it.value() == it2.value()))
891 return false;
892 ++it;
893 ++it2;
894 } while (it != end() && it.key() == akey);
895 }
896 return true;
897}
898
899template <class Key, class T>
900class QMultiHash : public QHash<Key, T>
901{
902public:
903 QMultiHash() {}
904 QMultiHash(const QHash<Key, T> &other) : QHash<Key, T>(other) {}
905
906 inline typename QHash<Key, T>::iterator replace(const Key &key, const T &value)
907 { return QHash<Key, T>::insert(key, value); }
908
909 inline typename QHash<Key, T>::iterator insert(const Key &key, const T &value)
910 { return QHash<Key, T>::insertMulti(key, value); }
911
912 inline QMultiHash &operator+=(const QMultiHash &other)
913 { unite(other); return *this; }
914 inline QMultiHash operator+(const QMultiHash &other) const
915 { QMultiHash result = *this; result += other; return result; }
916
917#ifndef Q_NO_USING_KEYWORD
918 using QHash<Key, T>::contains;
919 using QHash<Key, T>::remove;
920 using QHash<Key, T>::count;
921 using QHash<Key, T>::find;
922 using QHash<Key, T>::constFind;
923#else
924 inline bool contains(const Key &key) const
925 { return QHash<Key, T>::contains(key); }
926 inline int remove(const Key &key)
927 { return QHash<Key, T>::remove(key); }
928 inline int count(const Key &key) const
929 { return QHash<Key, T>::count(key); }
930 inline int count() const
931 { return QHash<Key, T>::count(); }
932 inline typename QHash<Key, T>::iterator find(const Key &key)
933 { return QHash<Key, T>::find(key); }
934 inline typename QHash<Key, T>::const_iterator find(const Key &key) const
935 { return QHash<Key, T>::find(key); }
936 inline typename QHash<Key, T>::const_iterator constFind(const Key &key) const
937 { return QHash<Key, T>::constFind(key); }
938#endif
939
940 bool contains(const Key &key, const T &value) const;
941
942 int remove(const Key &key, const T &value);
943
944 int count(const Key &key, const T &value) const;
945
946 typename QHash<Key, T>::iterator find(const Key &key, const T &value) {
947 typename QHash<Key, T>::iterator i(find(key));
948 typename QHash<Key, T>::iterator end(this->end());
949 while (i != end && i.key() == key) {
950 if (i.value() == value)
951 return i;
952 ++i;
953 }
954 return end;
955 }
956 typename QHash<Key, T>::const_iterator find(const Key &key, const T &value) const {
957 typename QHash<Key, T>::const_iterator i(constFind(key));
958 typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
959 while (i != end && i.key() == key) {
960 if (i.value() == value)
961 return i;
962 ++i;
963 }
964 return end;
965 }
966 typename QHash<Key, T>::const_iterator constFind(const Key &key, const T &value) const
967 { return find(key, value); }
968private:
969 T &operator[](const Key &key);
970 const T operator[](const Key &key) const;
971};
972
973template <class Key, class T>
974Q_INLINE_TEMPLATE bool QMultiHash<Key, T>::contains(const Key &key, const T &value) const
975{
976 return constFind(key, value) != QHash<Key, T>::constEnd();
977}
978
979template <class Key, class T>
980Q_INLINE_TEMPLATE int QMultiHash<Key, T>::remove(const Key &key, const T &value)
981{
982 int n = 0;
983 typename QHash<Key, T>::iterator i(find(key));
984 typename QHash<Key, T>::iterator end(QHash<Key, T>::end());
985 while (i != end && i.key() == key) {
986 if (i.value() == value) {
987 i = erase(i);
988 ++n;
989 } else {
990 ++i;
991 }
992 }
993 return n;
994}
995
996template <class Key, class T>
997Q_INLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &key, const T &value) const
998{
999 int n = 0;
1000 typename QHash<Key, T>::const_iterator i(constFind(key));
1001 typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
1002 while (i != end && i.key() == key) {
1003 if (i.value() == value)
1004 ++n;
1005 ++i;
1006 }
1007 return n;
1008}
1009
1010Q_DECLARE_ASSOCIATIVE_ITERATOR(Hash)
1011Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Hash)
1012
1013QT_END_NAMESPACE
1014
1015QT_END_HEADER
1016
1017#endif // QHASH_H
Note: See TracBrowser for help on using the repository browser.