Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qstringhash_p.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#ifndef QSTRINGHASH_P_H
6#define QSTRINGHASH_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qhashedstring_p.h>
20#include <private/qprimefornumbits_p.h>
21
22#include <QtCore/qbytearray.h>
23#include <QtCore/qstring.h>
24#include <QtCore/qtaggedpointer.h>
25
26QT_BEGIN_NAMESPACE
27
28static inline QString::DataPointer &mutableStringData(const QHashedString &key)
29{
30 return const_cast<QHashedString &>(key).data_ptr();
31}
32
33class QStringHashData;
35{
36public:
38 {
39 }
40
41 QStringHashNode(const QHashedString &key)
42 : length(int(key.size())), hash(key.hash()), symbolId(0)
44 , strData(mutableStringData(key).data())
45 {
46 Q_ASSERT(key.size() <= std::numeric_limits<int>::max());
47 if (arrayData)
48 arrayData->ref();
49 setQString(true);
50 }
51
52 QStringHashNode(const QHashedCStringRef &key)
53 : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
54 {
55 }
56
59 {
61 if (isQString()) {
62 strData = o.strData;
63 if (arrayData)
64 arrayData->ref();
65 } else {
66 ckey = o.ckey;
67 }
68 }
69
71 {
72 if (isQString() && arrayData && !arrayData->deref())
73 QTypedArrayData<char16_t>::deallocate(arrayData);
74 }
75
80
82
86
87 QTypedArrayData<char16_t> *arrayData = nullptr;
88 union {
89 const char *ckey = nullptr;
90 char16_t *strData;
91 };
92
93 inline QHashedString key() const
94 {
95 if (isQString()) {
96 if (arrayData)
97 arrayData->ref();
98 return QHashedString(QString(QStringPrivate(arrayData, strData, length)), hash);
99 }
100
101 return QHashedString(QString::fromLatin1(ckey, length), hash);
102 }
103
104 bool isQString() const { return next.tag() == NodeIsQString; }
105 void setQString(bool v) { if (v) next.setTag(NodeIsQString); else next.setTag(NodeIsCString); }
106
107 inline qsizetype size() const { return length; }
108 inline const char *cStrData() const { return ckey; }
109 inline const char16_t *utf16Data() const { return strData; }
110
111 inline bool equals(const QV4::Value &string) const {
112 QString s = string.toQStringNoThrow();
113 if (isQString()) {
114 return QStringView(utf16Data(), length) == s;
115 } else {
116 return QLatin1String(cStrData(), length) == s;
117 }
118 }
119
120 inline bool equals(const QV4::String *string) const {
121 if (length != string->d()->length() || hash != string->hashValue())
122 return false;
123 if (isQString()) {
124 return QStringView(utf16Data(), length) == string->toQString();
125 } else {
126 return QLatin1String(cStrData(), length) == string->toQString();
127 }
128 }
129
130 inline bool equals(const QHashedStringRef &string) const {
131 return length == string.length() &&
132 hash == string.hash() &&
133 (isQString()? string == QStringView {utf16Data(), length}:
134 QHashedString::compare(string.constData(), cStrData(), length));
135 }
136
137 inline bool equals(const QHashedCStringRef &string) const {
138 return length == string.length() &&
139 hash == string.hash() &&
140 (isQString()?QHashedString::compare((const QChar *)utf16Data(), string.constData(), length):
141 QHashedString::compare(string.constData(), cStrData(), length));
142 }
143};
144
146{
148public:
149 QStringHashData() = default;
150 ~QStringHashData() = default;
151
152 /*
153 A QHash has initially around pow(2, MinNumBits) buckets. For
154 example, if MinNumBits is 4, it has 17 buckets.
155 */
156 enum { MinNumBits = 4 };
157
158 QStringHashNode **buckets = nullptr; // life cycle managed by QStringHash
159 int numBuckets = 0;
160 int size = 0;
161 short numBits = 0;
162
163 template<typename StringHash>
165 IteratorData(QStringHashNode *n = nullptr, StringHash *p = nullptr) : n(n), p(p) {}
166
167 template<typename OtherData>
168 IteratorData(const OtherData &other) : n(other.n), p(other.p) {}
169
171 StringHash *p;
172 };
173
174 void rehashToBits(short bits)
175 {
176 numBits = qMax(short(MinNumBits), bits);
177
178 int nb = qPrimeForNumBits(numBits);
179 if (nb == numBuckets && buckets)
180 return;
181
182 QStringHashNode **newBuckets = new QStringHashNode *[nb];
183 ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
184
185 // Preserve the existing order within buckets so that items with the
186 // same key will retain the same find/findNext order
187 for (int i = 0; i < numBuckets; ++i) {
188 QStringHashNode *bucket = buckets[i];
189 if (bucket)
190 rehashNode(newBuckets, nb, bucket);
191 }
192
193 delete [] buckets;
194 buckets = newBuckets;
195 numBuckets = nb;
196 }
197
198 void rehashToSize(int size)
199 {
200 short bits = qMax(short(MinNumBits), numBits);
201 while (qPrimeForNumBits(bits) < size)
202 bits++;
203
204 if (bits > numBits)
205 rehashToBits(bits);
206 }
207
208 void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
209 {
210 QStringHashNode *next = node->next.data();
211 if (next)
212 rehashNode(newBuckets, nb, next);
213
214 int bucket = node->hash % nb;
215 node->next = newBuckets[bucket];
216 newBuckets[bucket] = node;
217 }
218};
219
220// For a supplied key type, in what form do we need to keep a hashed version?
221template<typename T>
222struct HashedForm {};
223
224template<> struct HashedForm<QString> { typedef QHashedString Type; };
225template<> struct HashedForm<QStringView> { typedef QHashedStringRef Type; };
226template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
227template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
228template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
229template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
230template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
231template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
232
234{
235public:
236 static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
237 static HashedForm<QStringView>::Type hashedString(QStringView s)
238 {
239 Q_ASSERT(s.size() <= std::numeric_limits<int>::max());
240 return QHashedStringRef(s.constData(), int(s.size()));
241 }
242 static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
243 static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
244 static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
245 static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
246
247 static HashedForm<QLatin1StringView>::Type hashedString(QLatin1StringView s)
248 {
249 Q_ASSERT(s.size() <= std::numeric_limits<int>::max());
250 return QHashedCStringRef(s.data(), int(s.size()));
251 }
252 static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
253
254 static const QString &toQString(const QString &s) { return s; }
255 static const QString &toQString(const QHashedString &s) { return s; }
256 static QString toQString(const QV4::String *s) { return s->toQString(); }
257 static QString toQString(const QHashedStringRef &s) { return s.toString(); }
258
259 static QString toQString(const QLatin1String &s) { return QString(s); }
260 static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
261
262 static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
263 static inline quint32 hashOf(QV4::String *s) { return s->hashValue(); }
264 static inline quint32 hashOf(const QV4::String *s) { return s->hashValue(); }
265
266 template<typename K>
267 static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
268};
269
270template<class T>
272{
273public:
275 typedef T mapped_type;
276
279
280 struct Node : public QStringHashNode {
281 Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
282 Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
283 Node(const Node &o) : QStringHashNode(o), value(o.value) {}
284 Node() {}
286 };
287 struct NewedNode : public Node {
288 NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
289 NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
290 NewedNode(const Node &o) : Node(o), nextNewed(nullptr) {}
292 };
294 {
295 ReservedNodePool() : nodes(nullptr) {}
296 ~ReservedNodePool() { delete [] nodes; }
297 int count = 0;
298 int used = 0;
300 };
301
305
306 template<typename K>
307 inline Node *findNode(const K &) const;
308
309 inline Node *createNode(const Node &o);
310
311 template<typename K>
312 inline Node *createNode(const K &, const T &);
313
315
316 inline void initializeNode(Node *, const QHashedString &key);
317 inline void initializeNode(Node *, const QHashedCStringRef &key);
318
319 template<typename K>
320 inline Node *takeNode(const K &key, const T &value);
321
322 inline Node *takeNode(const Node &o);
323
324 inline void copy(const QStringHash<T> &);
325
326 void copyNode(const QStringHashNode *otherNode);
327
328 template<typename StringHash, typename Data>
329 static inline Data iterateFirst(StringHash *self);
330
331 template<typename Data>
332 static inline Data iterateNext(const Data &);
333
334public:
335 inline QStringHash();
336 inline QStringHash(const QStringHash &);
337 inline ~QStringHash();
338
340
341 void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
342
343 inline bool isEmpty() const;
344 inline void clear();
345 inline int count() const;
346
347 inline int numBuckets() const;
348
349 template<typename Data, typename Value>
350 class Iterator {
351 public:
352 inline Iterator() = default;
353 inline Iterator(const Data &d) : d(d) {}
354
355 inline Iterator &operator++()
356 {
357 d = QStringHash<T>::iterateNext(d);
358 return *this;
359 }
360
361 inline bool operator==(const Iterator &o) const { return d.n == o.d.n; }
362 inline bool operator!=(const Iterator &o) const { return d.n != o.d.n; }
363
364 template<typename K>
365 inline bool equals(const K &key) const { return d.n->equals(key); }
366
367 inline QHashedString key() const { return static_cast<Node *>(d.n)->key(); }
368 inline Value &value() const { return static_cast<Node *>(d.n)->value; }
369 inline Value &operator*() const { return static_cast<Node *>(d.n)->value; }
370
371 Node *node() const { return static_cast<Node *>(d.n); }
372 private:
373 Data d;
374 };
375
378
379 template<typename K>
380 inline void insert(const K &, const T &);
381 inline void insert(const MutableIterator &);
382 inline void insert(const ConstIterator &);
383
384 template<typename K>
385 inline T *value(const K &) const;
386 inline T *value(const QV4::String *string) const;
387 inline T *value(const MutableIterator &) const;
388 inline T *value(const ConstIterator &) const;
389
390 template<typename K>
391 inline bool contains(const K &) const;
392
393 template<typename K>
394 inline T &operator[](const K &);
395
397 inline ConstIterator begin() const;
398 inline ConstIterator constBegin() const { return begin(); }
399
401 inline ConstIterator end() const;
402 inline ConstIterator constEnd() const { return end(); }
403
404 template<typename K>
405 inline MutableIterator find(const K &);
406
407 template<typename K>
408 inline ConstIterator find(const K &) const;
409
410 inline void reserve(int);
411};
412
413template<class T>
415: newedNodes(nullptr), nodePool(nullptr)
416{
417}
418
419template<class T>
421: newedNodes(nullptr), nodePool(nullptr)
422{
423 data.numBits = other.data.numBits;
424 data.size = other.data.size;
426 copy(other);
427}
428
429template<class T>
431{
432 if (&other == this)
433 return *this;
434
435 clear();
436
437 data.numBits = other.data.numBits;
438 data.size = other.data.size;
440 copy(other);
441
442 return *this;
443}
444
445template<class T>
446void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
447{
448 clear();
449 data.numBits = other.data.numBits;
450 reserve(other.count() + additionalReserve);
451 copy(other);
452}
453
454template<class T>
456{
457 clear();
458}
459
460template<class T>
462{
463 // Delete the individually allocated nodes
465 while (n) {
466 NewedNode *c = n;
467 n = c->nextNewed;
468 delete c;
469 }
470 // Delete the pool allocated nodes
471 if (nodePool) delete nodePool;
472 delete [] data.buckets;
473
474 data.buckets = nullptr;
475 data.numBuckets = 0;
476 data.numBits = 0;
477 data.size = 0;
478
479 newedNodes = nullptr;
480 nodePool = nullptr;
481}
482
483template<class T>
484bool QStringHash<T>::isEmpty() const
485{
486 return data.size== 0;
487}
488
489template<class T>
490int QStringHash<T>::count() const
491{
492 return data.size;
493}
494
495template<class T>
496int QStringHash<T>::numBuckets() const
497{
498 return data.numBuckets;
499}
500
501template<class T>
502void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
503{
504 node->length = key.size();
505 node->hash = key.hash();
506 node->arrayData = mutableStringData(key).d_ptr();
507 node->strData = mutableStringData(key).data();
508 if (node->arrayData)
509 node->arrayData->ref();
510 node->setQString(true);
511}
512
513template<class T>
514void QStringHash<T>::initializeNode(Node *node, const QHashedCStringRef &key)
515{
516 node->length = key.length();
517 node->hash = key.hash();
518 node->ckey = key.constData();
519}
520
521template<class T>
522template<class K>
523typename QStringHash<T>::Node *QStringHash<T>::takeNode(const K &key, const T &value)
524{
525 if (nodePool && nodePool->used != nodePool->count) {
526 Node *rv = nodePool->nodes + nodePool->used++;
527 initializeNode(rv, hashedString(key));
528 rv->value = value;
529 return rv;
530 } else {
531 NewedNode *rv = new NewedNode(hashedString(key), value);
532 rv->nextNewed = newedNodes;
533 newedNodes = rv;
534 return rv;
535 }
536}
537
538template<class T>
539typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
540{
541 if (nodePool && nodePool->used != nodePool->count) {
542 Node *rv = nodePool->nodes + nodePool->used++;
543 rv->length = o.length;
544 rv->hash = o.hash;
545 rv->arrayData = o.arrayData;
546 if (o.isQString()) {
547 rv->strData = o.strData;
548 rv->setQString(true);
549 if (rv->arrayData)
550 rv->arrayData->ref();
551 } else {
552 rv->ckey = o.ckey;
553 }
554 rv->symbolId = o.symbolId;
555 rv->value = o.value;
556 return rv;
557 } else {
558 NewedNode *rv = new NewedNode(o);
559 rv->nextNewed = newedNodes;
560 newedNodes = rv;
561 return rv;
562 }
563}
564
565template<class T>
566void QStringHash<T>::copyNode(const QStringHashNode *otherNode)
567{
568 // Copy the predecessor before the successor
569 QStringHashNode *next = otherNode->next.data();
570 if (next)
571 copyNode(next);
572
573 Node *mynode = takeNode(*(const Node *)otherNode);
574 int bucket = mynode->hash % data.numBuckets;
575 mynode->next = data.buckets[bucket];
576 data.buckets[bucket] = mynode;
577}
578
579template<class T>
580void QStringHash<T>::copy(const QStringHash<T> &other)
581{
582 Q_ASSERT(data.size == 0);
583
584 data.size = other.data.size;
585
586 // Ensure buckets array is created
587 data.rehashToBits(data.numBits);
588
589 // Preserve the existing order within buckets
590 for (int i = 0; i < other.data.numBuckets; ++i) {
591 QStringHashNode *bucket = other.data.buckets[i];
592 if (bucket)
593 copyNode(bucket);
594 }
595}
596
597template<class T>
598template<typename Data>
599Data QStringHash<T>::iterateNext(const Data &d)
600{
601 auto *This = d.p;
602 Node *node = (Node *)d.n;
603
604 if (This->nodePool && node >= This->nodePool->nodes &&
605 node < (This->nodePool->nodes + This->nodePool->used)) {
606 node--;
607 if (node < This->nodePool->nodes)
608 node = nullptr;
609 } else {
610 NewedNode *nn = (NewedNode *)node;
611 node = nn->nextNewed;
612
613 if (node == nullptr && This->nodePool && This->nodePool->used)
614 node = This->nodePool->nodes + This->nodePool->used - 1;
615 }
616
617 Data rv;
618 rv.n = node;
619 rv.p = d.p;
620 return rv;
621}
622
623template<class T>
624template<typename StringHash, typename Data>
625Data QStringHash<T>::iterateFirst(StringHash *self)
626{
627 typename StringHash::Node *n = nullptr;
628 if (self->newedNodes)
629 n = self->newedNodes;
630 else if (self->nodePool && self->nodePool->used)
631 n = self->nodePool->nodes + self->nodePool->used - 1;
632
633 Data rv;
634 rv.n = n;
635 rv.p = self;
636 return rv;
637}
638
639template<class T>
640typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
641{
642 Node *n = takeNode(o);
643 return insertNode(n, n->hash);
644}
645
646template<class T>
647template<class K>
648typename QStringHash<T>::Node *QStringHash<T>::createNode(const K &key, const T &value)
649{
650 Node *n = takeNode(key, value);
651 return insertNode(n, hashOf(key));
652}
653
654template<class T>
655typename QStringHash<T>::Node *QStringHash<T>::insertNode(Node *n, quint32 hash)
656{
657 if (data.size >= data.numBuckets)
658 data.rehashToBits(data.numBits + 1);
659
660 int bucket = hash % data.numBuckets;
661 n->next = data.buckets[bucket];
662 data.buckets[bucket] = n;
663
664 data.size++;
665
666 return n;
667}
668
669template<class T>
670template<class K>
671void QStringHash<T>::insert(const K &key, const T &value)
672{
673 Node *n = findNode(key);
674 if (n)
675 n->value = value;
676 else
677 createNode(key, value);
678}
679
680template<class T>
681void QStringHash<T>::insert(const MutableIterator &iter)
682{
683 insert(iter.key(), iter.value());
684}
685
686template<class T>
687void QStringHash<T>::insert(const ConstIterator &iter)
688{
689 insert(iter.key(), iter.value());
690}
691
692template<class T>
693template<class K>
694typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
695{
696 QStringHashNode *node = data.numBuckets?data.buckets[hashOf(key) % data.numBuckets]:nullptr;
697
698 typename HashedForm<K>::Type hashedKey(hashedString(key));
699 while (node && !node->equals(hashedKey))
700 node = node->next.data();
701
702 return (Node *)node;
703}
704
705template<class T>
706template<class K>
707T *QStringHash<T>::value(const K &key) const
708{
709 Node *n = findNode(key);
710 return n?&n->value:nullptr;
711}
712
713template<typename T>
714T *QStringHash<T>::value(const MutableIterator &iter) const
715{
716 return value(iter.node()->key());
717}
718
719template<class T>
720T *QStringHash<T>::value(const ConstIterator &iter) const
721{
722 return value(iter.node()->key());
723}
724
725template<class T>
726T *QStringHash<T>::value(const QV4::String *string) const
727{
728 Node *n = findNode(string);
729 return n?&n->value:nullptr;
730}
731
732template<class T>
733template<class K>
734bool QStringHash<T>::contains(const K &key) const
735{
736 return nullptr != value(key);
737}
738
739template<class T>
740template<class K>
741T &QStringHash<T>::operator[](const K &key)
742{
743 Node *n = findNode(key);
744 if (n) return n->value;
745 else return createNode(key, T())->value;
746}
747
748template<class T>
749void QStringHash<T>::reserve(int n)
750{
751 if (nodePool || 0 == n)
752 return;
753
755 nodePool->count = n;
756 nodePool->used = 0;
757 nodePool->nodes = new Node[n];
758
759 data.rehashToSize(n);
760}
761
762template<class T>
764{
765 return MutableIterator(iterateFirst<QStringHash<T>, MutableIteratorData>(this));
766}
767
768template<class T>
770{
771 return ConstIterator(iterateFirst<const QStringHash<T>, ConstIteratorData>(this));
772}
773
774template<class T>
776{
777 return MutableIterator();
778}
779
780template<class T>
781typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
782{
783 return ConstIterator();
784}
785
786template<class T>
787template<class K>
788typename QStringHash<T>::MutableIterator QStringHash<T>::find(const K &key)
789{
790 Node *n = findNode(key);
791 return n ? MutableIterator(MutableIteratorData(n, this)) : MutableIterator();
792}
793
794template<class T>
795template<class K>
796typename QStringHash<T>::ConstIterator QStringHash<T>::find(const K &key) const
797{
798 Node *n = findNode(key);
799 return n ? ConstIterator(ConstIteratorData(n, this)) : ConstIterator();
800}
801
802QT_END_NAMESPACE
803
804#endif // QSTRINGHASH_P_H
static const QString & toQString(const QString &s)
static HashedForm< constQV4::String * >::Type hashedString(const QV4::String *s)
static quint32 hashOf(const K &key)
static HashedForm< QV4::String * >::Type hashedString(QV4::String *s)
static QString toQString(const QV4::String *s)
static quint32 hashOf(const QHashedStringRef &s)
static HashedForm< QStringView >::Type hashedString(QStringView s)
static quint32 hashOf(const QV4::String *s)
static quint32 hashOf(QV4::String *s)
static HashedForm< QString >::Type hashedString(const QString &s)
void rehashToBits(short bits)
QStringHashNode ** buckets
void rehashToSize(int size)
~QStringHashData()=default
void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
qsizetype size() const
QStringHashNode(const QHashedString &key)
void setQString(bool v)
const char16_t * utf16Data() const
char16_t * strData
QHashedString key() const
const char * cStrData() const
bool equals(const QV4::String *string) const
const char * ckey
QTypedArrayData< char16_t > * arrayData
bool equals(const QV4::Value &string) const
QTaggedPointer< QStringHashNode, Tag > next
QStringHashNode(const QStringHashNode &o)
bool isQString() const
Iterator(const Data &d)
Value & value() const
bool equals(const K &key) const
bool operator!=(const Iterator &o) const
bool operator==(const Iterator &o) const
Value & operator*() const
QHashedString key() const
Node * takeNode(const K &key, const T &value)
void copyAndReserve(const QStringHash< T > &other, int additionalReserve)
void initializeNode(Node *, const QHashedString &key)
void copyNode(const QStringHashNode *otherNode)
QStringHashData::IteratorData< const QStringHash< T > > ConstIteratorData
bool contains(const K &) const
ConstIterator end() const
Iterator< MutableIteratorData, T > MutableIterator
MutableIterator find(const K &)
ReservedNodePool * nodePool
Node * findNode(const K &) const
ConstIterator begin() const
QHashedString key_type
static Data iterateFirst(StringHash *self)
T * value(const QV4::String *string) const
MutableIterator begin()
QStringHash & operator=(const QStringHash< T > &)
ConstIterator constEnd() const
void copy(const QStringHash< T > &)
Node * insertNode(Node *, quint32)
ConstIterator constBegin() const
T & operator[](const K &)
void insert(const MutableIterator &)
void insert(const K &, const T &)
T * value(const ConstIterator &) const
Iterator< ConstIteratorData, const T > ConstIterator
T * value(const K &) const
NewedNode * newedNodes
ConstIterator find(const K &) const
void insert(const ConstIterator &)
QStringHashData data
void reserve(int)
QStringHashData::IteratorData< QStringHash< T > > MutableIteratorData
Node * createNode(const Node &o)
static Data iterateNext(const Data &)
T * value(const MutableIterator &) const
Node * createNode(const K &, const T &)
int numBuckets() const
Node * takeNode(const Node &o)
QStringHash(const QStringHash &)
int count() const
MutableIterator end()
bool isEmpty() const
IteratorData(const OtherData &other)
IteratorData(QStringHashNode *n=nullptr, StringHash *p=nullptr)
NewedNode(const QHashedString &key, const T &value)
NewedNode(const Node &o)
Node(const Node &o)
Node(const QHashedString &key, const T &value)