source: trunk/src/corelib/tools/qmap.h@ 570

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

trunk: Merged in qt 4.6.1 sources.

File size: 31.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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 QMAP_H
43#define QMAP_H
44
45#include <QtCore/qatomic.h>
46#include <QtCore/qiterator.h>
47#include <QtCore/qlist.h>
48
49#ifndef QT_NO_STL
50#include <map>
51#endif
52
53#include <new>
54
55QT_BEGIN_HEADER
56
57QT_BEGIN_NAMESPACE
58
59QT_MODULE(Core)
60
61struct Q_CORE_EXPORT QMapData
62{
63 struct Node {
64 Node *backward;
65 Node *forward[1];
66 };
67 enum { LastLevel = 11, Sparseness = 3 };
68
69 QMapData *backward;
70 QMapData *forward[QMapData::LastLevel + 1];
71 QBasicAtomicInt ref;
72 int topLevel;
73 int size;
74 uint randomBits;
75 uint insertInOrder : 1;
76 uint sharable : 1;
77 uint strictAlignment : 1;
78 uint reserved : 29;
79
80 static QMapData *createData(); // ### Qt5 remove me
81 static QMapData *createData(int alignment);
82 void continueFreeData(int offset);
83 Node *node_create(Node *update[], int offset); // ### Qt5 remove me
84 Node *node_create(Node *update[], int offset, int alignment);
85 void node_delete(Node *update[], int offset, Node *node);
86#ifdef QT_QMAP_DEBUG
87 uint adjust_ptr(Node *node);
88 void dump();
89#endif
90
91 static QMapData shared_null;
92};
93
94
95/*
96 QMap uses qMapLessThanKey() to compare keys. The default
97 implementation uses operator<(). For pointer types,
98 qMapLessThanKey() casts the pointers to integers before it
99 compares them, because operator<() is undefined on pointers
100 that come from different memory blocks. (In practice, this
101 is only a problem when running a program such as
102 BoundsChecker.)
103*/
104
105template <class Key> inline bool qMapLessThanKey(const Key &key1, const Key &key2)
106{
107 return key1 < key2;
108}
109
110#ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
111template <class Ptr> inline bool qMapLessThanKey(Ptr *key1, Ptr *key2)
112{
113 Q_ASSERT(sizeof(quintptr) == sizeof(Ptr *));
114 return quintptr(key1) < quintptr(key2);
115}
116
117template <class Ptr> inline bool qMapLessThanKey(const Ptr *key1, const Ptr *key2)
118{
119 Q_ASSERT(sizeof(quintptr) == sizeof(const Ptr *));
120 return quintptr(key1) < quintptr(key2);
121}
122#endif // QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
123
124template <class Key, class T>
125struct QMapNode {
126 Key key;
127 T value;
128 QMapData::Node *backward;
129 QMapData::Node *forward[1];
130};
131
132template <class Key, class T>
133struct QMapPayloadNode
134{
135 Key key;
136 T value;
137 QMapData::Node *backward;
138};
139
140template <class Key, class T>
141class QMap
142{
143 typedef QMapNode<Key, T> Node;
144 typedef QMapPayloadNode<Key, T> PayloadNode;
145
146 union {
147 QMapData *d;
148 QMapData::Node *e;
149 };
150
151 static inline int payload() { return sizeof(PayloadNode) - sizeof(QMapData::Node *); }
152 static inline int alignment() {
153#ifdef Q_ALIGNOF
154 return int(qMax(sizeof(void*), Q_ALIGNOF(Node)));
155#else
156 return 0;
157#endif
158 }
159 static inline Node *concrete(QMapData::Node *node) {
160 return reinterpret_cast<Node *>(reinterpret_cast<char *>(node) - payload());
161 }
162
163public:
164 inline QMap() : d(&QMapData::shared_null) { d->ref.ref(); }
165 inline QMap(const QMap<Key, T> &other) : d(other.d)
166 { d->ref.ref(); if (!d->sharable) detach(); }
167 inline ~QMap() { if (!d) return; if (!d->ref.deref()) freeData(d); }
168
169 QMap<Key, T> &operator=(const QMap<Key, T> &other);
170#ifndef QT_NO_STL
171 explicit QMap(const typename std::map<Key, T> &other);
172 std::map<Key, T> toStdMap() const;
173#endif
174
175 bool operator==(const QMap<Key, T> &other) const;
176 inline bool operator!=(const QMap<Key, T> &other) const { return !(*this == other); }
177
178 inline int size() const { return d->size; }
179
180 inline bool isEmpty() const { return d->size == 0; }
181
182 inline void detach() { if (d->ref != 1) detach_helper(); }
183 inline bool isDetached() const { return d->ref == 1; }
184 inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
185 inline void setInsertInOrder(bool ordered) { d->insertInOrder = ordered; }
186
187 void clear();
188
189 int remove(const Key &key);
190 T take(const Key &key);
191
192 bool contains(const Key &key) const;
193 const Key key(const T &value) const;
194 const Key key(const T &value, const Key &defaultKey) const;
195 const T value(const Key &key) const;
196 const T value(const Key &key, const T &defaultValue) const;
197 T &operator[](const Key &key);
198 const T operator[](const Key &key) const;
199
200 QList<Key> uniqueKeys() const;
201 QList<Key> keys() const;
202 QList<Key> keys(const T &value) const;
203 QList<T> values() const;
204 QList<T> values(const Key &key) const;
205 int count(const Key &key) const;
206
207 class const_iterator;
208
209 class iterator
210 {
211 friend class const_iterator;
212 QMapData::Node *i;
213
214 public:
215 typedef std::bidirectional_iterator_tag iterator_category;
216 typedef ptrdiff_t difference_type;
217 typedef T value_type;
218 typedef T *pointer;
219 typedef T &reference;
220
221 // ### Qt 5: get rid of 'operator Node *'
222 inline operator QMapData::Node *() const { return i; }
223 inline iterator() : i(0) { }
224 inline iterator(QMapData::Node *node) : i(node) { }
225
226 inline const Key &key() const { return concrete(i)->key; }
227 inline T &value() const { return concrete(i)->value; }
228#ifdef QT3_SUPPORT
229 inline QT3_SUPPORT T &data() const { return concrete(i)->value; }
230#endif
231 inline T &operator*() const { return concrete(i)->value; }
232 inline T *operator->() const { return &concrete(i)->value; }
233 inline bool operator==(const iterator &o) const { return i == o.i; }
234 inline bool operator!=(const iterator &o) const { return i != o.i; }
235
236 inline iterator &operator++() {
237 i = i->forward[0];
238 return *this;
239 }
240 inline iterator operator++(int) {
241 iterator r = *this;
242 i = i->forward[0];
243 return r;
244 }
245 inline iterator &operator--() {
246 i = i->backward;
247 return *this;
248 }
249 inline iterator operator--(int) {
250 iterator r = *this;
251 i = i->backward;
252 return r;
253 }
254 inline iterator operator+(int j) const
255 { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
256 inline iterator operator-(int j) const { return operator+(-j); }
257 inline iterator &operator+=(int j) { return *this = *this + j; }
258 inline iterator &operator-=(int j) { return *this = *this - j; }
259
260 // ### Qt 5: not sure this is necessary anymore
261#ifdef QT_STRICT_ITERATORS
262 private:
263#else
264 public:
265#endif
266 inline bool operator==(const const_iterator &o) const
267 { return i == o.i; }
268 inline bool operator!=(const const_iterator &o) const
269 { return i != o.i; }
270
271 private:
272 // ### Qt 5: remove
273 inline operator bool() const { return false; }
274 };
275 friend class iterator;
276
277 class const_iterator
278 {
279 friend class iterator;
280 QMapData::Node *i;
281
282 public:
283 typedef std::bidirectional_iterator_tag iterator_category;
284 typedef ptrdiff_t difference_type;
285 typedef T value_type;
286 typedef const T *pointer;
287 typedef const T &reference;
288
289 // ### Qt 5: get rid of 'operator Node *'
290 inline operator QMapData::Node *() const { return i; }
291 inline const_iterator() : i(0) { }
292 inline const_iterator(QMapData::Node *node) : i(node) { }
293#ifdef QT_STRICT_ITERATORS
294 explicit inline const_iterator(const iterator &o)
295#else
296 inline const_iterator(const iterator &o)
297#endif
298 { i = o.i; }
299
300 inline const Key &key() const { return concrete(i)->key; }
301 inline const T &value() const { return concrete(i)->value; }
302#ifdef QT3_SUPPORT
303 inline QT3_SUPPORT const T &data() const { return concrete(i)->value; }
304#endif
305 inline const T &operator*() const { return concrete(i)->value; }
306 inline const T *operator->() const { return &concrete(i)->value; }
307 inline bool operator==(const const_iterator &o) const { return i == o.i; }
308 inline bool operator!=(const const_iterator &o) const { return i != o.i; }
309
310 inline const_iterator &operator++() {
311 i = i->forward[0];
312 return *this;
313 }
314 inline const_iterator operator++(int) {
315 const_iterator r = *this;
316 i = i->forward[0];
317 return r;
318 }
319 inline const_iterator &operator--() {
320 i = i->backward;
321 return *this;
322 }
323 inline const_iterator operator--(int) {
324 const_iterator r = *this;
325 i = i->backward;
326 return r;
327 }
328 inline const_iterator operator+(int j) const
329 { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
330 inline const_iterator operator-(int j) const { return operator+(-j); }
331 inline const_iterator &operator+=(int j) { return *this = *this + j; }
332 inline const_iterator &operator-=(int j) { return *this = *this - j; }
333
334 // ### Qt 5: not sure this is necessary anymore
335#ifdef QT_STRICT_ITERATORS
336 private:
337 inline bool operator==(const iterator &o) { return operator==(const_iterator(o)); }
338 inline bool operator!=(const iterator &o) { return operator!=(const_iterator(o)); }
339#endif
340
341 private:
342 // ### Qt 5: remove
343 inline operator bool() const { return false; }
344 };
345 friend class const_iterator;
346
347 // STL style
348 inline iterator begin() { detach(); return iterator(e->forward[0]); }
349 inline const_iterator begin() const { return const_iterator(e->forward[0]); }
350 inline const_iterator constBegin() const { return const_iterator(e->forward[0]); }
351 inline iterator end() {
352 detach();
353 return iterator(e);
354 }
355 inline const_iterator end() const { return const_iterator(e); }
356 inline const_iterator constEnd() const { return const_iterator(e); }
357 iterator erase(iterator it);
358#ifdef QT3_SUPPORT
359 inline QT3_SUPPORT iterator remove(iterator it) { return erase(it); }
360 inline QT3_SUPPORT void erase(const Key &aKey) { remove(aKey); }
361#endif
362
363 // more Qt
364 typedef iterator Iterator;
365 typedef const_iterator ConstIterator;
366 inline int count() const { return d->size; }
367 iterator find(const Key &key);
368 const_iterator find(const Key &key) const;
369 const_iterator constFind(const Key &key) const;
370 iterator lowerBound(const Key &key);
371 const_iterator lowerBound(const Key &key) const;
372 iterator upperBound(const Key &key);
373 const_iterator upperBound(const Key &key) const;
374 iterator insert(const Key &key, const T &value);
375#ifdef QT3_SUPPORT
376 QT3_SUPPORT iterator insert(const Key &key, const T &value, bool overwrite);
377#endif
378 iterator insertMulti(const Key &key, const T &value);
379#ifdef QT3_SUPPORT
380 inline QT3_SUPPORT iterator replace(const Key &aKey, const T &aValue) { return insert(aKey, aValue); }
381#endif
382 QMap<Key, T> &unite(const QMap<Key, T> &other);
383
384 // STL compatibility
385 typedef Key key_type;
386 typedef T mapped_type;
387 typedef ptrdiff_t difference_type;
388 typedef int size_type;
389 inline bool empty() const { return isEmpty(); }
390
391#ifdef QT_QMAP_DEBUG
392 inline void dump() const { d->dump(); }
393#endif
394
395private:
396 void detach_helper();
397 void freeData(QMapData *d);
398 QMapData::Node *findNode(const Key &key) const;
399 QMapData::Node *mutableFindNode(QMapData::Node *update[], const Key &key) const;
400 QMapData::Node *node_create(QMapData *d, QMapData::Node *update[], const Key &key,
401 const T &value);
402};
403
404template <class Key, class T>
405Q_INLINE_TEMPLATE QMap<Key, T> &QMap<Key, T>::operator=(const QMap<Key, T> &other)
406{
407 if (d != other.d) {
408 other.d->ref.ref();
409 if (!d->ref.deref())
410 freeData(d);
411 d = other.d;
412 if (!d->sharable)
413 detach_helper();
414 }
415 return *this;
416}
417
418template <class Key, class T>
419Q_INLINE_TEMPLATE void QMap<Key, T>::clear()
420{
421 *this = QMap<Key, T>();
422}
423
424template <class Key, class T>
425Q_INLINE_TEMPLATE typename QMapData::Node *
426QMap<Key, T>::node_create(QMapData *adt, QMapData::Node *aupdate[], const Key &akey, const T &avalue)
427{
428 QMapData::Node *abstractNode = adt->node_create(aupdate, payload(), alignment());
429 QT_TRY {
430 Node *concreteNode = concrete(abstractNode);
431 new (&concreteNode->key) Key(akey);
432 QT_TRY {
433 new (&concreteNode->value) T(avalue);
434 } QT_CATCH(...) {
435 concreteNode->key.~Key();
436 QT_RETHROW;
437 }
438 } QT_CATCH(...) {
439 adt->node_delete(aupdate, payload(), abstractNode);
440 QT_RETHROW;
441 }
442
443 // clean up the update array for further insertions
444 /*
445 for (int i = 0; i <= d->topLevel; ++i) {
446 if ( aupdate[i]==reinterpret_cast<QMapData::Node *>(adt) || aupdate[i]->forward[i] != abstractNode)
447 break;
448 aupdate[i] = abstractNode;
449 }
450*/
451
452 return abstractNode;
453}
454
455template <class Key, class T>
456Q_INLINE_TEMPLATE QMapData::Node *QMap<Key, T>::findNode(const Key &akey) const
457{
458 QMapData::Node *cur = e;
459 QMapData::Node *next = e;
460
461 for (int i = d->topLevel; i >= 0; i--) {
462 while ((next = cur->forward[i]) != e && qMapLessThanKey<Key>(concrete(next)->key, akey))
463 cur = next;
464 }
465
466 if (next != e && !qMapLessThanKey<Key>(akey, concrete(next)->key)) {
467 return next;
468 } else {
469 return e;
470 }
471}
472
473template <class Key, class T>
474Q_INLINE_TEMPLATE const T QMap<Key, T>::value(const Key &akey) const
475{
476 QMapData::Node *node;
477 if (d->size == 0 || (node = findNode(akey)) == e) {
478 return T();
479 } else {
480 return concrete(node)->value;
481 }
482}
483
484template <class Key, class T>
485Q_INLINE_TEMPLATE const T QMap<Key, T>::value(const Key &akey, const T &adefaultValue) const
486{
487 QMapData::Node *node;
488 if (d->size == 0 || (node = findNode(akey)) == e) {
489 return adefaultValue;
490 } else {
491 return concrete(node)->value;
492 }
493}
494
495template <class Key, class T>
496Q_INLINE_TEMPLATE const T QMap<Key, T>::operator[](const Key &akey) const
497{
498 return value(akey);
499}
500
501template <class Key, class T>
502Q_INLINE_TEMPLATE T &QMap<Key, T>::operator[](const Key &akey)
503{
504 detach();
505
506 QMapData::Node *update[QMapData::LastLevel + 1];
507 QMapData::Node *node = mutableFindNode(update, akey);
508 if (node == e)
509 node = node_create(d, update, akey, T());
510 return concrete(node)->value;
511}
512
513template <class Key, class T>
514Q_INLINE_TEMPLATE int QMap<Key, T>::count(const Key &akey) const
515{
516 int cnt = 0;
517 QMapData::Node *node = findNode(akey);
518 if (node != e) {
519 do {
520 ++cnt;
521 node = node->forward[0];
522 } while (node != e && !qMapLessThanKey<Key>(akey, concrete(node)->key));
523 }
524 return cnt;
525}
526
527template <class Key, class T>
528Q_INLINE_TEMPLATE bool QMap<Key, T>::contains(const Key &akey) const
529{
530 return findNode(akey) != e;
531}
532
533template <class Key, class T>
534Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insert(const Key &akey,
535 const T &avalue)
536{
537 detach();
538
539 QMapData::Node *update[QMapData::LastLevel + 1];
540 QMapData::Node *node = mutableFindNode(update, akey);
541 if (node == e) {
542 node = node_create(d, update, akey, avalue);
543 } else {
544 concrete(node)->value = avalue;
545 }
546 return iterator(node);
547}
548
549#ifdef QT3_SUPPORT
550template <class Key, class T>
551Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insert(const Key &akey,
552 const T &avalue,
553 bool aoverwrite)
554{
555 detach();
556
557 QMapData::Node *update[QMapData::LastLevel + 1];
558 QMapData::Node *node = mutableFindNode(update, akey);
559 if (node == e) {
560 node = node_create(d, update, akey, avalue);
561 } else {
562 if (aoverwrite)
563 concrete(node)->value = avalue;
564 }
565 return iterator(node);
566}
567#endif
568
569template <class Key, class T>
570Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key &akey,
571 const T &avalue)
572{
573 detach();
574
575 QMapData::Node *update[QMapData::LastLevel + 1];
576 mutableFindNode(update, akey);
577 return iterator(node_create(d, update, akey, avalue));
578}
579
580template <class Key, class T>
581Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator QMap<Key, T>::find(const Key &akey) const
582{
583 return const_iterator(findNode(akey));
584}
585
586template <class Key, class T>
587Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator QMap<Key, T>::constFind(const Key &akey) const
588{
589 return const_iterator(findNode(akey));
590}
591
592template <class Key, class T>
593Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::find(const Key &akey)
594{
595 detach();
596 return iterator(findNode(akey));
597}
598
599template <class Key, class T>
600Q_INLINE_TEMPLATE QMap<Key, T> &QMap<Key, T>::unite(const QMap<Key, T> &other)
601{
602 QMap<Key, T> copy(other);
603 const_iterator it = copy.constEnd();
604 const const_iterator b = copy.constBegin();
605 while (it != b) {
606 --it;
607 insertMulti(it.key(), it.value());
608 }
609 return *this;
610}
611
612template <class Key, class T>
613Q_OUTOFLINE_TEMPLATE void QMap<Key, T>::freeData(QMapData *x)
614{
615 if (QTypeInfo<Key>::isComplex || QTypeInfo<T>::isComplex) {
616 QMapData *cur = x;
617 QMapData *next = cur->forward[0];
618 while (next != x) {
619 cur = next;
620 next = cur->forward[0];
621#if defined(_MSC_VER) && (_MSC_VER >= 1300)
622#pragma warning(disable:4189)
623#endif
624 Node *concreteNode = concrete(reinterpret_cast<QMapData::Node *>(cur));
625 concreteNode->key.~Key();
626 concreteNode->value.~T();
627#if defined(_MSC_VER) && (_MSC_VER >= 1300)
628#pragma warning(default:4189)
629#endif
630 }
631 }
632 x->continueFreeData(payload());
633}
634
635template <class Key, class T>
636Q_OUTOFLINE_TEMPLATE int QMap<Key, T>::remove(const Key &akey)
637{
638 detach();
639
640 QMapData::Node *update[QMapData::LastLevel + 1];
641 QMapData::Node *cur = e;
642 QMapData::Node *next = e;
643 int oldSize = d->size;
644
645 for (int i = d->topLevel; i >= 0; i--) {
646 while ((next = cur->forward[i]) != e && qMapLessThanKey<Key>(concrete(next)->key, akey))
647 cur = next;
648 update[i] = cur;
649 }
650
651 if (next != e && !qMapLessThanKey<Key>(akey, concrete(next)->key)) {
652 bool deleteNext = true;
653 do {
654 cur = next;
655 next = cur->forward[0];
656 deleteNext = (next != e && !qMapLessThanKey<Key>(concrete(cur)->key, concrete(next)->key));
657 concrete(cur)->key.~Key();
658 concrete(cur)->value.~T();
659 d->node_delete(update, payload(), cur);
660 } while (deleteNext);
661 }
662 return oldSize - d->size;
663}
664
665template <class Key, class T>
666Q_OUTOFLINE_TEMPLATE T QMap<Key, T>::take(const Key &akey)
667{
668 detach();
669
670 QMapData::Node *update[QMapData::LastLevel + 1];
671 QMapData::Node *cur = e;
672 QMapData::Node *next = e;
673
674 for (int i = d->topLevel; i >= 0; i--) {
675 while ((next = cur->forward[i]) != e && qMapLessThanKey<Key>(concrete(next)->key, akey))
676 cur = next;
677 update[i] = cur;
678 }
679
680 if (next != e && !qMapLessThanKey<Key>(akey, concrete(next)->key)) {
681 T t = concrete(next)->value;
682 concrete(next)->key.~Key();
683 concrete(next)->value.~T();
684 d->node_delete(update, payload(), next);
685 return t;
686 }
687 return T();
688}
689
690template <class Key, class T>
691Q_OUTOFLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::erase(iterator it)
692{
693 QMapData::Node *update[QMapData::LastLevel + 1];
694 QMapData::Node *cur = e;
695 QMapData::Node *next = e;
696
697 if (it == iterator(e))
698 return it;
699
700 for (int i = d->topLevel; i >= 0; i--) {
701 while ((next = cur->forward[i]) != e && qMapLessThanKey<Key>(concrete(next)->key, it.key()))
702 cur = next;
703 update[i] = cur;
704 }
705
706 while (next != e) {
707 cur = next;
708 next = cur->forward[0];
709 if (cur == it) {
710 concrete(cur)->key.~Key();
711 concrete(cur)->value.~T();
712 d->node_delete(update, payload(), cur);
713 return iterator(next);
714 }
715
716 for (int i = 0; i <= d->topLevel; ++i) {
717 if (update[i]->forward[i] != cur)
718 break;
719 update[i] = cur;
720 }
721 }
722 return end();
723}
724
725template <class Key, class T>
726Q_OUTOFLINE_TEMPLATE void QMap<Key, T>::detach_helper()
727{
728 union { QMapData *d; QMapData::Node *e; } x;
729 x.d = QMapData::createData(alignment());
730 if (d->size) {
731 x.d->insertInOrder = true;
732 QMapData::Node *update[QMapData::LastLevel + 1];
733 QMapData::Node *cur = e->forward[0];
734 update[0] = x.e;
735 while (cur != e) {
736 QT_TRY {
737 Node *concreteNode = concrete(cur);
738 node_create(x.d, update, concreteNode->key, concreteNode->value);
739 } QT_CATCH(...) {
740 freeData(x.d);
741 QT_RETHROW;
742 }
743 cur = cur->forward[0];
744 }
745 x.d->insertInOrder = false;
746 }
747 if (!d->ref.deref())
748 freeData(d);
749 d = x.d;
750}
751
752template <class Key, class T>
753Q_OUTOFLINE_TEMPLATE QMapData::Node *QMap<Key, T>::mutableFindNode(QMapData::Node *aupdate[],
754 const Key &akey) const
755{
756 QMapData::Node *cur = e;
757 QMapData::Node *next = e;
758
759 for (int i = d->topLevel; i >= 0; i--) {
760 while ((next = cur->forward[i]) != e && qMapLessThanKey<Key>(concrete(next)->key, akey))
761 cur = next;
762 aupdate[i] = cur;
763 }
764 if (next != e && !qMapLessThanKey<Key>(akey, concrete(next)->key)) {
765 return next;
766 } else {
767 return e;
768 }
769}
770
771template <class Key, class T>
772Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::uniqueKeys() const
773{
774 QList<Key> res;
775 const_iterator i = begin();
776 if (i != end()) {
777 for (;;) {
778 const Key &aKey = i.key();
779 res.append(aKey);
780 do {
781 if (++i == end())
782 goto break_out_of_outer_loop;
783 } while (!(aKey < i.key())); // loop while (key == i.key())
784 }
785 }
786break_out_of_outer_loop:
787 return res;
788}
789
790template <class Key, class T>
791Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::keys() const
792{
793 QList<Key> res;
794 const_iterator i = begin();
795 while (i != end()) {
796 res.append(i.key());
797 ++i;
798 }
799 return res;
800}
801
802template <class Key, class T>
803Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::keys(const T &avalue) const
804{
805 QList<Key> res;
806 const_iterator i = begin();
807 while (i != end()) {
808 if (i.value() == avalue)
809 res.append(i.key());
810 ++i;
811 }
812 return res;
813}
814
815template <class Key, class T>
816Q_OUTOFLINE_TEMPLATE const Key QMap<Key, T>::key(const T &avalue) const
817{
818 return key(avalue, Key());
819}
820
821template <class Key, class T>
822Q_OUTOFLINE_TEMPLATE const Key QMap<Key, T>::key(const T &avalue, const Key &defaultKey) const
823{
824 const_iterator i = begin();
825 while (i != end()) {
826 if (i.value() == avalue)
827 return i.key();
828 ++i;
829 }
830
831 return defaultKey;
832}
833
834template <class Key, class T>
835Q_OUTOFLINE_TEMPLATE QList<T> QMap<Key, T>::values() const
836{
837 QList<T> res;
838 const_iterator i = begin();
839 while (i != end()) {
840 res.append(i.value());
841 ++i;
842 }
843 return res;
844}
845
846template <class Key, class T>
847Q_OUTOFLINE_TEMPLATE QList<T> QMap<Key, T>::values(const Key &akey) const
848{
849 QList<T> res;
850 QMapData::Node *node = findNode(akey);
851 if (node != e) {
852 do {
853 res.append(concrete(node)->value);
854 node = node->forward[0];
855 } while (node != e && !qMapLessThanKey<Key>(akey, concrete(node)->key));
856 }
857 return res;
858}
859
860template <class Key, class T>
861Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator
862QMap<Key, T>::lowerBound(const Key &akey) const
863{
864 QMapData::Node *update[QMapData::LastLevel + 1];
865 mutableFindNode(update, akey);
866 return const_iterator(update[0]->forward[0]);
867}
868
869template <class Key, class T>
870Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::lowerBound(const Key &akey)
871{
872 detach();
873 return static_cast<QMapData::Node *>(const_cast<const QMap *>(this)->lowerBound(akey));
874}
875
876template <class Key, class T>
877Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator
878QMap<Key, T>::upperBound(const Key &akey) const
879{
880 QMapData::Node *update[QMapData::LastLevel + 1];
881 mutableFindNode(update, akey);
882 QMapData::Node *node = update[0]->forward[0];
883 while (node != e && !qMapLessThanKey<Key>(akey, concrete(node)->key))
884 node = node->forward[0];
885 return const_iterator(node);
886}
887
888template <class Key, class T>
889Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::upperBound(const Key &akey)
890{
891 detach();
892 return static_cast<QMapData::Node *>(const_cast<const QMap *>(this)->upperBound(akey));
893}
894
895template <class Key, class T>
896Q_OUTOFLINE_TEMPLATE bool QMap<Key, T>::operator==(const QMap<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 it1 = begin();
904 const_iterator it2 = other.begin();
905
906 while (it1 != end()) {
907 if (!(it1.value() == it2.value()) || qMapLessThanKey(it1.key(), it2.key()) || qMapLessThanKey(it2.key(), it1.key()))
908 return false;
909 ++it2;
910 ++it1;
911 }
912 return true;
913}
914
915#ifndef QT_NO_STL
916template <class Key, class T>
917Q_OUTOFLINE_TEMPLATE QMap<Key, T>::QMap(const std::map<Key, T> &other)
918{
919 d = QMapData::createData(alignment());
920 d->insertInOrder = true;
921 typename std::map<Key,T>::const_iterator it = other.end();
922 while (it != other.begin()) {
923 --it;
924 insert((*it).first, (*it).second);
925 }
926 d->insertInOrder = false;
927}
928
929template <class Key, class T>
930Q_OUTOFLINE_TEMPLATE std::map<Key, T> QMap<Key, T>::toStdMap() const
931{
932 std::map<Key, T> map;
933 const_iterator it = end();
934 while (it != begin()) {
935 --it;
936 map.insert(std::pair<Key, T>(it.key(), it.value()));
937 }
938 return map;
939}
940
941#endif // QT_NO_STL
942
943template <class Key, class T>
944class QMultiMap : public QMap<Key, T>
945{
946public:
947 QMultiMap() {}
948 QMultiMap(const QMap<Key, T> &other) : QMap<Key, T>(other) {}
949
950 inline typename QMap<Key, T>::iterator replace(const Key &key, const T &value)
951 { return QMap<Key, T>::insert(key, value); }
952 inline typename QMap<Key, T>::iterator insert(const Key &key, const T &value)
953 { return QMap<Key, T>::insertMulti(key, value); }
954
955 inline QMultiMap &operator+=(const QMultiMap &other)
956 { unite(other); return *this; }
957 inline QMultiMap operator+(const QMultiMap &other) const
958 { QMultiMap result = *this; result += other; return result; }
959
960#if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT)
961 // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class
962 using QMap<Key, T>::contains;
963 using QMap<Key, T>::remove;
964 using QMap<Key, T>::count;
965 using QMap<Key, T>::find;
966 using QMap<Key, T>::constFind;
967#else
968 inline bool contains(const Key &key) const
969 { return QMap<Key, T>::contains(key); }
970 inline int remove(const Key &key)
971 { return QMap<Key, T>::remove(key); }
972 inline int count(const Key &key) const
973 { return QMap<Key, T>::count(key); }
974 inline int count() const
975 { return QMap<Key, T>::count(); }
976 inline typename QMap<Key, T>::iterator find(const Key &key)
977 { return QMap<Key, T>::find(key); }
978 inline typename QMap<Key, T>::const_iterator find(const Key &key) const
979 { return QMap<Key, T>::find(key); }
980 inline typename QMap<Key, T>::const_iterator constFind(const Key &key) const
981 { return QMap<Key, T>::constFind(key); }
982#endif
983
984 bool contains(const Key &key, const T &value) const;
985
986 int remove(const Key &key, const T &value);
987
988 int count(const Key &key, const T &value) const;
989
990 typename QMap<Key, T>::iterator find(const Key &key, const T &value) {
991 typename QMap<Key, T>::iterator i(find(key));
992 typename QMap<Key, T>::iterator end(this->end());
993 while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
994 if (i.value() == value)
995 return i;
996 ++i;
997 }
998 return end;
999 }
1000 typename QMap<Key, T>::const_iterator find(const Key &key, const T &value) const {
1001 typename QMap<Key, T>::const_iterator i(constFind(key));
1002 typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd());
1003 while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
1004 if (i.value() == value)
1005 return i;
1006 ++i;
1007 }
1008 return end;
1009 }
1010 typename QMap<Key, T>::const_iterator constFind(const Key &key, const T &value) const
1011 { return find(key, value); }
1012private:
1013 T &operator[](const Key &key);
1014 const T operator[](const Key &key) const;
1015};
1016
1017template <class Key, class T>
1018Q_INLINE_TEMPLATE bool QMultiMap<Key, T>::contains(const Key &key, const T &value) const
1019{
1020 return constFind(key, value) != QMap<Key, T>::constEnd();
1021}
1022
1023template <class Key, class T>
1024Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value)
1025{
1026 int n = 0;
1027 typename QMap<Key, T>::iterator i(find(key));
1028 typename QMap<Key, T>::iterator end(QMap<Key, T>::end());
1029 while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
1030 if (i.value() == value) {
1031#if defined(Q_CC_RVCT)
1032 // RVCT has problems with scoping, apparently.
1033 i = QMap<Key, T>::erase(i);
1034#else
1035 i = erase(i);
1036#endif
1037 ++n;
1038 } else {
1039 ++i;
1040 }
1041 }
1042 return n;
1043}
1044
1045template <class Key, class T>
1046Q_INLINE_TEMPLATE int QMultiMap<Key, T>::count(const Key &key, const T &value) const
1047{
1048 int n = 0;
1049 typename QMap<Key, T>::const_iterator i(constFind(key));
1050 typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd());
1051 while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
1052 if (i.value() == value)
1053 ++n;
1054 ++i;
1055 }
1056 return n;
1057}
1058
1059Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
1060Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
1061
1062QT_END_NAMESPACE
1063
1064QT_END_HEADER
1065
1066#endif // QMAP_H
Note: See TracBrowser for help on using the repository browser.