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

Last change on this file since 890 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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