qhash.h
上传用户:detong
上传日期:2022-06-22
资源大小:20675k
文件大小:29k
源码类别:

系统编程

开发平台:

Unix_Linux

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